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;
}