Sorry - wrong testcase. The attached is the proper one.
Am Donnerstag, den 14.04.2016, 13:55 +0200 schrieb Markus Doppelbauer:
> Hello,
> 
> It seems that there is an other issue (is neither works with 0.9.48):
> a) The connection creates a "callback" response
> b) The connection is suspended after every byte - then resumed (by a
> thread)
> c) The daemon get stalled after 33 requests
> 
> I have attached a small testcase.
> 
> Commandline:
> g++ -o testmhd test.cpp -I/tmp/libmicrohttpd/src/include/ 
> -L/tmp/libmicrohttpd/src/microhttpd/.libs/ -lmicrohttpd -pthread
> LD_LIBRARY_PATH=/tmp/libmicrohttpd/src/microhttpd/.libs/ ./testmhd
> while [ 1 == 1 ]; do wget --server-response -q -O - 127.0.0.1:8080;
> echo; done
> 
> Thanks a lot!
> Markus
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <microhttpd.h>

static int request_counter = 0;

static void* resume_connection( void *arg )
{
    struct MHD_Connection *connection = (struct MHD_Connection *)arg;
    MHD_resume_connection( connection );
    return NULL;
}
static void suspend_connection( struct MHD_Connection *connection )
{
    MHD_suspend_connection( connection );

    // wait to resume
    pthread_t thread_id;
    pthread_attr_t thread_attr;
    pthread_attr_init( &thread_attr );
    pthread_create( &thread_id, &thread_attr, resume_connection, connection );
}

struct ContentReaderUserdata
{
    int bytes_written;
    struct MHD_Connection *connection;
};
static ssize_t http_ContentReaderCallback( void *cls, uint64_t pos, char *buf, size_t max )
{
    struct ContentReaderUserdata *userdata = (struct ContentReaderUserdata*)cls;
    if( userdata->bytes_written >= 1024 )
    {
        fprintf( stderr, "finish: %d\n", request_counter );
        return MHD_CONTENT_READER_END_OF_STREAM;
    }
    userdata->bytes_written += 1;

    // write a byte
    const char alphabet[] = "\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    buf[0] = alphabet[ userdata->bytes_written % (sizeof(alphabet) - 1) ];

    // Suspend connection
    suspend_connection( userdata->connection );

    return 1;
}

static int http_AccessHandlerCallback( void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls )
{
    // Never respond on first call
    if( *con_cls == NULL )
    {
        fprintf( stderr, "start: %d\n", ++request_counter );

        struct ContentReaderUserdata *userdata = (struct ContentReaderUserdata*) malloc( sizeof(ContentReaderUserdata) );
        userdata->bytes_written = 0;
        userdata->connection = connection;
        *con_cls = userdata;
        return MHD_YES;
    }

    // Second call: create response
    struct MHD_Response *response = MHD_create_response_from_callback( -1, 32*1024, http_ContentReaderCallback, *con_cls, NULL );
    MHD_queue_response( connection, MHD_HTTP_OK, response );
    MHD_destroy_response( response );

    suspend_connection( connection );
    return MHD_YES;
}

int main()
{
    // create a socket on port 8080
    int ai_family = AF_INET;
    struct sockaddr addr_socket;
    struct sockaddr_in *in_addr = (struct sockaddr_in *) &addr_socket;
    memset( in_addr, 0, sizeof(*in_addr) );
    in_addr->sin_family = AF_INET;
    in_addr->sin_port = htons( 8080 );
    in_addr->sin_addr.s_addr = htonl( INADDR_ANY );
    socklen_t addr_len = sizeof(*in_addr);

    // Create socket
    int listening_socket = socket( ai_family, SOCK_STREAM, IPPROTO_TCP );
    if( listening_socket == -1 )
    {
        fprintf( stderr, "Could not create socket: %s.\n", strerror(errno) );
        return EXIT_FAILURE;
    }

    // Non blocking socket
    int file_descriptor_flag = fcntl( listening_socket, F_GETFL );
    fcntl( listening_socket, F_SETFL, file_descriptor_flag | O_NONBLOCK );

    // Socket options
    int optval = 1;
    setsockopt( listening_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval) );

    // Bind socket
    int bound = bind( listening_socket, &addr_socket, addr_len );
    if( bound == -1 )
    {
        close( listening_socket );
        fprintf( stderr, "Bind failed: %s\n", strerror(errno) );
        return EXIT_FAILURE;
    }

    // Start listening
    int listening = listen( listening_socket, 31 );
    if( listening == -1 )
    {
        close( listening_socket );
        fprintf( stderr, "Listen failed: %s\n", strerror(errno) );
        return EXIT_FAILURE;
    }

    // Create daemon
    unsigned int daemon_flags = MHD_USE_SELECT_INTERNALLY | MHD_USE_SUSPEND_RESUME | MHD_USE_PIPE_FOR_SHUTDOWN | MHD_USE_DEBUG;
    struct MHD_OptionItem options[] =
    {
        { MHD_OPTION_LISTEN_SOCKET, listening_socket, NULL },
        { MHD_OPTION_THREAD_POOL_SIZE, 1, NULL },
        { MHD_OPTION_END, 0, NULL }
    };
    struct MHD_Daemon *daemon = MHD_start_daemon( daemon_flags, 0,
                                                  NULL, NULL,
                                                  http_AccessHandlerCallback, NULL,
                                                  MHD_OPTION_ARRAY, options,
                                                  MHD_OPTION_END );
    if( daemon == NULL )
        return EXIT_FAILURE;

    // forever
    sleep( 999999999 );

    // Stop daemon
    MHD_stop_daemon( daemon );

    return EXIT_SUCCESS;
}

Reply via email to