aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorng0 <ng0@n0.is>2019-08-01 14:28:34 +0000
committerng0 <ng0@n0.is>2019-08-01 14:28:34 +0000
commit8ad5fab2e8173476b78c3fda9a416540b925cd0f (patch)
tree511af471e5c12c749792228281fcecb9e510e78f /src
parent9edfc8f8f7a548e0dad8f3d18f671b822601a384 (diff)
parent91826f50011e76014dc307e370e6b1f45b2df151 (diff)
downloadlibmicrohttpd-8ad5fab2e8173476b78c3fda9a416540b925cd0f.tar.gz
libmicrohttpd-8ad5fab2e8173476b78c3fda9a416540b925cd0f.zip
Merge remote-tracking branch 'origin/master' into dev/ng0/gsoc2019
Diffstat (limited to 'src')
-rw-r--r--src/include/microhttpd.h2
-rw-r--r--src/microhttpd/.gitignore2
-rw-r--r--src/microhttpd/Makefile.am34
-rw-r--r--src/microhttpd/connection.c30
-rw-r--r--src/microhttpd/daemon.c310
-rw-r--r--src/microhttpd/response.c80
-rw-r--r--src/microhttpd/test_upgrade_large.c1386
7 files changed, 1636 insertions, 208 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 9d28cdb1..c2fc90a4 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -132,7 +132,7 @@ typedef intptr_t ssize_t;
132 * Current version of the library. 132 * Current version of the library.
133 * 0x01093001 = 1.9.30-1. 133 * 0x01093001 = 1.9.30-1.
134 */ 134 */
135#define MHD_VERSION 0x00096502 135#define MHD_VERSION 0x00096600
136 136
137/** 137/**
138 * MHD-internal return code for "YES". 138 * MHD-internal return code for "YES".
diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore
index ec2e027d..611f88ec 100644
--- a/src/microhttpd/.gitignore
+++ b/src/microhttpd/.gitignore
@@ -57,3 +57,5 @@ test_shutdown_poll
57test_shutdown_select 57test_shutdown_select
58test_md5 58test_md5
59test_sha256 59test_sha256
60test_upgrade_large
61test_upgrade_large_tls
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 7a484371..597a2d56 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -166,17 +166,17 @@ check_PROGRAMS = \
166if HAVE_POSIX_THREADS 166if HAVE_POSIX_THREADS
167if ENABLE_UPGRADE 167if ENABLE_UPGRADE
168if USE_POSIX_THREADS 168if USE_POSIX_THREADS
169 check_PROGRAMS += test_upgrade 169 check_PROGRAMS += test_upgrade test_upgrade_large
170endif 170endif
171if USE_W32_THREADS 171if USE_W32_THREADS
172 check_PROGRAMS += test_upgrade 172 check_PROGRAMS += test_upgrade test_upgrade_large
173endif 173endif
174if ENABLE_HTTPS 174if ENABLE_HTTPS
175if USE_POSIX_THREADS 175if USE_POSIX_THREADS
176check_PROGRAMS += test_upgrade_tls 176check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls
177endif 177endif
178if USE_W32_THREADS 178if USE_W32_THREADS
179check_PROGRAMS += test_upgrade_tls 179check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls
180endif 180endif
181endif 181endif
182endif 182endif
@@ -231,6 +231,19 @@ test_upgrade_LDADD = \
231 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ 231 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
232 $(PTHREAD_LIBS) 232 $(PTHREAD_LIBS)
233 233
234test_upgrade_large_SOURCES = \
235 test_upgrade_large.c test_helpers.h mhd_sockets.h
236test_upgrade_large_CPPFLAGS = \
237 $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
238test_upgrade_large_CFLAGS = \
239 $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
240test_upgrade_large_LDFLAGS = \
241 $(MHD_TLS_LIB_LDFLAGS)
242test_upgrade_large_LDADD = \
243 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
244 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
245 $(PTHREAD_LIBS)
246
234test_upgrade_tls_SOURCES = \ 247test_upgrade_tls_SOURCES = \
235 test_upgrade.c test_helpers.h mhd_sockets.h 248 test_upgrade.c test_helpers.h mhd_sockets.h
236test_upgrade_tls_CPPFLAGS = \ 249test_upgrade_tls_CPPFLAGS = \
@@ -244,6 +257,19 @@ test_upgrade_tls_LDADD = \
244 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ 257 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
245 $(PTHREAD_LIBS) 258 $(PTHREAD_LIBS)
246 259
260test_upgrade_large_tls_SOURCES = \
261 test_upgrade_large.c test_helpers.h mhd_sockets.h
262test_upgrade_large_tls_CPPFLAGS = \
263 $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
264test_upgrade_large_tls_CFLAGS = \
265 $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
266test_upgrade_large_tls_LDFLAGS = \
267 $(MHD_TLS_LIB_LDFLAGS)
268test_upgrade_large_tls_LDADD = \
269 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
270 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \
271 $(PTHREAD_LIBS)
272
247test_postprocessor_SOURCES = \ 273test_postprocessor_SOURCES = \
248 test_postprocessor.c 274 test_postprocessor.c
249test_postprocessor_CPPFLAGS = \ 275test_postprocessor_CPPFLAGS = \
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 643ef52a..dab28878 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -800,7 +800,7 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection,
800 { 800 {
801 for (pos = connection->headers_received; NULL != pos; pos = pos->next) 801 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
802 { 802 {
803 if ( (kind == pos->kind) && 803 if ( (0 != (kind & pos->kind)) &&
804 (NULL == pos->header) ) 804 (NULL == pos->header) )
805 break; 805 break;
806 } 806 }
@@ -809,7 +809,7 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection,
809 { 809 {
810 for (pos = connection->headers_received; NULL != pos; pos = pos->next) 810 for (pos = connection->headers_received; NULL != pos; pos = pos->next)
811 { 811 {
812 if ( (kind == pos->kind) && 812 if ( (0 != (kind & pos->kind)) &&
813 (key_size == pos->header_size) && 813 (key_size == pos->header_size) &&
814 ( (key == pos->header) || 814 ( (key == pos->header) ||
815 (MHD_str_equal_caseless_bin_n_ (key, 815 (MHD_str_equal_caseless_bin_n_ (key,
@@ -2454,7 +2454,19 @@ process_request_body (struct MHD_Connection *connection)
2454 char *buffer_head; 2454 char *buffer_head;
2455 2455
2456 if (NULL != connection->response) 2456 if (NULL != connection->response)
2457 return; /* already queued a response */ 2457 {
2458 /* already queued a response, discard remaining upload
2459 (but not more, there might be another request after it) */
2460 uint64_t purge = MHD_MIN (connection->remaining_upload_size,
2461 connection->read_buffer_offset);
2462 connection->remaining_upload_size -= purge;
2463 if (connection->read_buffer_offset > purge)
2464 memmove (connection->read_buffer,
2465 &connection->read_buffer[purge],
2466 connection->read_buffer_offset - purge);
2467 connection->read_buffer_offset -= purge;
2468 return;
2469 }
2458 2470
2459 buffer_head = connection->read_buffer; 2471 buffer_head = connection->read_buffer;
2460 available = connection->read_buffer_offset; 2472 available = connection->read_buffer_offset;
@@ -2589,19 +2601,19 @@ process_request_body (struct MHD_Connection *connection)
2589 { 2601 {
2590 /* no chunked encoding, give all to the client */ 2602 /* no chunked encoding, give all to the client */
2591 if ( (0 != connection->remaining_upload_size) && 2603 if ( (0 != connection->remaining_upload_size) &&
2592 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && 2604 (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
2593 (connection->remaining_upload_size < available) ) 2605 (connection->remaining_upload_size < available) )
2594 { 2606 {
2595 to_be_processed = (size_t)connection->remaining_upload_size; 2607 to_be_processed = (size_t)connection->remaining_upload_size;
2596 } 2608 }
2597 else 2609 else
2598 { 2610 {
2599 /** 2611 /**
2600 * 1. no chunked encoding, give all to the client 2612 * 1. no chunked encoding, give all to the client
2601 * 2. client may send large chunked data, but only a smaller part is available at one time. 2613 * 2. client may send large chunked data, but only a smaller part is available at one time.
2602 */ 2614 */
2603 to_be_processed = available; 2615 to_be_processed = available;
2604 } 2616 }
2605 } 2617 }
2606 left_unprocessed = to_be_processed; 2618 left_unprocessed = to_be_processed;
2607 connection->client_aware = true; 2619 connection->client_aware = true;
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index d3595fe0..bf01ba9b 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -721,8 +721,8 @@ int
721MHD_get_fdset (struct MHD_Daemon *daemon, 721MHD_get_fdset (struct MHD_Daemon *daemon,
722 fd_set *read_fd_set, 722 fd_set *read_fd_set,
723 fd_set *write_fd_set, 723 fd_set *write_fd_set,
724 fd_set *except_fd_set, 724 fd_set *except_fd_set,
725 MHD_socket *max_fd) 725 MHD_socket *max_fd)
726{ 726{
727 return MHD_get_fdset2 (daemon, 727 return MHD_get_fdset2 (daemon,
728 read_fd_set, 728 read_fd_set,
@@ -2344,11 +2344,11 @@ psk_gnutls_adapter (gnutls_session_t session,
2344 */ 2344 */
2345static int 2345static int
2346internal_add_connection (struct MHD_Daemon *daemon, 2346internal_add_connection (struct MHD_Daemon *daemon,
2347 MHD_socket client_socket, 2347 MHD_socket client_socket,
2348 const struct sockaddr *addr, 2348 const struct sockaddr *addr,
2349 socklen_t addrlen, 2349 socklen_t addrlen,
2350 bool external_add, 2350 bool external_add,
2351 bool non_blck) 2351 bool non_blck)
2352{ 2352{
2353 struct MHD_Connection *connection; 2353 struct MHD_Connection *connection;
2354#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) 2354#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
@@ -2362,8 +2362,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2362 if ((external_add) && (NULL != daemon->worker_pool)) 2362 if ((external_add) && (NULL != daemon->worker_pool))
2363 { 2363 {
2364 /* have a pool, try to find a pool with capacity; we use the 2364 /* have a pool, try to find a pool with capacity; we use the
2365 socket as the initial offset into the pool for load 2365 socket as the initial offset into the pool for load
2366 balancing */ 2366 balancing */
2367 for (i = 0; i < daemon->worker_pool_size; ++i) 2367 for (i = 0; i < daemon->worker_pool_size; ++i)
2368 { 2368 {
2369 struct MHD_Daemon * const worker = 2369 struct MHD_Daemon * const worker =
@@ -2448,7 +2448,7 @@ internal_add_connection (struct MHD_Daemon *daemon,
2448 /* apply connection acceptance policy if present */ 2448 /* apply connection acceptance policy if present */
2449 if ( (NULL != daemon->apc) && 2449 if ( (NULL != daemon->apc) &&
2450 (MHD_NO == daemon->apc (daemon->apc_cls, 2450 (MHD_NO == daemon->apc (daemon->apc_cls,
2451 addr, 2451 addr,
2452 addrlen)) ) 2452 addrlen)) )
2453 { 2453 {
2454#if DEBUG_CLOSE 2454#if DEBUG_CLOSE
@@ -2472,8 +2472,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2472 eno = errno; 2472 eno = errno;
2473#ifdef HAVE_MESSAGES 2473#ifdef HAVE_MESSAGES
2474 MHD_DLOG (daemon, 2474 MHD_DLOG (daemon,
2475 "Error allocating memory: %s\n", 2475 "Error allocating memory: %s\n",
2476 MHD_strerror_ (errno)); 2476 MHD_strerror_ (errno));
2477#endif 2477#endif
2478 MHD_socket_close_chk_ (client_socket); 2478 MHD_socket_close_chk_ (client_socket);
2479 MHD_ip_limit_del (daemon, 2479 MHD_ip_limit_del (daemon,
@@ -2487,8 +2487,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2487 { 2487 {
2488#ifdef HAVE_MESSAGES 2488#ifdef HAVE_MESSAGES
2489 MHD_DLOG (daemon, 2489 MHD_DLOG (daemon,
2490 _("Error allocating memory: %s\n"), 2490 _("Error allocating memory: %s\n"),
2491 MHD_strerror_ (errno)); 2491 MHD_strerror_ (errno));
2492#endif 2492#endif
2493 MHD_socket_close_chk_ (client_socket); 2493 MHD_socket_close_chk_ (client_socket);
2494 MHD_ip_limit_del (daemon, 2494 MHD_ip_limit_del (daemon,
@@ -2507,8 +2507,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2507 eno = errno; 2507 eno = errno;
2508#ifdef HAVE_MESSAGES 2508#ifdef HAVE_MESSAGES
2509 MHD_DLOG (daemon, 2509 MHD_DLOG (daemon,
2510 _("Error allocating memory: %s\n"), 2510 _("Error allocating memory: %s\n"),
2511 MHD_strerror_ (errno)); 2511 MHD_strerror_ (errno));
2512#endif 2512#endif
2513 MHD_socket_close_chk_ (client_socket); 2513 MHD_socket_close_chk_ (client_socket);
2514 MHD_ip_limit_del (daemon, 2514 MHD_ip_limit_del (daemon,
@@ -2566,8 +2566,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2566 /* set needed credentials for certificate authentication. */ 2566 /* set needed credentials for certificate authentication. */
2567 case GNUTLS_CRD_CERTIFICATE: 2567 case GNUTLS_CRD_CERTIFICATE:
2568 gnutls_credentials_set (connection->tls_session, 2568 gnutls_credentials_set (connection->tls_session,
2569 GNUTLS_CRD_CERTIFICATE, 2569 GNUTLS_CRD_CERTIFICATE,
2570 daemon->x509_cred); 2570 daemon->x509_cred);
2571 break; 2571 break;
2572 case GNUTLS_CRD_PSK: 2572 case GNUTLS_CRD_PSK:
2573 gnutls_credentials_set (connection->tls_session, 2573 gnutls_credentials_set (connection->tls_session,
@@ -2596,18 +2596,18 @@ internal_add_connection (struct MHD_Daemon *daemon,
2596 } 2596 }
2597#if (GNUTLS_VERSION_NUMBER+0 >= 0x030109) && !defined(_WIN64) 2597#if (GNUTLS_VERSION_NUMBER+0 >= 0x030109) && !defined(_WIN64)
2598 gnutls_transport_set_int (connection->tls_session, 2598 gnutls_transport_set_int (connection->tls_session,
2599 (int)(client_socket)); 2599 (int)(client_socket));
2600#else /* GnuTLS before 3.1.9 or Win x64 */ 2600#else /* GnuTLS before 3.1.9 or Win x64 */
2601 gnutls_transport_set_ptr (connection->tls_session, 2601 gnutls_transport_set_ptr (connection->tls_session,
2602 (gnutls_transport_ptr_t)(intptr_t)(client_socket)); 2602 (gnutls_transport_ptr_t)(intptr_t)(client_socket));
2603#endif /* GnuTLS before 3.1.9 */ 2603#endif /* GnuTLS before 3.1.9 */
2604#ifdef MHD_TLSLIB_NEED_PUSH_FUNC 2604#ifdef MHD_TLSLIB_NEED_PUSH_FUNC
2605 gnutls_transport_set_push_function (connection->tls_session, 2605 gnutls_transport_set_push_function (connection->tls_session,
2606 MHD_tls_push_func_); 2606 MHD_tls_push_func_);
2607#endif /* MHD_TLSLIB_NEED_PUSH_FUNC */ 2607#endif /* MHD_TLSLIB_NEED_PUSH_FUNC */
2608 if (daemon->https_mem_trust) 2608 if (daemon->https_mem_trust)
2609 gnutls_certificate_server_set_request (connection->tls_session, 2609 gnutls_certificate_server_set_request (connection->tls_session,
2610 GNUTLS_CERT_REQUEST); 2610 GNUTLS_CERT_REQUEST);
2611#else /* ! HTTPS_SUPPORT */ 2611#else /* ! HTTPS_SUPPORT */
2612 eno = EINVAL; 2612 eno = EINVAL;
2613 goto cleanup; 2613 goto cleanup;
@@ -2641,8 +2641,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2641 connection); 2641 connection);
2642 } 2642 }
2643 DLL_insert (daemon->connections_head, 2643 DLL_insert (daemon->connections_head,
2644 daemon->connections_tail, 2644 daemon->connections_tail,
2645 connection); 2645 connection);
2646#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) 2646#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
2647 MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); 2647 MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
2648#endif 2648#endif
@@ -2661,13 +2661,13 @@ internal_add_connection (struct MHD_Daemon *daemon,
2661 &thread_main_handle_connection, 2661 &thread_main_handle_connection,
2662 connection)) 2662 connection))
2663 { 2663 {
2664 eno = errno; 2664 eno = errno;
2665#ifdef HAVE_MESSAGES 2665#ifdef HAVE_MESSAGES
2666 MHD_DLOG (daemon, 2666 MHD_DLOG (daemon,
2667 "Failed to create a thread: %s\n", 2667 "Failed to create a thread: %s\n",
2668 MHD_strerror_ (eno)); 2668 MHD_strerror_ (eno));
2669#endif 2669#endif
2670 goto cleanup; 2670 goto cleanup;
2671 } 2671 }
2672 } 2672 }
2673 else 2673 else
@@ -2683,9 +2683,9 @@ internal_add_connection (struct MHD_Daemon *daemon,
2683 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; 2683 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
2684 event.data.ptr = connection; 2684 event.data.ptr = connection;
2685 if (0 != epoll_ctl (daemon->epoll_fd, 2685 if (0 != epoll_ctl (daemon->epoll_fd,
2686 EPOLL_CTL_ADD, 2686 EPOLL_CTL_ADD,
2687 client_socket, 2687 client_socket,
2688 &event)) 2688 &event))
2689 { 2689 {
2690 eno = errno; 2690 eno = errno;
2691#ifdef HAVE_MESSAGES 2691#ifdef HAVE_MESSAGES
@@ -2702,8 +2702,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
2702 connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY 2702 connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY
2703 | MHD_EPOLL_STATE_IN_EREADY_EDLL; 2703 | MHD_EPOLL_STATE_IN_EREADY_EDLL;
2704 EDLL_insert (daemon->eready_head, 2704 EDLL_insert (daemon->eready_head,
2705 daemon->eready_tail, 2705 daemon->eready_tail,
2706 connection); 2706 connection);
2707 } 2707 }
2708 } 2708 }
2709 else /* This 'else' is combined with next 'if'. */ 2709 else /* This 'else' is combined with next 'if'. */
@@ -3041,12 +3041,12 @@ resume_suspended_connections (struct MHD_Daemon *daemon)
3041 { /* Wake up suspended connections. */ 3041 { /* Wake up suspended connections. */
3042 if (! MHD_itc_activate_(daemon->itc, 3042 if (! MHD_itc_activate_(daemon->itc,
3043 "w")) 3043 "w"))
3044 { 3044 {
3045#ifdef HAVE_MESSAGES 3045#ifdef HAVE_MESSAGES
3046 MHD_DLOG (daemon, 3046 MHD_DLOG (daemon,
3047 _("Failed to signal resume of connection via inter-thread communication channel.")); 3047 _("Failed to signal resume of connection via inter-thread communication channel."));
3048#endif 3048#endif
3049 } 3049 }
3050 } 3050 }
3051 return ret; 3051 return ret;
3052} 3052}
@@ -3081,11 +3081,12 @@ resume_suspended_connections (struct MHD_Daemon *daemon)
3081 */ 3081 */
3082int 3082int
3083MHD_add_connection (struct MHD_Daemon *daemon, 3083MHD_add_connection (struct MHD_Daemon *daemon,
3084 MHD_socket client_socket, 3084 MHD_socket client_socket,
3085 const struct sockaddr *addr, 3085 const struct sockaddr *addr,
3086 socklen_t addrlen) 3086 socklen_t addrlen)
3087{ 3087{
3088 bool sk_nonbl; 3088 bool sk_nonbl;
3089
3089 if (! MHD_socket_nonblocking_ (client_socket)) 3090 if (! MHD_socket_nonblocking_ (client_socket))
3090 { 3091 {
3091#ifdef HAVE_MESSAGES 3092#ifdef HAVE_MESSAGES
@@ -3116,11 +3117,11 @@ MHD_add_connection (struct MHD_Daemon *daemon,
3116#endif 3117#endif
3117 } 3118 }
3118 return internal_add_connection (daemon, 3119 return internal_add_connection (daemon,
3119 client_socket, 3120 client_socket,
3120 addr, 3121 addr,
3121 addrlen, 3122 addrlen,
3122 true, 3123 true,
3123 sk_nonbl); 3124 sk_nonbl);
3124} 3125}
3125 3126
3126 3127
@@ -3253,9 +3254,9 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
3253#endif 3254#endif
3254 (void) internal_add_connection (daemon, 3255 (void) internal_add_connection (daemon,
3255 s, 3256 s,
3256 addr, 3257 addr,
3257 addrlen, 3258 addrlen,
3258 false, 3259 false,
3259 sk_nonbl); 3260 sk_nonbl);
3260 return MHD_YES; 3261 return MHD_YES;
3261} 3262}
@@ -3381,7 +3382,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
3381 */ 3382 */
3382int 3383int
3383MHD_get_timeout (struct MHD_Daemon *daemon, 3384MHD_get_timeout (struct MHD_Daemon *daemon,
3384 MHD_UNSIGNED_LONG_LONG *timeout) 3385 MHD_UNSIGNED_LONG_LONG *timeout)
3385{ 3386{
3386 time_t earliest_deadline; 3387 time_t earliest_deadline;
3387 time_t now; 3388 time_t now;
@@ -4177,28 +4178,29 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4177 struct MHD_UpgradeResponseHandle * prev; 4178 struct MHD_UpgradeResponseHandle * prev;
4178 4179
4179 num_events = MAX_EVENTS; 4180 num_events = MAX_EVENTS;
4180 while (MAX_EVENTS == num_events) 4181 while (0 != num_events)
4181 { 4182 {
4182 unsigned int i; 4183 unsigned int i;
4183 /* update event masks */ 4184 /* update event masks */
4184 num_events = epoll_wait (daemon->epoll_upgrade_fd, 4185 num_events = epoll_wait (daemon->epoll_upgrade_fd,
4185 events, 4186 events,
4186 MAX_EVENTS, 4187 MAX_EVENTS,
4187 0); 4188 0);
4188 if (-1 == num_events) 4189 if (-1 == num_events)
4189 { 4190 {
4190 const int err = MHD_socket_get_error_ (); 4191 const int err = MHD_socket_get_error_ ();
4192
4191 if (MHD_SCKT_ERR_IS_EINTR_ (err)) 4193 if (MHD_SCKT_ERR_IS_EINTR_ (err))
4192 return MHD_YES; 4194 return MHD_YES;
4193#ifdef HAVE_MESSAGES 4195#ifdef HAVE_MESSAGES
4194 MHD_DLOG (daemon, 4196 MHD_DLOG (daemon,
4195 _("Call to epoll_wait failed: %s\n"), 4197 _("Call to epoll_wait failed: %s\n"),
4196 MHD_socket_strerr_ (err)); 4198 MHD_socket_strerr_ (err));
4197#endif 4199#endif
4198 return MHD_NO; 4200 return MHD_NO;
4199 } 4201 }
4200 for (i = 0; i < (unsigned int) num_events; i++) 4202 for (i = 0; i < (unsigned int) num_events; i++)
4201 { 4203 {
4202 struct UpgradeEpollHandle * const ueh = events[i].data.ptr; 4204 struct UpgradeEpollHandle * const ueh = events[i].data.ptr;
4203 struct MHD_UpgradeResponseHandle * const urh = ueh->urh; 4205 struct MHD_UpgradeResponseHandle * const urh = ueh->urh;
4204 bool new_err_state = false; 4206 bool new_err_state = false;
@@ -4216,24 +4218,24 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4216 4218
4217 if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) && 4219 if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) &&
4218 (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) ) 4220 (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) )
4219 { 4221 {
4220 /* Process new error state only one time 4222 /* Process new error state only one time
4221 * and avoid continuously marking this connection 4223 * and avoid continuously marking this connection
4222 * as 'ready'. */ 4224 * as 'ready'. */
4223 ueh->celi |= MHD_EPOLL_STATE_ERROR; 4225 ueh->celi |= MHD_EPOLL_STATE_ERROR;
4224 new_err_state = true; 4226 new_err_state = true;
4225 } 4227 }
4226 4228
4227 if (! urh->in_eready_list) 4229 if (! urh->in_eready_list)
4228 { 4230 {
4229 if (new_err_state || 4231 if (new_err_state ||
4230 is_urh_ready(urh)) 4232 is_urh_ready(urh))
4231 { 4233 {
4232 EDLL_insert (daemon->eready_urh_head, 4234 EDLL_insert (daemon->eready_urh_head,
4233 daemon->eready_urh_tail, 4235 daemon->eready_urh_tail,
4234 urh); 4236 urh);
4235 urh->in_eready_list = true; 4237 urh->in_eready_list = true;
4236 } 4238 }
4237 } 4239 }
4238 } 4240 }
4239 } 4241 }
@@ -4245,8 +4247,8 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4245 if (! is_urh_ready(pos)) 4247 if (! is_urh_ready(pos))
4246 { 4248 {
4247 EDLL_remove (daemon->eready_urh_head, 4249 EDLL_remove (daemon->eready_urh_head,
4248 daemon->eready_urh_tail, 4250 daemon->eready_urh_tail,
4249 pos); 4251 pos);
4250 pos->in_eready_list = false; 4252 pos->in_eready_list = false;
4251 } 4253 }
4252 /* Finished forwarding? */ 4254 /* Finished forwarding? */
@@ -4261,7 +4263,7 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon)
4261 * will be moved immediately to cleanup list. Otherwise 4263 * will be moved immediately to cleanup list. Otherwise
4262 * connection will stay in suspended list until 'pos' will 4264 * connection will stay in suspended list until 'pos' will
4263 * be marked with 'was_closed' by application. */ 4265 * be marked with 'was_closed' by application. */
4264 MHD_resume_connection(pos->connection); 4266 MHD_resume_connection (pos->connection);
4265 } 4267 }
4266 } 4268 }
4267 4269
@@ -4286,7 +4288,7 @@ static const char * const epoll_itc_marker = "itc_marker";
4286 */ 4288 */
4287static int 4289static int
4288MHD_epoll (struct MHD_Daemon *daemon, 4290MHD_epoll (struct MHD_Daemon *daemon,
4289 int may_block) 4291 int may_block)
4290{ 4292{
4291#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4293#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4292 static const char * const upgrade_marker = "upgrade_ptr"; 4294 static const char * const upgrade_marker = "upgrade_ptr";
@@ -4301,7 +4303,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
4301 unsigned int i; 4303 unsigned int i;
4302 MHD_socket ls; 4304 MHD_socket ls;
4303#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4305#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4304 int run_upgraded = MHD_NO; 4306 bool run_upgraded = false;
4305#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4307#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4306 4308
4307 if (-1 == daemon->epoll_fd) 4309 if (-1 == daemon->epoll_fd)
@@ -4317,50 +4319,50 @@ MHD_epoll (struct MHD_Daemon *daemon,
4317 event.events = EPOLLIN; 4319 event.events = EPOLLIN;
4318 event.data.ptr = daemon; 4320 event.data.ptr = daemon;
4319 if (0 != epoll_ctl (daemon->epoll_fd, 4321 if (0 != epoll_ctl (daemon->epoll_fd,
4320 EPOLL_CTL_ADD, 4322 EPOLL_CTL_ADD,
4321 ls, 4323 ls,
4322 &event)) 4324 &event))
4323 { 4325 {
4324#ifdef HAVE_MESSAGES 4326#ifdef HAVE_MESSAGES
4325 MHD_DLOG (daemon, 4327 MHD_DLOG (daemon,
4326 _("Call to epoll_ctl failed: %s\n"), 4328 _("Call to epoll_ctl failed: %s\n"),
4327 MHD_socket_last_strerr_ ()); 4329 MHD_socket_last_strerr_ ());
4328#endif 4330#endif
4329 return MHD_NO; 4331 return MHD_NO;
4330 } 4332 }
4331 daemon->listen_socket_in_epoll = true; 4333 daemon->listen_socket_in_epoll = true;
4332 } 4334 }
4333 if ( (daemon->was_quiesced) && 4335 if ( (daemon->was_quiesced) &&
4334 (daemon->listen_socket_in_epoll) ) 4336 (daemon->listen_socket_in_epoll) )
4335 { 4337 {
4336 if ( (0 != epoll_ctl (daemon->epoll_fd, 4338 if ( (0 != epoll_ctl (daemon->epoll_fd,
4337 EPOLL_CTL_DEL, 4339 EPOLL_CTL_DEL,
4338 ls, 4340 ls,
4339 NULL)) && 4341 NULL)) &&
4340 (ENOENT != errno) ) /* ENOENT can happen due to race with 4342 (ENOENT != errno) ) /* ENOENT can happen due to race with
4341 #MHD_quiesce_daemon() */ 4343 #MHD_quiesce_daemon() */
4342 MHD_PANIC ("Failed to remove listen FD from epoll set\n"); 4344 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
4343 daemon->listen_socket_in_epoll = false; 4345 daemon->listen_socket_in_epoll = false;
4344 } 4346 }
4345 4347
4346#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4348#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4347 if ( (! daemon->upgrade_fd_in_epoll) && 4349 if ( ( (! daemon->upgrade_fd_in_epoll) &&
4348 (-1 != daemon->epoll_upgrade_fd) ) 4350 (-1 != daemon->epoll_upgrade_fd) ) )
4349 { 4351 {
4350 event.events = EPOLLIN | EPOLLOUT; 4352 event.events = EPOLLIN | EPOLLOUT;
4351 event.data.ptr = (void *) upgrade_marker; 4353 event.data.ptr = (void *) upgrade_marker;
4352 if (0 != epoll_ctl (daemon->epoll_fd, 4354 if (0 != epoll_ctl (daemon->epoll_fd,
4353 EPOLL_CTL_ADD, 4355 EPOLL_CTL_ADD,
4354 daemon->epoll_upgrade_fd, 4356 daemon->epoll_upgrade_fd,
4355 &event)) 4357 &event))
4356 { 4358 {
4357#ifdef HAVE_MESSAGES 4359#ifdef HAVE_MESSAGES
4358 MHD_DLOG (daemon, 4360 MHD_DLOG (daemon,
4359 _("Call to epoll_ctl failed: %s\n"), 4361 _("Call to epoll_ctl failed: %s\n"),
4360 MHD_socket_last_strerr_ ()); 4362 MHD_socket_last_strerr_ ());
4361#endif 4363#endif
4362 return MHD_NO; 4364 return MHD_NO;
4363 } 4365 }
4364 daemon->upgrade_fd_in_epoll = true; 4366 daemon->upgrade_fd_in_epoll = true;
4365 } 4367 }
4366#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4368#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
@@ -4372,10 +4374,10 @@ MHD_epoll (struct MHD_Daemon *daemon,
4372 /* we're at the connection limit, disable listen socket 4374 /* we're at the connection limit, disable listen socket
4373 for event loop for now */ 4375 for event loop for now */
4374 if (0 != epoll_ctl (daemon->epoll_fd, 4376 if (0 != epoll_ctl (daemon->epoll_fd,
4375 EPOLL_CTL_DEL, 4377 EPOLL_CTL_DEL,
4376 ls, 4378 ls,
4377 NULL)) 4379 NULL))
4378 MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); 4380 MHD_PANIC (_("Failed to remove listen FD from epoll set\n"));
4379 daemon->listen_socket_in_epoll = false; 4381 daemon->listen_socket_in_epoll = false;
4380 } 4382 }
4381 4383
@@ -4386,15 +4388,15 @@ MHD_epoll (struct MHD_Daemon *daemon,
4386 if (MHD_YES == may_block) 4388 if (MHD_YES == may_block)
4387 { 4389 {
4388 if (MHD_YES == MHD_get_timeout (daemon, 4390 if (MHD_YES == MHD_get_timeout (daemon,
4389 &timeout_ll)) 4391 &timeout_ll))
4390 { 4392 {
4391 if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) 4393 if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
4392 timeout_ms = INT_MAX; 4394 timeout_ms = INT_MAX;
4393 else 4395 else
4394 timeout_ms = (int) timeout_ll; 4396 timeout_ms = (int) timeout_ll;
4395 } 4397 }
4396 else 4398 else
4397 timeout_ms = -1; 4399 timeout_ms = -1;
4398 } 4400 }
4399 else 4401 else
4400 timeout_ms = 0; 4402 timeout_ms = 0;
@@ -4413,33 +4415,33 @@ MHD_epoll (struct MHD_Daemon *daemon,
4413 { 4415 {
4414 /* update event masks */ 4416 /* update event masks */
4415 num_events = epoll_wait (daemon->epoll_fd, 4417 num_events = epoll_wait (daemon->epoll_fd,
4416 events, 4418 events,
4417 MAX_EVENTS, 4419 MAX_EVENTS,
4418 timeout_ms); 4420 timeout_ms);
4419 if (-1 == num_events) 4421 if (-1 == num_events)
4420 { 4422 {
4421 const int err = MHD_socket_get_error_ (); 4423 const int err = MHD_socket_get_error_ ();
4422 if (MHD_SCKT_ERR_IS_EINTR_ (err)) 4424 if (MHD_SCKT_ERR_IS_EINTR_ (err))
4423 return MHD_YES; 4425 return MHD_YES;
4424#ifdef HAVE_MESSAGES 4426#ifdef HAVE_MESSAGES
4425 MHD_DLOG (daemon, 4427 MHD_DLOG (daemon,
4426 _("Call to epoll_wait failed: %s\n"), 4428 _("Call to epoll_wait failed: %s\n"),
4427 MHD_socket_strerr_ (err)); 4429 MHD_socket_strerr_ (err));
4428#endif 4430#endif
4429 return MHD_NO; 4431 return MHD_NO;
4430 } 4432 }
4431 for (i=0;i<(unsigned int) num_events;i++) 4433 for (i=0;i<(unsigned int) num_events;i++)
4432 { 4434 {
4433 /* First, check for the values of `ptr` that would indicate 4435 /* First, check for the values of `ptr` that would indicate
4434 that this event is not about a normal connection. */ 4436 that this event is not about a normal connection. */
4435 if (NULL == events[i].data.ptr) 4437 if (NULL == events[i].data.ptr)
4436 continue; /* shutdown signal! */ 4438 continue; /* shutdown signal! */
4437#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4439#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4438 if (upgrade_marker == events[i].data.ptr) 4440 if (upgrade_marker == events[i].data.ptr)
4439 { 4441 {
4440 /* activity on an upgraded connection, we process 4442 /* activity on an upgraded connection, we process
4441 those in a separate epoll() */ 4443 those in a separate epoll() */
4442 run_upgraded = MHD_YES; 4444 run_upgraded = true;
4443 continue; 4445 continue;
4444 } 4446 }
4445#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4447#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
@@ -4450,8 +4452,8 @@ MHD_epoll (struct MHD_Daemon *daemon,
4450 MHD_itc_clear_ (daemon->itc); 4452 MHD_itc_clear_ (daemon->itc);
4451 continue; 4453 continue;
4452 } 4454 }
4453 if (daemon == events[i].data.ptr) 4455 if (daemon == events[i].data.ptr)
4454 { 4456 {
4455 /* Check for error conditions on listen socket. */ 4457 /* Check for error conditions on listen socket. */
4456 /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */ 4458 /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */
4457 if (0 == (events[i].events & (EPOLLERR | EPOLLHUP))) 4459 if (0 == (events[i].events & (EPOLLERR | EPOLLHUP)))
@@ -4466,9 +4468,9 @@ MHD_epoll (struct MHD_Daemon *daemon,
4466 (daemon->connections < daemon->connection_limit) && 4468 (daemon->connections < daemon->connection_limit) &&
4467 (! daemon->at_limit) ) 4469 (! daemon->at_limit) )
4468 series_length++; 4470 series_length++;
4469 } 4471 }
4470 continue; 4472 continue;
4471 } 4473 }
4472 /* this is an event relating to a 'normal' connection, 4474 /* this is an event relating to a 'normal' connection,
4473 remember the event and if appropriate mark the 4475 remember the event and if appropriate mark the
4474 connection as 'eready'. */ 4476 connection as 'eready'. */
@@ -4517,7 +4519,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
4517 } 4519 }
4518 4520
4519#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4521#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4520 if (MHD_YES == run_upgraded) 4522 if (run_upgraded || (NULL != daemon->eready_urh_head))
4521 run_epoll_for_upgrade (daemon); 4523 run_epoll_for_upgrade (daemon);
4522#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4524#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4523 4525
@@ -4605,22 +4607,22 @@ MHD_run (struct MHD_Daemon *daemon)
4605 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) ) 4607 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) )
4606 return MHD_NO; 4608 return MHD_NO;
4607 if (0 != (daemon->options & MHD_USE_POLL)) 4609 if (0 != (daemon->options & MHD_USE_POLL))
4608 { 4610 {
4609 MHD_poll (daemon, MHD_NO); 4611 MHD_poll (daemon, MHD_NO);
4610 MHD_cleanup_connections (daemon); 4612 MHD_cleanup_connections (daemon);
4611 } 4613 }
4612#ifdef EPOLL_SUPPORT 4614#ifdef EPOLL_SUPPORT
4613 else if (0 != (daemon->options & MHD_USE_EPOLL)) 4615 else if (0 != (daemon->options & MHD_USE_EPOLL))
4614 { 4616 {
4615 MHD_epoll (daemon, MHD_NO); 4617 MHD_epoll (daemon, MHD_NO);
4616 MHD_cleanup_connections (daemon); 4618 MHD_cleanup_connections (daemon);
4617 } 4619 }
4618#endif 4620#endif
4619 else 4621 else
4620 { 4622 {
4621 MHD_select (daemon, MHD_NO); 4623 MHD_select (daemon, MHD_NO);
4622 /* MHD_select does MHD_cleanup_connections already */ 4624 /* MHD_select does MHD_cleanup_connections already */
4623 } 4625 }
4624 return MHD_YES; 4626 return MHD_YES;
4625} 4627}
4626 4628
@@ -4822,26 +4824,26 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4822 if (NULL != daemon->worker_pool) 4824 if (NULL != daemon->worker_pool)
4823 for (i = 0; i < daemon->worker_pool_size; i++) 4825 for (i = 0; i < daemon->worker_pool_size; i++)
4824 { 4826 {
4825 daemon->worker_pool[i].was_quiesced = true; 4827 daemon->worker_pool[i].was_quiesced = true;
4826#ifdef EPOLL_SUPPORT 4828#ifdef EPOLL_SUPPORT
4827 if ( (0 != (daemon->options & MHD_USE_EPOLL)) && 4829 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4828 (-1 != daemon->worker_pool[i].epoll_fd) && 4830 (-1 != daemon->worker_pool[i].epoll_fd) &&
4829 (daemon->worker_pool[i].listen_socket_in_epoll) ) 4831 (daemon->worker_pool[i].listen_socket_in_epoll) )
4830 {
4831 if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd,
4832 EPOLL_CTL_DEL,
4833 ret,
4834 NULL))
4835 MHD_PANIC (_("Failed to remove listen FD from epoll set\n"));
4836 daemon->worker_pool[i].listen_socket_in_epoll = false;
4837 }
4838 else
4839#endif
4840 if (MHD_ITC_IS_VALID_(daemon->worker_pool[i].itc))
4841 { 4832 {
4842 if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "q")) 4833 if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd,
4843 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); 4834 EPOLL_CTL_DEL,
4835 ret,
4836 NULL))
4837 MHD_PANIC (_("Failed to remove listen FD from epoll set\n"));
4838 daemon->worker_pool[i].listen_socket_in_epoll = false;
4844 } 4839 }
4840 else
4841#endif
4842 if (MHD_ITC_IS_VALID_(daemon->worker_pool[i].itc))
4843 {
4844 if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "q"))
4845 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel"));
4846 }
4845 } 4847 }
4846#endif 4848#endif
4847 daemon->was_quiesced = true; 4849 daemon->was_quiesced = true;
@@ -4856,7 +4858,7 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4856 NULL)) && 4858 NULL)) &&
4857 (ENOENT != errno) ) /* ENOENT can happen due to race with 4859 (ENOENT != errno) ) /* ENOENT can happen due to race with
4858 #MHD_epoll() */ 4860 #MHD_epoll() */
4859 MHD_PANIC ("Failed to remove listen FD from epoll set\n"); 4861 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
4860 daemon->listen_socket_in_epoll = false; 4862 daemon->listen_socket_in_epoll = false;
4861 } 4863 }
4862#endif 4864#endif
@@ -4890,8 +4892,8 @@ typedef void
4890 */ 4892 */
4891static int 4893static int
4892parse_options_va (struct MHD_Daemon *daemon, 4894parse_options_va (struct MHD_Daemon *daemon,
4893 const struct sockaddr **servaddr, 4895 const struct sockaddr **servaddr,
4894 va_list ap); 4896 va_list ap);
4895 4897
4896 4898
4897/** 4899/**
@@ -4929,8 +4931,8 @@ parse_options (struct MHD_Daemon *daemon,
4929 */ 4931 */
4930static int 4932static int
4931parse_options_va (struct MHD_Daemon *daemon, 4933parse_options_va (struct MHD_Daemon *daemon,
4932 const struct sockaddr **servaddr, 4934 const struct sockaddr **servaddr,
4933 va_list ap) 4935 va_list ap)
4934{ 4936{
4935 enum MHD_OPTION opt; 4937 enum MHD_OPTION opt;
4936 struct MHD_OptionItem *oa; 4938 struct MHD_OptionItem *oa;
@@ -6493,10 +6495,10 @@ thread_failed:
6493 if (daemon->upgrade_fd_in_epoll) 6495 if (daemon->upgrade_fd_in_epoll)
6494 { 6496 {
6495 if (0 != epoll_ctl (daemon->epoll_fd, 6497 if (0 != epoll_ctl (daemon->epoll_fd,
6496 EPOLL_CTL_DEL, 6498 EPOLL_CTL_DEL,
6497 daemon->epoll_upgrade_fd, 6499 daemon->epoll_upgrade_fd,
6498 NULL)) 6500 NULL))
6499 MHD_PANIC (_("Failed to remove FD from epoll set\n")); 6501 MHD_PANIC (_("Failed to remove FD from epoll set\n"));
6500 daemon->upgrade_fd_in_epoll = false; 6502 daemon->upgrade_fd_in_epoll = false;
6501 } 6503 }
6502#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 6504#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 6e569d77..7b98a45c 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -80,9 +80,9 @@
80 */ 80 */
81static int 81static int
82add_response_entry (struct MHD_Response *response, 82add_response_entry (struct MHD_Response *response,
83 enum MHD_ValueKind kind, 83 enum MHD_ValueKind kind,
84 const char *header, 84 const char *header,
85 const char *content) 85 const char *content)
86{ 86{
87 struct MHD_HTTP_Header *hdr; 87 struct MHD_HTTP_Header *hdr;
88 88
@@ -280,7 +280,7 @@ MHD_get_response_headers (struct MHD_Response *response,
280 */ 280 */
281const char * 281const char *
282MHD_get_response_header (struct MHD_Response *response, 282MHD_get_response_header (struct MHD_Response *response,
283 const char *key) 283 const char *key)
284{ 284{
285 struct MHD_HTTP_Header *pos; 285 struct MHD_HTTP_Header *pos;
286 size_t key_size; 286 size_t key_size;
@@ -732,8 +732,8 @@ MHD_create_response_from_data (size_t size,
732 */ 732 */
733struct MHD_Response * 733struct MHD_Response *
734MHD_create_response_from_buffer (size_t size, 734MHD_create_response_from_buffer (size_t size,
735 void *buffer, 735 void *buffer,
736 enum MHD_ResponseMemoryMode mode) 736 enum MHD_ResponseMemoryMode mode)
737{ 737{
738 return MHD_create_response_from_data (size, 738 return MHD_create_response_from_data (size,
739 buffer, 739 buffer,
@@ -754,15 +754,15 @@ MHD_create_response_from_buffer (size_t size,
754 */ 754 */
755_MHD_EXTERN struct MHD_Response * 755_MHD_EXTERN struct MHD_Response *
756MHD_create_response_from_buffer_with_free_callback (size_t size, 756MHD_create_response_from_buffer_with_free_callback (size_t size,
757 void *buffer, 757 void *buffer,
758 MHD_ContentReaderFreeCallback crfc) 758 MHD_ContentReaderFreeCallback crfc)
759{ 759{
760 struct MHD_Response *r; 760 struct MHD_Response *r;
761 761
762 r = MHD_create_response_from_data (size, 762 r = MHD_create_response_from_data (size,
763 buffer, 763 buffer,
764 MHD_YES, 764 MHD_YES,
765 MHD_NO); 765 MHD_NO);
766 if (NULL == r) 766 if (NULL == r)
767 return r; 767 return r;
768 r->crfc = crfc; 768 r->crfc = crfc;
@@ -997,17 +997,17 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
997 EPOLL_CTL_ADD, 997 EPOLL_CTL_ADD,
998 connection->socket_fd, 998 connection->socket_fd,
999 &event)) 999 &event))
1000 { 1000 {
1001#ifdef HAVE_MESSAGES 1001#ifdef HAVE_MESSAGES
1002 MHD_DLOG (daemon, 1002 MHD_DLOG (daemon,
1003 _("Call to epoll_ctl failed: %s\n"), 1003 _("Call to epoll_ctl failed: %s\n"),
1004 MHD_socket_last_strerr_ ()); 1004 MHD_socket_last_strerr_ ());
1005#endif 1005#endif
1006 MHD_socket_close_chk_ (sv[0]); 1006 MHD_socket_close_chk_ (sv[0]);
1007 MHD_socket_close_chk_ (sv[1]); 1007 MHD_socket_close_chk_ (sv[1]);
1008 free (urh); 1008 free (urh);
1009 return MHD_NO; 1009 return MHD_NO;
1010 } 1010 }
1011 1011
1012 /* Second, add our end of the UNIX socketpair() */ 1012 /* Second, add our end of the UNIX socketpair() */
1013 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; 1013 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
@@ -1016,28 +1016,28 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
1016 EPOLL_CTL_ADD, 1016 EPOLL_CTL_ADD,
1017 urh->mhd.socket, 1017 urh->mhd.socket,
1018 &event)) 1018 &event))
1019 { 1019 {
1020 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; 1020 event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
1021 event.data.ptr = &urh->app; 1021 event.data.ptr = &urh->app;
1022 if (0 != epoll_ctl (daemon->epoll_upgrade_fd, 1022 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
1023 EPOLL_CTL_DEL, 1023 EPOLL_CTL_DEL,
1024 connection->socket_fd, 1024 connection->socket_fd,
1025 &event)) 1025 &event))
1026 MHD_PANIC (_("Error cleaning up while handling epoll error")); 1026 MHD_PANIC (_("Error cleaning up while handling epoll error"));
1027#ifdef HAVE_MESSAGES 1027#ifdef HAVE_MESSAGES
1028 MHD_DLOG (daemon, 1028 MHD_DLOG (daemon,
1029 _("Call to epoll_ctl failed: %s\n"), 1029 _("Call to epoll_ctl failed: %s\n"),
1030 MHD_socket_last_strerr_ ()); 1030 MHD_socket_last_strerr_ ());
1031#endif 1031#endif
1032 MHD_socket_close_chk_ (sv[0]); 1032 MHD_socket_close_chk_ (sv[0]);
1033 MHD_socket_close_chk_ (sv[1]); 1033 MHD_socket_close_chk_ (sv[1]);
1034 free (urh); 1034 free (urh);
1035 return MHD_NO; 1035 return MHD_NO;
1036 } 1036 }
1037 EDLL_insert (daemon->eready_urh_head, 1037 EDLL_insert (daemon->eready_urh_head,
1038 daemon->eready_urh_tail, 1038 daemon->eready_urh_tail,
1039 urh); 1039 urh);
1040 urh->in_eready_list = true; 1040 urh->in_eready_list = true;
1041 } 1041 }
1042#endif /* EPOLL_SUPPORT */ 1042#endif /* EPOLL_SUPPORT */
1043 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) 1043 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) )
diff --git a/src/microhttpd/test_upgrade_large.c b/src/microhttpd/test_upgrade_large.c
new file mode 100644
index 00000000..6f2a1b94
--- /dev/null
+++ b/src/microhttpd/test_upgrade_large.c
@@ -0,0 +1,1386 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016, 2019 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_upgrade_large.c
23 * @brief Testcase for libmicrohttpd upgrading a connection,
24 * modified to test the "large" corner case reported
25 * by Viet on the mailinglist in 6'2019
26 * @author Christian Grothoff
27 * @author Karlson2k (Evgeny Grin)
28 */
29
30#include "mhd_options.h"
31#include <stdlib.h>
32#include <string.h>
33#include <stdio.h>
34#include <pthread.h>
35#include <stdlib.h>
36#include <stddef.h>
37#ifndef WINDOWS
38#include <unistd.h>
39#endif
40#ifdef HAVE_STDBOOL_H
41#include <stdbool.h>
42#endif /* HAVE_STDBOOL_H */
43
44#include "mhd_sockets.h"
45#ifdef HAVE_NETINET_IP_H
46#include <netinet/ip.h>
47#endif /* HAVE_NETINET_IP_H */
48
49#include "platform.h"
50#include "microhttpd.h"
51
52#include "test_helpers.h"
53
54#define LARGE_STRING "HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello"
55
56#define LARGE_REPLY_STRING "WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorld"
57
58#ifdef HTTPS_SUPPORT
59#include <gnutls/gnutls.h>
60#include "../testcurl/https/tls_test_keys.h"
61
62#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
63#include <sys/types.h>
64#include <sys/wait.h>
65#endif /* HAVE_FORK && HAVE_WAITPID */
66#endif /* HTTPS_SUPPORT */
67
68static int verbose = 0;
69
70static int kicker[2] = {-1, -1} ;
71
72enum tls_tool
73{
74 TLS_CLI_NO_TOOL = 0,
75 TLS_CLI_GNUTLS,
76 TLS_CLI_OPENSSL,
77 TLS_LIB_GNUTLS
78};
79
80enum tls_tool use_tls_tool;
81
82#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
83/**
84 * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to
85 * talk to our port over a socket in @a sp without having to worry
86 * about TLS.
87 *
88 * @param location where the socket is returned
89 * @return -1 on error, otherwise PID of TLS child process
90 */
91static pid_t
92gnutlscli_connect (int *sock,
93 uint16_t port)
94{
95 pid_t chld;
96 int sp[2];
97 char destination[30];
98
99 if (0 != socketpair (AF_UNIX,
100 SOCK_STREAM,
101 0,
102 sp))
103 return -1;
104 chld = fork ();
105 if (0 != chld)
106 {
107 *sock = sp[1];
108 MHD_socket_close_chk_ (sp[0]);
109 return chld;
110 }
111 MHD_socket_close_chk_ (sp[1]);
112 (void) close (0);
113 (void) close (1);
114 if (-1 == dup2 (sp[0], 0))
115 abort ();
116 if (-1 == dup2 (sp[0], 1))
117 abort ();
118 MHD_socket_close_chk_ (sp[0]);
119 if (TLS_CLI_GNUTLS == use_tls_tool)
120 {
121 snprintf (destination,
122 sizeof(destination),
123 "%u",
124 (unsigned int) port);
125 execlp ("gnutls-cli",
126 "gnutls-cli",
127 "--insecure",
128 "-p",
129 destination,
130 "127.0.0.1",
131 (char *) NULL);
132 }
133 else if (TLS_CLI_OPENSSL == use_tls_tool)
134 {
135 snprintf (destination,
136 sizeof(destination),
137 "127.0.0.1:%u",
138 (unsigned int) port);
139 execlp ("openssl",
140 "openssl",
141 "s_client",
142 "-connect",
143 destination,
144 "-verify",
145 "1",
146 (char *) NULL);
147 }
148 _exit (1);
149}
150#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
151
152
153/**
154 * Wrapper structure for plain&TLS sockets
155 */
156struct wr_socket
157{
158 /**
159 * Real network socket
160 */
161 MHD_socket fd;
162
163 /**
164 * Type of this socket
165 */
166 enum wr_type
167 {
168 wr_invalid = 0,
169 wr_plain = 1,
170 wr_tls = 2
171 } t;
172#ifdef HTTPS_SUPPORT
173 /**
174 * TLS credentials
175 */
176 gnutls_certificate_credentials_t tls_crd;
177
178 /**
179 * TLS session.
180 */
181 gnutls_session_t tls_s;
182
183 /**
184 * TLS handshake already succeed?
185 */
186 bool tls_connected;
187#endif
188};
189
190
191/**
192 * Get underlying real socket.
193 * @return FD of real socket
194 */
195#define wr_fd(s) ((s)->fd)
196
197
198/**
199 * Create wr_socket with plain TCP underlying socket
200 * @return created socket on success, NULL otherwise
201 */
202static struct wr_socket *
203wr_create_plain_sckt(void)
204{
205 struct wr_socket *s = malloc(sizeof(struct wr_socket));
206 if (NULL == s)
207 return NULL;
208 s->t = wr_plain;
209 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
210 if (MHD_INVALID_SOCKET != s->fd)
211 return s;
212 free(s);
213 return NULL;
214}
215
216
217/**
218 * Create wr_socket with TLS TCP underlying socket
219 * @return created socket on success, NULL otherwise
220 */
221static struct wr_socket *
222wr_create_tls_sckt(void)
223{
224#ifdef HTTPS_SUPPORT
225 struct wr_socket *s = malloc(sizeof(struct wr_socket));
226 if (NULL == s)
227 return NULL;
228 s->t = wr_tls;
229 s->tls_connected = 0;
230 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
231 if (MHD_INVALID_SOCKET != s->fd)
232 {
233 if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT))
234 {
235 if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s))
236 {
237 if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (&(s->tls_crd)))
238 {
239 if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, GNUTLS_CRD_CERTIFICATE, s->tls_crd))
240 {
241#if GNUTLS_VERSION_NUMBER+0 >= 0x030109
242 gnutls_transport_set_int (s->tls_s, (int)(s->fd));
243#else /* GnuTLS before 3.1.9 */
244 gnutls_transport_set_ptr (s->tls_s, (gnutls_transport_ptr_t)(intptr_t)(s->fd));
245#endif /* GnuTLS before 3.1.9 */
246 return s;
247 }
248 gnutls_certificate_free_credentials (s->tls_crd);
249 }
250 }
251 gnutls_deinit (s->tls_s);
252 }
253 (void)MHD_socket_close_ (s->fd);
254 }
255 free(s);
256#endif /* HTTPS_SUPPORT */
257 return NULL;
258}
259
260
261/**
262 * Create wr_socket with plain TCP underlying socket
263 * from already created TCP socket.
264 * @param plain_sk real TCP socket
265 * @return created socket on success, NULL otherwise
266 */
267static struct wr_socket *
268wr_create_from_plain_sckt(MHD_socket plain_sk)
269{
270 struct wr_socket *s = malloc(sizeof(struct wr_socket));
271
272 if (NULL == s)
273 return NULL;
274 s->t = wr_plain;
275 s->fd = plain_sk;
276 return s;
277}
278
279
280/**
281 * Connect socket to specified address.
282 * @param s socket to use
283 * @param addr address to connect
284 * @param length of sturcture pointed by @a addr
285 * @return zero on success, -1 otherwise.
286 */
287static int
288wr_connect(struct wr_socket *s,
289 const struct sockaddr *addr,
290 int length)
291{
292 if (0 != connect (s->fd, addr, length))
293 return -1;
294 if (wr_plain == s->t)
295 return 0;
296#ifdef HTTPS_SUPPORT
297 if (wr_tls == s->t)
298 {
299 /* Do not try handshake here as
300 * it require processing on MHD side and
301 * when testing with "external" polling,
302 * test will call MHD processing only
303 * after return from wr_connect(). */
304 s->tls_connected = 0;
305 return 0;
306 }
307#endif /* HTTPS_SUPPORT */
308 return -1;
309}
310
311#ifdef HTTPS_SUPPORT
312/* Only to be called from wr_send() and wr_recv() ! */
313static bool
314wr_handshake(struct wr_socket *s)
315{
316 int res = gnutls_handshake (s->tls_s);
317 if (GNUTLS_E_SUCCESS == res)
318 s->tls_connected = true;
319 else if (GNUTLS_E_AGAIN == res)
320 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
321 else
322 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
323 return s->tls_connected;
324}
325#endif /* HTTPS_SUPPORT */
326
327
328/**
329 * Send data to remote by socket.
330 * @param s the socket to use
331 * @param buf the buffer with data to send
332 * @param len the length of data in @a buf
333 * @return number of bytes were sent if succeed,
334 * -1 if failed. Use #MHD_socket_get_error_()
335 * to get socket error.
336 */
337static ssize_t
338wr_send (struct wr_socket *s,
339 const void *buf,
340 size_t len)
341{
342 if (wr_plain == s->t)
343 return MHD_send_(s->fd, buf, len);
344#ifdef HTTPS_SUPPORT
345 if (wr_tls == s->t)
346 {
347 ssize_t ret;
348 if (!s->tls_connected && !wr_handshake (s))
349 return -1;
350
351 ret = gnutls_record_send (s->tls_s, buf, len);
352 if (ret > 0)
353 return ret;
354 if (GNUTLS_E_AGAIN == ret)
355 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
356 else
357 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
358 }
359#endif /* HTTPS_SUPPORT */
360 return -1;
361}
362
363
364/**
365 * Receive data from remote by socket.
366 * @param s the socket to use
367 * @param buf the buffer to store received data
368 * @param len the length of @a buf
369 * @return number of bytes were received if succeed,
370 * -1 if failed. Use #MHD_socket_get_error_()
371 * to get socket error.
372 */
373static ssize_t
374wr_recv (struct wr_socket *s,
375 void *buf,
376 size_t len)
377{
378 if (wr_plain == s->t)
379 return MHD_recv_ (s->fd, buf, len);
380#ifdef HTTPS_SUPPORT
381 if (wr_tls == s->t)
382 {
383 ssize_t ret;
384 if (!s->tls_connected && !wr_handshake (s))
385 return -1;
386
387 ret = gnutls_record_recv (s->tls_s, buf, len);
388 if (ret > 0)
389 return ret;
390 if (GNUTLS_E_AGAIN == ret)
391 MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
392 else
393 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
394 }
395#endif /* HTTPS_SUPPORT */
396 return -1;
397}
398
399
400/**
401 * Close socket and release allocated resourced
402 * @param s the socket to close
403 * @return zero on succeed, -1 otherwise
404 */
405static int
406wr_close (struct wr_socket *s)
407{
408 int ret = (MHD_socket_close_(s->fd)) ? 0 : -1;
409#ifdef HTTPS_SUPPORT
410 if (wr_tls == s->t)
411 {
412 gnutls_deinit (s->tls_s);
413 gnutls_certificate_free_credentials (s->tls_crd);
414 }
415#endif /* HTTPS_SUPPORT */
416 free (s);
417 return ret;
418}
419
420
421/**
422 * Thread we use to run the interaction with the upgraded socket.
423 */
424static pthread_t pt;
425
426/**
427 * Will be set to the upgraded socket.
428 */
429static struct wr_socket *usock;
430
431/**
432 * Thread we use to run the interaction with the upgraded socket.
433 */
434static pthread_t pt_client;
435
436/**
437 * Flag set to 1 once the test is finished.
438 */
439static volatile bool done;
440
441
442/**
443 * Callback used by MHD to notify the application about completed
444 * requests. Frees memory.
445 *
446 * @param cls client-defined closure
447 * @param connection connection handle
448 * @param con_cls value as set by the last call to
449 * the #MHD_AccessHandlerCallback
450 * @param toe reason for request termination
451 */
452static void
453notify_completed_cb (void *cls,
454 struct MHD_Connection *connection,
455 void **con_cls,
456 enum MHD_RequestTerminationCode toe)
457{
458 pthread_t* ppth = *con_cls;
459
460 (void) cls;
461 (void) connection; /* Unused. Silent compiler warning. */
462 if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) &&
463 (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) &&
464 (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) )
465 abort ();
466 if (! pthread_equal (**((pthread_t**)con_cls),
467 pthread_self ()))
468 abort ();
469 if (NULL != ppth)
470 free (*con_cls);
471 *con_cls = NULL;
472}
473
474
475/**
476 * Logging callback.
477 *
478 * @param cls logging closure (NULL)
479 * @param uri access URI
480 * @param connection connection handle
481 * @return #TEST_PTR
482 */
483static void *
484log_cb (void *cls,
485 const char *uri,
486 struct MHD_Connection *connection)
487{
488 pthread_t *ppth;
489
490 (void) cls;
491 (void) connection; /* Unused. Silent compiler warning. */
492 if (0 != strcmp (uri,
493 "/"))
494 abort ();
495 ppth = malloc (sizeof (pthread_t));
496 if (NULL == ppth)
497 abort();
498 *ppth = pthread_self ();
499 return (void *) ppth;
500}
501
502
503/**
504 * Function to check that MHD properly notifies about starting
505 * and stopping.
506 *
507 * @param cls client-defined closure
508 * @param connection connection handle
509 * @param socket_context socket-specific pointer where the
510 * client can associate some state specific
511 * to the TCP connection; note that this is
512 * different from the "con_cls" which is per
513 * HTTP request. The client can initialize
514 * during #MHD_CONNECTION_NOTIFY_STARTED and
515 * cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
516 * and access in the meantime using
517 * #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
518 * @param toe reason for connection notification
519 * @see #MHD_OPTION_NOTIFY_CONNECTION
520 * @ingroup request
521 */
522static void
523notify_connection_cb (void *cls,
524 struct MHD_Connection *connection,
525 void **socket_context,
526 enum MHD_ConnectionNotificationCode toe)
527{
528 static int started;
529
530 (void) cls;
531 (void) connection; /* Unused. Silent compiler warning. */
532 switch (toe)
533 {
534 case MHD_CONNECTION_NOTIFY_STARTED:
535 if (MHD_NO != started)
536 abort ();
537 started = MHD_YES;
538 *socket_context = &started;
539 break;
540 case MHD_CONNECTION_NOTIFY_CLOSED:
541 if (MHD_YES != started)
542 abort ();
543 if (&started != *socket_context)
544 abort ();
545 *socket_context = NULL;
546 started = MHD_NO;
547 break;
548 }
549}
550
551
552/**
553 * Change socket to blocking.
554 *
555 * @param fd the socket to manipulate
556 * @return non-zero if succeeded, zero otherwise
557 */
558static void
559make_blocking (MHD_socket fd)
560{
561#if defined(MHD_POSIX_SOCKETS)
562 int flags;
563
564 flags = fcntl (fd, F_GETFL);
565 if (-1 == flags)
566 return;
567 if ((flags & ~O_NONBLOCK) != flags)
568 if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
569 abort ();
570#elif defined(MHD_WINSOCK_SOCKETS)
571 unsigned long flags = 1;
572
573 ioctlsocket (fd, FIONBIO, &flags);
574#endif /* MHD_WINSOCK_SOCKETS */
575}
576
577
578static void
579kick_select ()
580{
581 if (-1 != kicker[1])
582 {
583 write (kicker[1], "K", 1);
584 fprintf (stderr, "KICKING\n");
585 }
586}
587
588
589static void
590send_all (struct wr_socket *sock,
591 const char *text)
592{
593 size_t len = strlen (text);
594 ssize_t ret;
595 size_t off;
596
597 make_blocking (wr_fd (sock));
598 for (off = 0; off < len; off += ret)
599 {
600 ret = wr_send (sock,
601 &text[off],
602 len - off);
603 kick_select ();
604 if (0 > ret)
605 {
606 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
607 {
608 ret = 0;
609 continue;
610 }
611 abort ();
612 }
613 }
614}
615
616
617/**
618 * Read character-by-character until we
619 * get '\r\n\r\n'.
620 */
621static void
622recv_hdr (struct wr_socket *sock)
623{
624 unsigned int i;
625 char next;
626 char c;
627 ssize_t ret;
628
629 make_blocking (wr_fd (sock));
630 next = '\r';
631 i = 0;
632 while (i < 4)
633 {
634 ret = wr_recv (sock,
635 &c,
636 1);
637 kick_select ();
638 if (0 > ret)
639 {
640 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
641 continue;
642 abort ();
643 }
644 if (0 == ret)
645 continue;
646 if (c == next)
647 {
648 i++;
649 if (next == '\r')
650 next = '\n';
651 else
652 next = '\r';
653 continue;
654 }
655 if (c == '\r')
656 {
657 i = 1;
658 next = '\n';
659 continue;
660 }
661 i = 0;
662 next = '\r';
663 }
664}
665
666
667static void
668recv_all (struct wr_socket *sock,
669 const char *text)
670{
671 size_t len = strlen (text);
672 char buf[len];
673 ssize_t ret;
674 size_t off;
675
676 make_blocking (wr_fd (sock));
677 for (off = 0; off < len; off += ret)
678 {
679 ret = wr_recv (sock,
680 &buf[off],
681 len - off);
682 if (0 > ret)
683 {
684 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
685 {
686 ret = 0;
687 continue;
688 }
689 abort ();
690 }
691 }
692 if (0 != strncmp (text, buf, len))
693 abort();
694}
695
696
697/**
698 * Main function for the thread that runs the interaction with
699 * the upgraded socket.
700 *
701 * @param cls the handle for the upgrade
702 */
703static void *
704run_usock (void *cls)
705{
706 struct MHD_UpgradeResponseHandle *urh = cls;
707
708 send_all (usock,
709 LARGE_STRING);
710 recv_all (usock,
711 LARGE_REPLY_STRING);
712 send_all (usock,
713 "Finished");
714 MHD_upgrade_action (urh,
715 MHD_UPGRADE_ACTION_CLOSE);
716 free (usock);
717 usock = NULL;
718 return NULL;
719}
720
721
722/**
723 * Main function for the thread that runs the client-side of the
724 * interaction with the upgraded socket.
725 *
726 * @param cls the client socket
727 */
728static void *
729run_usock_client (void *cls)
730{
731 struct wr_socket *sock = cls;
732
733 send_all (sock,
734 "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
735 recv_hdr (sock);
736 recv_all (sock,
737 LARGE_STRING);
738 send_all (sock,
739 LARGE_REPLY_STRING);
740 recv_all (sock,
741 "Finished");
742 wr_close (sock);
743 done = true;
744 return NULL;
745}
746
747
748/**
749 * Function called after a protocol "upgrade" response was sent
750 * successfully and the socket should now be controlled by some
751 * protocol other than HTTP.
752 *
753 * Any data already received on the socket will be made available in
754 * @e extra_in. This can happen if the application sent extra data
755 * before MHD send the upgrade response. The application should
756 * treat data from @a extra_in as if it had read it from the socket.
757 *
758 * Note that the application must not close() @a sock directly,
759 * but instead use #MHD_upgrade_action() for special operations
760 * on @a sock.
761 *
762 * Except when in 'thread-per-connection' mode, implementations
763 * of this function should never block (as it will still be called
764 * from within the main event loop).
765 *
766 * @param cls closure, whatever was given to #MHD_create_response_for_upgrade().
767 * @param connection original HTTP connection handle,
768 * giving the function a last chance
769 * to inspect the original HTTP request
770 * @param con_cls last value left in `con_cls` of the `MHD_AccessHandlerCallback`
771 * @param extra_in if we happened to have read bytes after the
772 * HTTP header already (because the client sent
773 * more than the HTTP header of the request before
774 * we sent the upgrade response),
775 * these are the extra bytes already read from @a sock
776 * by MHD. The application should treat these as if
777 * it had read them from @a sock.
778 * @param extra_in_size number of bytes in @a extra_in
779 * @param sock socket to use for bi-directional communication
780 * with the client. For HTTPS, this may not be a socket
781 * that is directly connected to the client and thus certain
782 * operations (TCP-specific setsockopt(), getsockopt(), etc.)
783 * may not work as expected (as the socket could be from a
784 * socketpair() or a TCP-loopback). The application is expected
785 * to perform read()/recv() and write()/send() calls on the socket.
786 * The application may also call shutdown(), but must not call
787 * close() directly.
788 * @param urh argument for #MHD_upgrade_action()s on this @a connection.
789 * Applications must eventually use this callback to (indirectly)
790 * perform the close() action on the @a sock.
791 */
792static void
793upgrade_cb (void *cls,
794 struct MHD_Connection *connection,
795 void *con_cls,
796 const char *extra_in,
797 size_t extra_in_size,
798 MHD_socket sock,
799 struct MHD_UpgradeResponseHandle *urh)
800{
801 (void) cls;
802 (void) connection;
803 (void) con_cls;
804 (void) extra_in; /* Unused. Silent compiler warning. */
805
806 usock = wr_create_from_plain_sckt (sock);
807 if (0 != extra_in_size)
808 abort ();
809 if (0 != pthread_create (&pt,
810 NULL,
811 &run_usock,
812 urh))
813 abort ();
814}
815
816
817/**
818 * A client has requested the given url using the given method
819 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
820 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
821 * must call MHD callbacks to provide content to give back to the
822 * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
823 * #MHD_HTTP_NOT_FOUND, etc.).
824 *
825 * @param cls argument given together with the function
826 * pointer when the handler was registered with MHD
827 * @param url the requested url
828 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
829 * #MHD_HTTP_METHOD_PUT, etc.)
830 * @param version the HTTP version string (i.e.
831 * #MHD_HTTP_VERSION_1_1)
832 * @param upload_data the data being uploaded (excluding HEADERS,
833 * for a POST that fits into memory and that is encoded
834 * with a supported encoding, the POST data will NOT be
835 * given in upload_data and is instead available as
836 * part of #MHD_get_connection_values; very large POST
837 * data *will* be made available incrementally in
838 * @a upload_data)
839 * @param upload_data_size set initially to the size of the
840 * @a upload_data provided; the method must update this
841 * value to the number of bytes NOT processed;
842 * @param con_cls pointer that the callback can set to some
843 * address and that will be preserved by MHD for future
844 * calls for this request; since the access handler may
845 * be called many times (i.e., for a PUT/POST operation
846 * with plenty of upload data) this allows the application
847 * to easily associate some request-specific state.
848 * If necessary, this state can be cleaned up in the
849 * global #MHD_RequestCompletedCallback (which
850 * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
851 * Initially, `*con_cls` will be NULL.
852 * @return #MHD_YES if the connection was handled successfully,
853 * #MHD_NO if the socket must be closed due to a serios
854 * error while handling the request
855 */
856static int
857ahc_upgrade (void *cls,
858 struct MHD_Connection *connection,
859 const char *url,
860 const char *method,
861 const char *version,
862 const char *upload_data,
863 size_t *upload_data_size,
864 void **con_cls)
865{
866 struct MHD_Response *resp;
867 int ret;
868 (void) cls;
869 (void) url;
870 (void) method; /* Unused. Silent compiler warning. */
871 (void) version;
872 (void) upload_data;
873 (void) upload_data_size; /* Unused. Silent compiler warning. */
874
875 if (NULL == *con_cls)
876 abort ();
877 if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
878 abort ();
879 resp = MHD_create_response_for_upgrade (&upgrade_cb,
880 NULL);
881 MHD_add_response_header (resp,
882 MHD_HTTP_HEADER_UPGRADE,
883 "Hello World Protocol");
884 ret = MHD_queue_response (connection,
885 MHD_HTTP_SWITCHING_PROTOCOLS,
886 resp);
887 MHD_destroy_response (resp);
888 return ret;
889}
890
891
892/**
893 * Run the MHD external event loop using select.
894 *
895 * @param daemon daemon to run it for
896 */
897static void
898run_mhd_select_loop (struct MHD_Daemon *daemon)
899{
900 fd_set rs;
901 fd_set ws;
902 fd_set es;
903 MHD_socket max_fd;
904 MHD_UNSIGNED_LONG_LONG to;
905 struct timeval tv;
906 char drain[128];
907
908 if (0 != pipe (kicker))
909 abort ();
910 while (! done)
911 {
912 FD_ZERO (&rs);
913 FD_ZERO (&ws);
914 FD_ZERO (&es);
915 max_fd = -1;
916 to = 1000;
917
918 FD_SET (kicker[0], &rs);
919 if (MHD_YES !=
920 MHD_get_fdset (daemon,
921 &rs,
922 &ws,
923 &es,
924 &max_fd))
925 abort ();
926 (void) MHD_get_timeout (daemon,
927 &to);
928 if (1000 < to)
929 to = 1000;
930 tv.tv_sec = to / 1000;
931 tv.tv_usec = 1000 * (to % 1000);
932 if (0 > MHD_SYS_select_ (max_fd + 1,
933 &rs,
934 &ws,
935 &es,
936 &tv))
937 abort ();
938 if (FD_ISSET (kicker[0], &rs))
939 (void) read (kicker[0], drain, sizeof (drain));
940 MHD_run_from_select (daemon,
941 &rs,
942 &ws,
943 &es);
944 }
945 close (kicker[0]);
946 close (kicker[1]);
947 kicker[0] = -1;
948 kicker[1] = -1;
949}
950
951#ifdef HAVE_POLL
952
953/**
954 * Run the MHD external event loop using select.
955 *
956 * @param daemon daemon to run it for
957 */
958static void
959run_mhd_poll_loop (struct MHD_Daemon *daemon)
960{
961 (void)daemon; /* Unused. Silent compiler warning. */
962 abort (); /* currently not implementable with existing MHD API */
963}
964#endif /* HAVE_POLL */
965
966
967#ifdef EPOLL_SUPPORT
968/**
969 * Run the MHD external event loop using select.
970 *
971 * @param daemon daemon to run it for
972 */
973static void
974run_mhd_epoll_loop (struct MHD_Daemon *daemon)
975{
976 const union MHD_DaemonInfo *di;
977 MHD_socket ep;
978 fd_set rs;
979 MHD_UNSIGNED_LONG_LONG to;
980 struct timeval tv;
981 int ret;
982 char drain[128];
983
984 di = MHD_get_daemon_info (daemon,
985 MHD_DAEMON_INFO_EPOLL_FD);
986 ep = di->listen_fd;
987 if (0 != pipe (kicker))
988 abort ();
989 while (! done)
990 {
991 FD_ZERO (&rs);
992 to = 1000;
993 FD_SET (kicker[0], &rs);
994 FD_SET (ep, &rs);
995 (void) MHD_get_timeout (daemon,
996 &to);
997 if (1000 < to)
998 to = 1000;
999 tv.tv_sec = to / 1000;
1000 tv.tv_usec = 1000 * (to % 1000);
1001 ret = select (ep + 1,
1002 &rs,
1003 NULL,
1004 NULL,
1005 &tv);
1006 if ( (-1 == ret) &&
1007 (EAGAIN != errno) &&
1008 (EINTR != errno) )
1009 abort ();
1010 if (FD_ISSET (kicker[0], &rs))
1011 (void) read (kicker[0], drain, sizeof (drain));
1012 MHD_run (daemon);
1013 }
1014 close (kicker[0]);
1015 close (kicker[1]);
1016 kicker[0] = -1;
1017 kicker[1] = -1;
1018}
1019#endif /* EPOLL_SUPPORT */
1020
1021/**
1022 * Run the MHD external event loop using select.
1023 *
1024 * @param daemon daemon to run it for
1025 */
1026static void
1027run_mhd_loop (struct MHD_Daemon *daemon,
1028 int flags)
1029{
1030 if (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL)))
1031 run_mhd_select_loop (daemon);
1032#ifdef HAVE_POLL
1033 else if (0 != (flags & MHD_USE_POLL))
1034 run_mhd_poll_loop (daemon);
1035#endif /* HAVE_POLL */
1036#if EPOLL_SUPPORT
1037 else if (0 != (flags & MHD_USE_EPOLL))
1038 run_mhd_epoll_loop (daemon);
1039#endif
1040 else
1041 abort ();
1042}
1043
1044
1045static bool test_tls;
1046
1047/**
1048 * Test upgrading a connection.
1049 *
1050 * @param flags which event loop style should be tested
1051 * @param pool size of the thread pool, 0 to disable
1052 */
1053static int
1054test_upgrade (int flags,
1055 unsigned int pool)
1056{
1057 struct MHD_Daemon *d = NULL;
1058 struct wr_socket *sock;
1059 struct sockaddr_in sa;
1060 const union MHD_DaemonInfo *real_flags;
1061 const union MHD_DaemonInfo *dinfo;
1062#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1063 pid_t pid = -1;
1064#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
1065
1066 done = false;
1067
1068 if (! test_tls)
1069 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE,
1070 MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
1071 0 : 1090,
1072 NULL, NULL,
1073 &ahc_upgrade, NULL,
1074 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512,
1075 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
1076 MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
1077 MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
1078 MHD_OPTION_THREAD_POOL_SIZE, pool,
1079 MHD_OPTION_END);
1080#ifdef HTTPS_SUPPORT
1081 else
1082 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE | MHD_USE_TLS,
1083 MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
1084 0 : 1090,
1085 NULL, NULL,
1086 &ahc_upgrade, NULL,
1087 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512,
1088 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
1089 MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
1090 MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
1091 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
1092 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
1093 MHD_OPTION_THREAD_POOL_SIZE, pool,
1094 MHD_OPTION_END);
1095#endif /* HTTPS_SUPPORT */
1096 if (NULL == d)
1097 return 2;
1098 real_flags = MHD_get_daemon_info (d,
1099 MHD_DAEMON_INFO_FLAGS);
1100 if (NULL == real_flags)
1101 abort ();
1102 dinfo = MHD_get_daemon_info (d,
1103 MHD_DAEMON_INFO_BIND_PORT);
1104 if ( (NULL == dinfo) ||
1105 (0 == dinfo->port) )
1106 abort ();
1107 if (!test_tls || TLS_LIB_GNUTLS == use_tls_tool)
1108 {
1109 sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt ();
1110 if (NULL == sock)
1111 abort ();
1112 sa.sin_family = AF_INET;
1113 sa.sin_port = htons (dinfo->port);
1114 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1115 if (0 != wr_connect (sock,
1116 (struct sockaddr *) &sa,
1117 sizeof (sa)))
1118 abort ();
1119 }
1120 else
1121 {
1122#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1123 MHD_socket tls_fork_sock;
1124 uint16_t port;
1125
1126 /* make address sanitizer happy */
1127 memcpy (&port,
1128 dinfo /* ->port */,
1129 sizeof (port));
1130 if (-1 == (pid = gnutlscli_connect (&tls_fork_sock,
1131 port)))
1132 {
1133 MHD_stop_daemon (d);
1134 return 4;
1135 }
1136
1137 sock = wr_create_from_plain_sckt (tls_fork_sock);
1138 if (NULL == sock)
1139 abort ();
1140#else /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
1141 abort ();
1142#endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
1143 }
1144
1145 if (0 != pthread_create (&pt_client,
1146 NULL,
1147 &run_usock_client,
1148 sock))
1149 abort ();
1150 if (0 == (flags & MHD_USE_INTERNAL_POLLING_THREAD) )
1151 {
1152 enum MHD_FLAG flags;
1153
1154 /* make address sanitizer happy */
1155 memcpy (&flags,
1156 real_flags /* ->flags */,
1157 sizeof (flags));
1158 run_mhd_loop (d, flags);
1159 }
1160 pthread_join (pt_client,
1161 NULL);
1162 pthread_join (pt,
1163 NULL);
1164#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
1165 if (test_tls && TLS_LIB_GNUTLS != use_tls_tool)
1166 waitpid (pid, NULL, 0);
1167#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
1168 MHD_stop_daemon (d);
1169 return 0;
1170}
1171
1172
1173int
1174main (int argc,
1175 char *const *argv)
1176{
1177 int error_count = 0;
1178 int res;
1179
1180 use_tls_tool = TLS_CLI_NO_TOOL;
1181 test_tls = has_in_name(argv[0], "_tls");
1182
1183 verbose = 1;
1184 if (has_param(argc, argv, "-q") ||
1185 has_param(argc, argv, "--quiet"))
1186 verbose = 0;
1187
1188 if (test_tls)
1189 {
1190#ifdef HTTPS_SUPPORT
1191 if (has_param(argc, argv, "--use-gnutls-cli"))
1192 use_tls_tool = TLS_CLI_GNUTLS;
1193 else if (has_param(argc, argv, "--use-openssl"))
1194 use_tls_tool = TLS_CLI_OPENSSL;
1195 else if (has_param(argc, argv, "--use-gnutls-lib"))
1196 use_tls_tool = TLS_LIB_GNUTLS;
1197#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
1198 else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null"))
1199 use_tls_tool = TLS_CLI_GNUTLS;
1200 else if (0 == system ("openssl version 1> /dev/null 2> /dev/null"))
1201 use_tls_tool = TLS_CLI_OPENSSL;
1202#endif /* HAVE_FORK && HAVE_WAITPID */
1203 else
1204 use_tls_tool = TLS_LIB_GNUTLS; /* Should be available as MHD use it. */
1205 if (verbose)
1206 {
1207 switch (use_tls_tool)
1208 {
1209 case TLS_CLI_GNUTLS:
1210 printf ("GnuTLS-CLI will be used for testing.\n");
1211 break;
1212 case TLS_CLI_OPENSSL:
1213 printf ("Command line version of OpenSSL will be used for testing.\n");
1214 break;
1215 case TLS_LIB_GNUTLS:
1216 printf ("GnuTLS library will be used for testing.\n");
1217 break;
1218 default:
1219 abort ();
1220 }
1221 }
1222 if ( (TLS_LIB_GNUTLS == use_tls_tool) &&
1223 (GNUTLS_E_SUCCESS != gnutls_global_init()) )
1224 abort ();
1225
1226#else /* ! HTTPS_SUPPORT */
1227 fprintf (stderr, "HTTPS support was disabled by configure.\n");
1228 return 77;
1229#endif /* ! HTTPS_SUPPORT */
1230 }
1231
1232 /* run tests */
1233 if (verbose)
1234 printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n",
1235 test_tls ? "TLS" : "plain");
1236 /* try external select */
1237 res = test_upgrade (0,
1238 0);
1239 error_count += res;
1240 if (res)
1241 fprintf (stderr,
1242 "FAILED: Upgrade with external select, return code %d.\n",
1243 res);
1244 else if (verbose)
1245 printf ("PASSED: Upgrade with external select.\n");
1246
1247 /* Try external auto */
1248 res = test_upgrade (MHD_USE_AUTO,
1249 0);
1250 error_count += res;
1251 if (res)
1252 fprintf (stderr,
1253 "FAILED: Upgrade with external 'auto', return code %d.\n",
1254 res);
1255 else if (verbose)
1256 printf ("PASSED: Upgrade with external 'auto'.\n");
1257
1258#ifdef EPOLL_SUPPORT
1259 res = test_upgrade (MHD_USE_EPOLL,
1260 0);
1261 error_count += res;
1262 if (res)
1263 fprintf (stderr,
1264 "FAILED: Upgrade with external select with EPOLL, return code %d.\n",
1265 res);
1266 else if (verbose)
1267 printf ("PASSED: Upgrade with external select with EPOLL.\n");
1268#endif
1269
1270 /* Test thread-per-connection */
1271 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
1272 0);
1273 error_count += res;
1274 if (res)
1275 fprintf (stderr,
1276 "FAILED: Upgrade with thread per connection, return code %d.\n",
1277 res);
1278 else if (verbose)
1279 printf ("PASSED: Upgrade with thread per connection.\n");
1280
1281 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
1282 0);
1283 error_count += res;
1284 if (res)
1285 fprintf (stderr,
1286 "FAILED: Upgrade with thread per connection and 'auto', return code %d.\n",
1287 res);
1288 else if (verbose)
1289 printf ("PASSED: Upgrade with thread per connection and 'auto'.\n");
1290#ifdef HAVE_POLL
1291 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
1292 0);
1293 error_count += res;
1294 if (res)
1295 fprintf (stderr,
1296 "FAILED: Upgrade with thread per connection and poll, return code %d.\n",
1297 res);
1298 else if (verbose)
1299 printf ("PASSED: Upgrade with thread per connection and poll.\n");
1300#endif /* HAVE_POLL */
1301
1302 /* Test different event loops, with and without thread pool */
1303 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
1304 0);
1305 error_count += res;
1306 if (res)
1307 fprintf (stderr,
1308 "FAILED: Upgrade with internal select, return code %d.\n",
1309 res);
1310 else if (verbose)
1311 printf ("PASSED: Upgrade with internal select.\n");
1312 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
1313 2);
1314 error_count += res;
1315 if (res)
1316 fprintf (stderr,
1317 "FAILED: Upgrade with internal select with thread pool, return code %d.\n",
1318 res);
1319 else if (verbose)
1320 printf ("PASSED: Upgrade with internal select with thread pool.\n");
1321 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
1322 0);
1323 error_count += res;
1324 if (res)
1325 fprintf (stderr,
1326 "FAILED: Upgrade with internal 'auto' return code %d.\n",
1327 res);
1328 else if (verbose)
1329 printf ("PASSED: Upgrade with internal 'auto'.\n");
1330 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
1331 2);
1332 error_count += res;
1333 if (res)
1334 fprintf (stderr,
1335 "FAILED: Upgrade with internal 'auto' with thread pool, return code %d.\n",
1336 res);
1337 else if (verbose)
1338 printf ("PASSED: Upgrade with internal 'auto' with thread pool.\n");
1339#ifdef HAVE_POLL
1340 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
1341 0);
1342 error_count += res;
1343 if (res)
1344 fprintf (stderr,
1345 "FAILED: Upgrade with internal poll, return code %d.\n",
1346 res);
1347 else if (verbose)
1348 printf ("PASSED: Upgrade with internal poll.\n");
1349 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
1350 2);
1351 if (res)
1352 fprintf (stderr,
1353 "FAILED: Upgrade with internal poll with thread pool, return code %d.\n",
1354 res);
1355 else if (verbose)
1356 printf ("PASSED: Upgrade with internal poll with thread pool.\n");
1357#endif
1358#ifdef EPOLL_SUPPORT
1359 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
1360 0);
1361 if (res)
1362 fprintf (stderr,
1363 "FAILED: Upgrade with internal epoll, return code %d.\n",
1364 res);
1365 else if (verbose)
1366 printf ("PASSED: Upgrade with internal epoll.\n");
1367 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
1368 2);
1369 if (res)
1370 fprintf (stderr,
1371 "FAILED: Upgrade with internal epoll, return code %d.\n",
1372 res);
1373 else if (verbose)
1374 printf ("PASSED: Upgrade with internal epoll.\n");
1375#endif
1376 /* report result */
1377 if (0 != error_count)
1378 fprintf (stderr,
1379 "Error (code: %u)\n",
1380 error_count);
1381#ifdef HTTPS_SUPPORT
1382 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool))
1383 gnutls_global_deinit();
1384#endif /* HTTPS_SUPPORT */
1385 return error_count != 0; /* 0 == pass */
1386}