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