aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-28 23:09:44 +0000
committerChristian Grothoff <christian@grothoff.org>2016-08-28 23:09:44 +0000
commitb6ac5b9f8e1a668a1a9026cfe7004dbdab4264da (patch)
tree316e16aabd97175dac09e06f38e05ec7990800a8
parentaf90b3cd5169fbc49d376f4b96df1f231a577fdc (diff)
downloadlibmicrohttpd-b6ac5b9f8e1a668a1a9026cfe7004dbdab4264da.tar.gz
libmicrohttpd-b6ac5b9f8e1a668a1a9026cfe7004dbdab4264da.zip
-theoretically finishing epoll() + HTTPS-based connection upgrade logic
-rw-r--r--doc/libmicrohttpd.texi13
-rw-r--r--src/include/microhttpd.h19
-rw-r--r--src/microhttpd/connection.c19
-rw-r--r--src/microhttpd/daemon.c392
-rw-r--r--src/microhttpd/internal.h72
-rw-r--r--src/microhttpd/response.c144
6 files changed, 527 insertions, 132 deletions
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
index deee825e..2adfd51d 100644
--- a/doc/libmicrohttpd.texi
+++ b/doc/libmicrohttpd.texi
@@ -587,6 +587,19 @@ Enable TCP_FASTOPEN on the listen socket. TCP_FASTOPEN is currently
587supported on Linux >= 3.6. On other systems using this option with 587supported on Linux >= 3.6. On other systems using this option with
588cause @code{MHD_start_daemon} to fail. 588cause @code{MHD_start_daemon} to fail.
589 589
590@item MHD_USE_TLS_EPOLL_UPGRADE
591@cindex epoll
592@cindex upgrade
593@cindex https
594@cindex tls
595This option must be set if you want to use @code{epoll()} in
596combination with a server offering TLS and then upgrade connections
597(via ``101 Switching Protocols'' responses). This requires MHD to
598open up and process an extra socket, and hence we require this
599special flag in case this is really needed. Note that using
600this option automatically implies @code{MHD_USE_EPOLL},
601@code{MHD_USE_TLS} and @code{MHD_USE_SUSPEND_RESUME}.
602
590@end table 603@end table
591@end deftp 604@end deftp
592 605
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 46a82625..7347447c 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -538,11 +538,16 @@ enum MHD_FLAG
538 MHD_USE_DEBUG = 1, 538 MHD_USE_DEBUG = 1,
539 539
540 /** 540 /**
541 * Run in HTTPS mode. 541 * Run in HTTPS mode. Same as #MHD_USE_TLS, just using the historic name.
542 */ 542 */
543 MHD_USE_SSL = 2, 543 MHD_USE_SSL = 2,
544 544
545 /** 545 /**
546 * Run in HTTPS mode. The modern protocol is called TLS.
547 */
548 MHD_USE_TLS = 2,
549
550 /**
546 * Run using one thread per connection. 551 * Run using one thread per connection.
547 */ 552 */
548 MHD_USE_THREAD_PER_CONNECTION = 4, 553 MHD_USE_THREAD_PER_CONNECTION = 4,
@@ -672,7 +677,17 @@ enum MHD_FLAG
672 * kernel >= 3.6. On other systems, using this option cases #MHD_start_daemon 677 * kernel >= 3.6. On other systems, using this option cases #MHD_start_daemon
673 * to fail. 678 * to fail.
674 */ 679 */
675 MHD_USE_TCP_FASTOPEN = 16384 680 MHD_USE_TCP_FASTOPEN = 16384,
681
682 /**
683 * You need to set this option if you want to use epoll() in
684 * combination with HTTPS connections and switching protocols via
685 * connection upgrades (via #MHD_create_response_for_upgrade()).
686 * This flag is required as under these circumstances we need to
687 * open up an extra file descriptor, which we do not want to do
688 * unless necessary.
689 */
690 MHD_USE_TLS_EPOLL_UPGRADE = 32768 | MHD_USE_SUSPEND_RESUME | MHD_USE_EPOLL | MHD_USE_TLS
676 691
677}; 692};
678 693
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 54556167..e3880e8a 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -3158,6 +3158,8 @@ MHD_queue_response (struct MHD_Connection *connection,
3158 unsigned int status_code, 3158 unsigned int status_code,
3159 struct MHD_Response *response) 3159 struct MHD_Response *response)
3160{ 3160{
3161 struct MHD_Daemon *daemon = connection->daemon;
3162
3161 if ( (NULL == connection) || 3163 if ( (NULL == connection) ||
3162 (NULL == response) || 3164 (NULL == response) ||
3163 (NULL != connection->response) || 3165 (NULL != connection->response) ||
@@ -3168,20 +3170,31 @@ MHD_queue_response (struct MHD_Connection *connection,
3168 (NULL != response->upgrade_handler) ) 3170 (NULL != response->upgrade_handler) )
3169 { 3171 {
3170#ifdef HAVE_MESSAGES 3172#ifdef HAVE_MESSAGES
3171 MHD_DLOG (connection->daemon, 3173 MHD_DLOG (daemon,
3172 "Application used invalid status code for 'upgrade' response!\n"); 3174 "Application used invalid status code for 'upgrade' response!\n");
3173#endif 3175#endif
3174 return MHD_NO; 3176 return MHD_NO;
3175 } 3177 }
3176 if ( (NULL != response->upgrade_handler) && 3178 if ( (NULL != response->upgrade_handler) &&
3177 (0 == (connection->daemon->options & MHD_USE_SUSPEND_RESUME)) ) 3179 (0 == (daemon->options & MHD_USE_SUSPEND_RESUME)) )
3178 { 3180 {
3179#ifdef HAVE_MESSAGES 3181#ifdef HAVE_MESSAGES
3180 MHD_DLOG (connection->daemon, 3182 MHD_DLOG (daemon,
3181 "Application attempted 'upgrade' without setting MHD_USE_SUSPEND_RESUME!\n"); 3183 "Application attempted 'upgrade' without setting MHD_USE_SUSPEND_RESUME!\n");
3182#endif 3184#endif
3183 return MHD_NO; 3185 return MHD_NO;
3184 } 3186 }
3187 if ( (NULL != response->upgrade_handler) &&
3188 (0 != (MHD_USE_EPOLL & daemon->options)) &&
3189 (0 != (MHD_USE_TLS & daemon->options)) &&
3190 (MHD_USE_TLS_EPOLL_UPGRADE != (MHD_USE_TLS_EPOLL_UPGRADE & daemon->options)) )
3191 {
3192#ifdef HAVE_MESSAGES
3193 MHD_DLOG (daemon,
3194 "Application attempted 'upgrade' HTTPS connection in epoll mode without setting MHD_USE_HTTPS_EPOLL_UPGRADE!\n");
3195#endif
3196 return MHD_NO;
3197 }
3185 MHD_increment_response_rc (response); 3198 MHD_increment_response_rc (response);
3186 connection->response = response; 3199 connection->response = response;
3187 connection->responseCode = status_code; 3200 connection->responseCode = status_code;
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index a25fe358..2fb87ed4 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -626,11 +626,15 @@ MHD_get_fdset (struct MHD_Daemon *daemon,
626 fd_set *except_fd_set, 626 fd_set *except_fd_set,
627 MHD_socket *max_fd) 627 MHD_socket *max_fd)
628{ 628{
629 return MHD_get_fdset2(daemon, read_fd_set, 629 return MHD_get_fdset2 (daemon,
630 write_fd_set, except_fd_set, 630 read_fd_set,
631 max_fd, _MHD_SYS_DEFAULT_FD_SETSIZE); 631 write_fd_set,
632 except_fd_set,
633 max_fd,
634 _MHD_SYS_DEFAULT_FD_SETSIZE);
632} 635}
633 636
637
634/** 638/**
635 * Obtain the `select()` sets for this daemon. 639 * Obtain the `select()` sets for this daemon.
636 * Daemon's FDs will be added to fd_sets. To get only 640 * Daemon's FDs will be added to fd_sets. To get only
@@ -729,25 +733,25 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon,
729 } 733 }
730 for (urh = daemon->urh_head; NULL != urh; urh = urh->next) 734 for (urh = daemon->urh_head; NULL != urh; urh = urh->next)
731 { 735 {
732 if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) && 736 if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) &&
733 (! MHD_add_to_fd_set_ (urh->mhd_socket, 737 (! MHD_add_to_fd_set_ (urh->mhd.socket,
734 read_fd_set, 738 read_fd_set,
735 max_fd, 739 max_fd,
736 fd_setsize)) ) 740 fd_setsize)) )
737 result = MHD_NO; 741 result = MHD_NO;
738 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) && 742 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) &&
739 (! MHD_add_to_fd_set_ (urh->mhd_socket, 743 (! MHD_add_to_fd_set_ (urh->mhd.socket,
740 write_fd_set, 744 write_fd_set,
741 max_fd, 745 max_fd,
742 fd_setsize)) ) 746 fd_setsize)) )
743 result = MHD_NO; 747 result = MHD_NO;
744 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) && 748 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) &&
745 (! MHD_add_to_fd_set_ (urh->connection->socket_fd, 749 (! MHD_add_to_fd_set_ (urh->connection->socket_fd,
746 read_fd_set, 750 read_fd_set,
747 max_fd, 751 max_fd,
748 fd_setsize)) ) 752 fd_setsize)) )
749 result = MHD_NO; 753 result = MHD_NO;
750 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) && 754 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) &&
751 (! MHD_add_to_fd_set_ (urh->connection->socket_fd, 755 (! MHD_add_to_fd_set_ (urh->connection->socket_fd,
752 write_fd_set, 756 write_fd_set,
753 max_fd, 757 max_fd,
@@ -2175,7 +2179,7 @@ static void
2175process_urh (struct MHD_UpgradeResponseHandle *urh) 2179process_urh (struct MHD_UpgradeResponseHandle *urh)
2176{ 2180{
2177 /* handle reading from TLS client and writing to application */ 2181 /* handle reading from TLS client and writing to application */
2178 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) && 2182 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) &&
2179 (urh->in_buffer_off < urh->in_buffer_size) ) 2183 (urh->in_buffer_off < urh->in_buffer_size) )
2180 { 2184 {
2181 ssize_t res; 2185 ssize_t res;
@@ -2186,25 +2190,25 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2186 if ( (GNUTLS_E_AGAIN == res) || 2190 if ( (GNUTLS_E_AGAIN == res) ||
2187 (GNUTLS_E_INTERRUPTED == res) ) 2191 (GNUTLS_E_INTERRUPTED == res) )
2188 { 2192 {
2189 urh->celi_client &= ~MHD_EPOLL_STATE_READ_READY; 2193 urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY;
2190 } 2194 }
2191 else if (res > 0) 2195 else if (res > 0)
2192 { 2196 {
2193 urh->in_buffer_off += res; 2197 urh->in_buffer_off += res;
2194 } 2198 }
2195 } 2199 }
2196 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) && 2200 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) &&
2197 (urh->in_buffer_off > 0) ) 2201 (urh->in_buffer_off > 0) )
2198 { 2202 {
2199 size_t res; 2203 size_t res;
2200 2204
2201 res = write (urh->mhd_socket, 2205 res = write (urh->mhd.socket,
2202 urh->in_buffer, 2206 urh->in_buffer,
2203 urh->in_buffer_off); 2207 urh->in_buffer_off);
2204 if (-1 == res) 2208 if (-1 == res)
2205 { 2209 {
2206 /* FIXME: differenciate by errno? */ 2210 /* FIXME: differenciate by errno? */
2207 urh->celi_mhd &= ~MHD_EPOLL_STATE_WRITE_READY; 2211 urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY;
2208 } 2212 }
2209 else 2213 else
2210 { 2214 {
@@ -2223,25 +2227,25 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2223 } 2227 }
2224 2228
2225 /* handle reading from application and writing to HTTPS client */ 2229 /* handle reading from application and writing to HTTPS client */
2226 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) && 2230 if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) &&
2227 (urh->out_buffer_off < urh->out_buffer_size) ) 2231 (urh->out_buffer_off < urh->out_buffer_size) )
2228 { 2232 {
2229 size_t res; 2233 size_t res;
2230 2234
2231 res = read (urh->mhd_socket, 2235 res = read (urh->mhd.socket,
2232 &urh->out_buffer[urh->out_buffer_off], 2236 &urh->out_buffer[urh->out_buffer_off],
2233 urh->out_buffer_size - urh->out_buffer_off); 2237 urh->out_buffer_size - urh->out_buffer_off);
2234 if (-1 == res) 2238 if (-1 == res)
2235 { 2239 {
2236 /* FIXME: differenciate by errno? */ 2240 /* FIXME: differenciate by errno? */
2237 urh->celi_mhd &= ~MHD_EPOLL_STATE_READ_READY; 2241 urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY;
2238 } 2242 }
2239 else 2243 else
2240 { 2244 {
2241 urh->out_buffer_off += res; 2245 urh->out_buffer_off += res;
2242 } 2246 }
2243 } 2247 }
2244 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) && 2248 if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) &&
2245 (urh->out_buffer_off > 0) ) 2249 (urh->out_buffer_off > 0) )
2246 { 2250 {
2247 ssize_t res; 2251 ssize_t res;
@@ -2252,7 +2256,7 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
2252 if ( (GNUTLS_E_AGAIN == res) || 2256 if ( (GNUTLS_E_AGAIN == res) ||
2253 (GNUTLS_E_INTERRUPTED == res) ) 2257 (GNUTLS_E_INTERRUPTED == res) )
2254 { 2258 {
2255 urh->celi_client &= ~MHD_EPOLL_STATE_WRITE_READY; 2259 urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY;
2256 } 2260 }
2257 else if (res > 0) 2261 else if (res > 0)
2258 { 2262 {
@@ -2359,13 +2363,13 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
2359 { 2363 {
2360 /* update urh state based on select() output */ 2364 /* update urh state based on select() output */
2361 if (FD_ISSET (urh->connection->socket_fd, read_fd_set)) 2365 if (FD_ISSET (urh->connection->socket_fd, read_fd_set))
2362 urh->celi_client |= MHD_EPOLL_STATE_READ_READY; 2366 urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
2363 if (FD_ISSET (urh->connection->socket_fd, write_fd_set)) 2367 if (FD_ISSET (urh->connection->socket_fd, write_fd_set))
2364 urh->celi_client |= MHD_EPOLL_STATE_WRITE_READY; 2368 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
2365 if (FD_ISSET (urh->mhd_socket, read_fd_set)) 2369 if (FD_ISSET (urh->mhd.socket, read_fd_set))
2366 urh->celi_mhd |= MHD_EPOLL_STATE_READ_READY; 2370 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
2367 if (FD_ISSET (urh->mhd_socket, write_fd_set)) 2371 if (FD_ISSET (urh->mhd.socket, write_fd_set))
2368 urh->celi_mhd |= MHD_EPOLL_STATE_WRITE_READY; 2372 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
2369 /* call generic forwarding function for passing data */ 2373 /* call generic forwarding function for passing data */
2370 process_urh (urh); 2374 process_urh (urh);
2371 } 2375 }
@@ -2632,15 +2636,15 @@ MHD_poll_all (struct MHD_Daemon *daemon,
2632 for (urh = daemon->urh_head; NULL != urh; urh = urh->next) 2636 for (urh = daemon->urh_head; NULL != urh; urh = urh->next)
2633 { 2637 {
2634 p[poll_server+i].fd = urh->connection->socket_fd; 2638 p[poll_server+i].fd = urh->connection->socket_fd;
2635 if (0 == (MHD_EPOLL_STATE_READ_READY & urh->celi_client)) 2639 if (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi))
2636 p[poll_server+i].events |= POLLIN; 2640 p[poll_server+i].events |= POLLIN;
2637 if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->celi_client)) 2641 if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi))
2638 p[poll_server+i].events |= POLLOUT; 2642 p[poll_server+i].events |= POLLOUT;
2639 i++; 2643 i++;
2640 p[poll_server+i].fd = urh->mhd_socket; 2644 p[poll_server+i].fd = urh->mhd.socket;
2641 if (0 == (MHD_EPOLL_STATE_READ_READY & urh->celi_mhd)) 2645 if (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi))
2642 p[poll_server+i].events |= POLLIN; 2646 p[poll_server+i].events |= POLLIN;
2643 if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->celi_mhd)) 2647 if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi))
2644 p[poll_server+i].events |= POLLOUT; 2648 p[poll_server+i].events |= POLLOUT;
2645 i++; 2649 i++;
2646 } 2650 }
@@ -2701,11 +2705,11 @@ MHD_poll_all (struct MHD_Daemon *daemon,
2701 if (p[poll_server+i].fd != urh->connection->socket_fd) 2705 if (p[poll_server+i].fd != urh->connection->socket_fd)
2702 continue; /* fd mismatch, something else happened, retry later ... */ 2706 continue; /* fd mismatch, something else happened, retry later ... */
2703 if (0 != (p[poll_server+i].revents & POLLIN)) 2707 if (0 != (p[poll_server+i].revents & POLLIN))
2704 urh->celi_client |= MHD_EPOLL_STATE_READ_READY; 2708 urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
2705 if (0 != (p[poll_server+i].revents & POLLOUT)) 2709 if (0 != (p[poll_server+i].revents & POLLOUT))
2706 urh->celi_client |= MHD_EPOLL_STATE_WRITE_READY; 2710 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
2707 i++; 2711 i++;
2708 if (p[poll_server+i].fd != urh->mhd_socket) 2712 if (p[poll_server+i].fd != urh->mhd.socket)
2709 { 2713 {
2710 /* fd mismatch, something else happened, retry later ... */ 2714 /* fd mismatch, something else happened, retry later ... */
2711 /* may still be able to do something based on updates 2715 /* may still be able to do something based on updates
@@ -2714,9 +2718,9 @@ MHD_poll_all (struct MHD_Daemon *daemon,
2714 continue; 2718 continue;
2715 } 2719 }
2716 if (0 != (p[poll_server+i].revents & POLLIN)) 2720 if (0 != (p[poll_server+i].revents & POLLIN))
2717 urh->celi_mhd |= MHD_EPOLL_STATE_READ_READY; 2721 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
2718 if (0 != (p[poll_server+i].revents & POLLOUT)) 2722 if (0 != (p[poll_server+i].revents & POLLOUT))
2719 urh->celi_mhd |= MHD_EPOLL_STATE_WRITE_READY; 2723 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
2720 i++; 2724 i++;
2721 process_urh (urh); 2725 process_urh (urh);
2722 } 2726 }
@@ -2832,6 +2836,136 @@ MHD_poll (struct MHD_Daemon *daemon,
2832#define MAX_EVENTS 128 2836#define MAX_EVENTS 128
2833 2837
2834 2838
2839#if HTTPS_SUPPORT
2840
2841/**
2842 * Do epoll()-based processing for TLS connections that have been
2843 * upgraded. This requires a separate epoll() invocation as we
2844 * cannot use the `struct MHD_Connection` data structures for
2845 * the `union epoll_data` in this case.
2846 */
2847static int
2848run_epoll_for_upgrade (struct MHD_Daemon *daemon)
2849{
2850 struct epoll_event events[MAX_EVENTS];
2851 int num_events;
2852 unsigned int i;
2853
2854 num_events = MAX_EVENTS;
2855 while (MAX_EVENTS == num_events)
2856 {
2857 /* update event masks */
2858 num_events = epoll_wait (daemon->epoll_upgrade_fd,
2859 events,
2860 MAX_EVENTS,
2861 0);
2862 if (-1 == num_events)
2863 {
2864 const int err = MHD_socket_get_error_ ();
2865 if (MHD_SCKT_ERR_IS_EINTR_ (err))
2866 return MHD_YES;
2867#ifdef HAVE_MESSAGES
2868 MHD_DLOG (daemon,
2869 "Call to epoll_wait failed: %s\n",
2870 MHD_socket_strerr_ (err));
2871#endif
2872 return MHD_NO;
2873 }
2874 for (i=0;i<(unsigned int) num_events;i++)
2875 {
2876 struct UpgradeEpollHandle *ueh = events[i].data.ptr;
2877 struct MHD_UpgradeResponseHandle *urh = ueh->urh;
2878 struct epoll_event event;
2879 int fd;
2880
2881 /* Update our state based on what is ready according to epoll() */
2882 if (0 != (events[i].events & EPOLLIN))
2883 ueh->celi |= MHD_EPOLL_STATE_READ_READY;
2884 if (0 != (events[i].events & EPOLLOUT))
2885 ueh->celi |= MHD_EPOLL_STATE_WRITE_READY;
2886
2887 /* shuffle data based on buffers and FD readyness */
2888 process_urh (urh);
2889
2890 /* if we drained the IO buffer, re-add to epoll() to wait for more! */
2891 if (0 == (ueh->celi & MHD_EPOLL_STATE_READ_READY))
2892 {
2893 event.events = EPOLLIN;
2894 event.data.ptr = ueh;
2895 fd = (ueh == &urh->mhd) ? ueh->socket : urh->connection->socket_fd;
2896 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2897 EPOLL_CTL_ADD,
2898 fd,
2899 &event))
2900 {
2901 MHD_socket myfd;
2902
2903 /* Handle error by closing OUR socket; with some
2904 luck, this should tricker the application to fail
2905 to read, and then the application should close
2906 the connection completely. */
2907
2908 /* epoll documentation suggests that closing a FD
2909 automatically removes it from the epoll set;
2910 however, this is not true as if we fail to do
2911 manually remove it, we are still seeing an event
2912 for this fd in epoll, causing grief
2913 (use-after-free...) --- at least on my system. */
2914 myfd = urh->mhd.socket;
2915 if ( (fd != myfd) &&
2916 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2917 EPOLL_CTL_DEL,
2918 urh->mhd.socket,
2919 NULL)) )
2920 MHD_PANIC ("Failed to remove FD from epoll set\n");
2921 urh->mhd.socket = MHD_INVALID_SOCKET;
2922 MHD_socket_close_ (myfd);
2923 continue;
2924 }
2925 }
2926 if (0 == (ueh->celi & MHD_EPOLL_STATE_WRITE_READY))
2927 {
2928 event.events = EPOLLOUT;
2929 event.data.ptr = ueh;
2930 fd = (ueh == &ueh->urh->mhd) ? ueh->socket : ueh->urh->connection->socket_fd;
2931 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2932 EPOLL_CTL_ADD,
2933 fd,
2934 &event))
2935 {
2936 MHD_socket myfd;
2937
2938 /* Handle error by closing OUR socket; with some
2939 luck, this should tricker the application to fail
2940 to read, and then the application should close
2941 the connection completely. */
2942
2943 /* epoll documentation suggests that closing a FD
2944 automatically removes it from the epoll set;
2945 however, this is not true as if we fail to do
2946 manually remove it, we are still seeing an event
2947 for this fd in epoll, causing grief
2948 (use-after-free...) --- at least on my system. */
2949 myfd = urh->mhd.socket;
2950 if ( (fd != myfd) &&
2951 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
2952 EPOLL_CTL_DEL,
2953 urh->mhd.socket,
2954 NULL)) )
2955 MHD_PANIC ("Failed to remove FD from epoll set\n");
2956
2957 urh->mhd.socket = MHD_INVALID_SOCKET;
2958 MHD_socket_close_ (myfd);
2959 continue;
2960 }
2961 }
2962 }
2963 }
2964 return MHD_YES;
2965}
2966#endif
2967
2968
2835/** 2969/**
2836 * Do epoll()-based processing (this function is allowed to 2970 * Do epoll()-based processing (this function is allowed to
2837 * block if @a may_block is set to #MHD_YES). 2971 * block if @a may_block is set to #MHD_YES).
@@ -2844,6 +2978,9 @@ static int
2844MHD_epoll (struct MHD_Daemon *daemon, 2978MHD_epoll (struct MHD_Daemon *daemon,
2845 int may_block) 2979 int may_block)
2846{ 2980{
2981#if HTTPS_SUPPORT
2982 static const char *upgrade_marker = "upgrade_ptr";
2983#endif
2847 struct MHD_Connection *pos; 2984 struct MHD_Connection *pos;
2848 struct MHD_Connection *next; 2985 struct MHD_Connection *next;
2849 struct epoll_event events[MAX_EVENTS]; 2986 struct epoll_event events[MAX_EVENTS];
@@ -2879,6 +3016,27 @@ MHD_epoll (struct MHD_Daemon *daemon,
2879 } 3016 }
2880 daemon->listen_socket_in_epoll = MHD_YES; 3017 daemon->listen_socket_in_epoll = MHD_YES;
2881 } 3018 }
3019#if HTTPS_SUPPORT
3020 if ( (MHD_NO == daemon->upgrade_fd_in_epoll) &&
3021 (MHD_INVALID_SOCKET != daemon->epoll_upgrade_fd) )
3022 {
3023 event.events = EPOLLIN | EPOLLOUT;
3024 event.data.ptr = (void *) upgrade_marker;
3025 if (0 != epoll_ctl (daemon->epoll_fd,
3026 EPOLL_CTL_ADD,
3027 daemon->epoll_upgrade_fd,
3028 &event))
3029 {
3030#ifdef HAVE_MESSAGES
3031 MHD_DLOG (daemon,
3032 "Call to epoll_ctl failed: %s\n",
3033 MHD_socket_last_strerr_ ());
3034#endif
3035 return MHD_NO;
3036 }
3037 daemon->upgrade_fd_in_epoll = MHD_YES;
3038 }
3039#endif
2882 if ( ( (MHD_YES == daemon->listen_socket_in_epoll) && 3040 if ( ( (MHD_YES == daemon->listen_socket_in_epoll) &&
2883 (daemon->connections == daemon->connection_limit) ) || 3041 (daemon->connections == daemon->connection_limit) ) ||
2884 (MHD_YES == daemon->at_limit) ) 3042 (MHD_YES == daemon->at_limit) )
@@ -2917,7 +3075,9 @@ MHD_epoll (struct MHD_Daemon *daemon,
2917 { 3075 {
2918 /* update event masks */ 3076 /* update event masks */
2919 num_events = epoll_wait (daemon->epoll_fd, 3077 num_events = epoll_wait (daemon->epoll_fd,
2920 events, MAX_EVENTS, timeout_ms); 3078 events,
3079 MAX_EVENTS,
3080 timeout_ms);
2921 if (-1 == num_events) 3081 if (-1 == num_events)
2922 { 3082 {
2923 const int err = MHD_socket_get_error_ (); 3083 const int err = MHD_socket_get_error_ ();
@@ -2932,8 +3092,25 @@ MHD_epoll (struct MHD_Daemon *daemon,
2932 } 3092 }
2933 for (i=0;i<(unsigned int) num_events;i++) 3093 for (i=0;i<(unsigned int) num_events;i++)
2934 { 3094 {
3095 /* First, check for the values of `ptr` that would indicate
3096 that this event is not about a normal connection. */
2935 if (NULL == events[i].data.ptr) 3097 if (NULL == events[i].data.ptr)
2936 continue; /* shutdown signal! */ 3098 continue; /* shutdown signal! */
3099#if HTTPS_SUPPORT
3100 if (upgrade_marker == events[i].data.ptr)
3101 {
3102 /* activity on an upgraded connection, we process
3103 those in a separate epoll() */
3104 daemon->upgrade_fd_in_epoll = MHD_NO;
3105 run_epoll_for_upgrade (daemon);
3106 continue;
3107 }
3108#endif
3109 /* UGH: we're storing pointers and fds in the same union
3110 here; incredibly ugly and somewhat risky, even though a
3111 pointer with the same numeric value as the wpipe[0] can
3112 be expected to be rare... FIXME (a construction similar
3113 to what we did with the `upgrade_marker` should do) */
2937 if ( (MHD_INVALID_PIPE_ != daemon->wpipe[0]) && 3114 if ( (MHD_INVALID_PIPE_ != daemon->wpipe[0]) &&
2938 (daemon->wpipe[0] == events[i].data.fd) ) 3115 (daemon->wpipe[0] == events[i].data.fd) )
2939 { 3116 {
@@ -2942,39 +3119,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
2942 MHD_pipe_drain_ (daemon->wpipe[0]); 3119 MHD_pipe_drain_ (daemon->wpipe[0]);
2943 continue; 3120 continue;
2944 } 3121 }
2945 if (daemon != events[i].data.ptr) 3122 if (daemon == events[i].data.ptr)
2946 {
2947 /* this is an event relating to a 'normal' connection,
2948 remember the event and if appropriate mark the
2949 connection as 'eready'. */
2950 pos = events[i].data.ptr;
2951 if (0 != (events[i].events & EPOLLIN))
2952 {
2953 pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
2954 if ( ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
2955 (pos->read_buffer_size > pos->read_buffer_offset) ) &&
2956 (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
2957 {
2958 EDLL_insert (daemon->eready_head,
2959 daemon->eready_tail,
2960 pos);
2961 pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
2962 }
2963 }
2964 if (0 != (events[i].events & EPOLLOUT))
2965 {
2966 pos->epoll_state |= MHD_EPOLL_STATE_WRITE_READY;
2967 if ( (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) &&
2968 (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
2969 {
2970 EDLL_insert (daemon->eready_head,
2971 daemon->eready_tail,
2972 pos);
2973 pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
2974 }
2975 }
2976 }
2977 else /* must be listen socket */
2978 { 3123 {
2979 /* run 'accept' until it fails or we are not allowed to take 3124 /* run 'accept' until it fails or we are not allowed to take
2980 on more connections */ 3125 on more connections */
@@ -2984,8 +3129,39 @@ MHD_epoll (struct MHD_Daemon *daemon,
2984 (series_length < 128) && 3129 (series_length < 128) &&
2985 (MHD_NO == daemon->at_limit) ) 3130 (MHD_NO == daemon->at_limit) )
2986 series_length++; 3131 series_length++;
3132 continue;
2987 } 3133 }
2988 } 3134 /* this is an event relating to a 'normal' connection,
3135 remember the event and if appropriate mark the
3136 connection as 'eready'. */
3137 pos = events[i].data.ptr;
3138 /* normal processing: update read/write data */
3139 if (0 != (events[i].events & EPOLLIN))
3140 {
3141 pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
3142 if ( ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
3143 (pos->read_buffer_size > pos->read_buffer_offset) ) &&
3144 (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
3145 {
3146 EDLL_insert (daemon->eready_head,
3147 daemon->eready_tail,
3148 pos);
3149 pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
3150 }
3151 }
3152 if (0 != (events[i].events & EPOLLOUT))
3153 {
3154 pos->epoll_state |= MHD_EPOLL_STATE_WRITE_READY;
3155 if ( (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) &&
3156 (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
3157 {
3158 EDLL_insert (daemon->eready_head,
3159 daemon->eready_tail,
3160 pos);
3161 pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
3162 }
3163 }
3164 }
2989 } 3165 }
2990 3166
2991 /* we handle resumes here because we may have ready connections 3167 /* we handle resumes here because we may have ready connections
@@ -3426,8 +3602,8 @@ parse_options_va (struct MHD_Daemon *daemon,
3426 if (gnutls_dh_params_init (&daemon->https_mem_dhparams) < 0) 3602 if (gnutls_dh_params_init (&daemon->https_mem_dhparams) < 0)
3427 { 3603 {
3428#ifdef HAVE_MESSAGES 3604#ifdef HAVE_MESSAGES
3429 MHD_DLOG(daemon, 3605 MHD_DLOG (daemon,
3430 "Error initializing DH parameters\n"); 3606 "Error initializing DH parameters\n");
3431#endif 3607#endif
3432 return MHD_NO; 3608 return MHD_NO;
3433 } 3609 }
@@ -3437,8 +3613,8 @@ parse_options_va (struct MHD_Daemon *daemon,
3437 GNUTLS_X509_FMT_PEM) < 0) 3613 GNUTLS_X509_FMT_PEM) < 0)
3438 { 3614 {
3439#ifdef HAVE_MESSAGES 3615#ifdef HAVE_MESSAGES
3440 MHD_DLOG(daemon, 3616 MHD_DLOG (daemon,
3441 "Bad Diffie-Hellman parameters format\n"); 3617 "Bad Diffie-Hellman parameters format\n");
3442#endif 3618#endif
3443 gnutls_dh_params_deinit (daemon->https_mem_dhparams); 3619 gnutls_dh_params_deinit (daemon->https_mem_dhparams);
3444 return MHD_NO; 3620 return MHD_NO;
@@ -3652,34 +3828,27 @@ parse_options_va (struct MHD_Daemon *daemon,
3652 3828
3653 3829
3654#ifdef EPOLL_SUPPORT 3830#ifdef EPOLL_SUPPORT
3655/**
3656 * Setup epoll() FD for the daemon and initialize it to listen
3657 * on the listen FD.
3658 *
3659 * @param daemon daemon to initialize for epoll()
3660 * @return #MHD_YES on success, #MHD_NO on failure
3661 */
3662static int 3831static int
3663setup_epoll_to_listen (struct MHD_Daemon *daemon) 3832setup_epoll_fd (struct MHD_Daemon *daemon)
3664{ 3833{
3665 struct epoll_event event; 3834 int fd;
3666 3835
3667#ifdef USE_EPOLL_CREATE1 3836#ifdef USE_EPOLL_CREATE1
3668 daemon->epoll_fd = epoll_create1 (EPOLL_CLOEXEC); 3837 fd = epoll_create1 (EPOLL_CLOEXEC);
3669#else /* ! USE_EPOLL_CREATE1 */ 3838#else /* ! USE_EPOLL_CREATE1 */
3670 daemon->epoll_fd = epoll_create (MAX_EVENTS); 3839 fd = epoll_create (MAX_EVENTS);
3671#endif /* ! USE_EPOLL_CREATE1 */ 3840#endif /* ! USE_EPOLL_CREATE1 */
3672 if (-1 == daemon->epoll_fd) 3841 if (MHD_INVALID_SOCKET == fd)
3673 { 3842 {
3674#ifdef HAVE_MESSAGES 3843#ifdef HAVE_MESSAGES
3675 MHD_DLOG (daemon, 3844 MHD_DLOG (daemon,
3676 "Call to epoll_create1 failed: %s\n", 3845 "Call to epoll_create1 failed: %s\n",
3677 MHD_socket_last_strerr_ ()); 3846 MHD_socket_last_strerr_ ());
3678#endif 3847#endif
3679 return MHD_NO; 3848 return MHD_INVALID_SOCKET;
3680 } 3849 }
3681#if !defined(USE_EPOLL_CREATE1) 3850#if !defined(USE_EPOLL_CREATE1)
3682 if (!MHD_socket_noninheritable_ (daemon->epoll_fd)) 3851 if (! MHD_socket_noninheritable_ (fd))
3683 { 3852 {
3684#ifdef HAVE_MESSAGES 3853#ifdef HAVE_MESSAGES
3685 MHD_DLOG (daemon, 3854 MHD_DLOG (daemon,
@@ -3687,6 +3856,33 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon)
3687#endif 3856#endif
3688 } 3857 }
3689#endif /* ! USE_EPOLL_CREATE1 */ 3858#endif /* ! USE_EPOLL_CREATE1 */
3859 return fd;
3860}
3861
3862
3863/**
3864 * Setup epoll() FD for the daemon and initialize it to listen
3865 * on the listen FD.
3866 *
3867 * @param daemon daemon to initialize for epoll()
3868 * @return #MHD_YES on success, #MHD_NO on failure
3869 */
3870static int
3871setup_epoll_to_listen (struct MHD_Daemon *daemon)
3872{
3873 struct epoll_event event;
3874
3875 daemon->epoll_fd = setup_epoll_fd (daemon);
3876 if (MHD_INVALID_SOCKET == daemon->epoll_fd)
3877 return MHD_NO;
3878#if HTTPS_SUPPORT
3879 if (MHD_USE_TLS_EPOLL_UPGRADE == (MHD_USE_TLS_EPOLL_UPGRADE & daemon->options))
3880 {
3881 daemon->epoll_upgrade_fd = setup_epoll_fd (daemon);
3882 if (MHD_INVALID_SOCKET == daemon->epoll_upgrade_fd)
3883 return MHD_NO;
3884 }
3885#endif
3690 if (MHD_INVALID_SOCKET == daemon->socket_fd) 3886 if (MHD_INVALID_SOCKET == daemon->socket_fd)
3691 return MHD_YES; /* non-listening daemon */ 3887 return MHD_YES; /* non-listening daemon */
3692 event.events = EPOLLIN; 3888 event.events = EPOLLIN;
@@ -3788,6 +3984,9 @@ MHD_start_daemon_va (unsigned int flags,
3788 memset (daemon, 0, sizeof (struct MHD_Daemon)); 3984 memset (daemon, 0, sizeof (struct MHD_Daemon));
3789#ifdef EPOLL_SUPPORT 3985#ifdef EPOLL_SUPPORT
3790 daemon->epoll_fd = -1; 3986 daemon->epoll_fd = -1;
3987#if HTTPS_SUPPORT
3988 daemon->epoll_upgrade_fd = -1;
3989#endif
3791#endif 3990#endif
3792 /* try to open listen socket */ 3991 /* try to open listen socket */
3793#if HTTPS_SUPPORT 3992#if HTTPS_SUPPORT
@@ -3842,7 +4041,7 @@ MHD_start_daemon_va (unsigned int flags,
3842 free (daemon); 4041 free (daemon);
3843 return NULL; 4042 return NULL;
3844 } 4043 }
3845 if (!MHD_itc_nonblocking_(daemon->wpipe[0])) 4044 if (! MHD_itc_nonblocking_(daemon->wpipe[0]))
3846 { 4045 {
3847#ifdef HAVE_MESSAGES 4046#ifdef HAVE_MESSAGES
3848 MHD_DLOG (daemon, 4047 MHD_DLOG (daemon,
@@ -4482,6 +4681,10 @@ thread_failed:
4482#ifdef EPOLL_SUPPORT 4681#ifdef EPOLL_SUPPORT
4483 if (-1 != daemon->epoll_fd) 4682 if (-1 != daemon->epoll_fd)
4484 close (daemon->epoll_fd); 4683 close (daemon->epoll_fd);
4684#if HTTPS_SUPPORT
4685 if (-1 != daemon->epoll_upgrade_fd)
4686 close (daemon->epoll_upgrade_fd);
4687#endif
4485#endif 4688#endif
4486#ifdef DAUTH_SUPPORT 4689#ifdef DAUTH_SUPPORT
4487 free (daemon->nnc); 4690 free (daemon->nnc);
@@ -4710,6 +4913,11 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
4710 if ( (-1 != daemon->worker_pool[i].epoll_fd) && 4913 if ( (-1 != daemon->worker_pool[i].epoll_fd) &&
4711 (0 != MHD_socket_close_ (daemon->worker_pool[i].epoll_fd)) ) 4914 (0 != MHD_socket_close_ (daemon->worker_pool[i].epoll_fd)) )
4712 MHD_PANIC ("close failed\n"); 4915 MHD_PANIC ("close failed\n");
4916#if HTTPS_SUPPORT
4917 if ( (-1 != daemon->worker_pool[i].epoll_upgrade_fd) &&
4918 (0 != MHD_socket_close_ (daemon->worker_pool[i].epoll_upgrade_fd)) )
4919 MHD_PANIC ("close failed\n");
4920#endif
4713#endif 4921#endif
4714 /* Individual pipes are always used */ 4922 /* Individual pipes are always used */
4715 if (1) 4923 if (1)
@@ -4762,6 +4970,12 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
4762 (-1 != daemon->epoll_fd) && 4970 (-1 != daemon->epoll_fd) &&
4763 (0 != MHD_socket_close_ (daemon->epoll_fd)) ) 4971 (0 != MHD_socket_close_ (daemon->epoll_fd)) )
4764 MHD_PANIC ("close failed\n"); 4972 MHD_PANIC ("close failed\n");
4973#if HTTPS_SUPPORT
4974 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4975 (-1 != daemon->epoll_upgrade_fd) &&
4976 (0 != MHD_socket_close_ (daemon->epoll_upgrade_fd)) )
4977 MHD_PANIC ("close failed\n");
4978#endif
4765#endif 4979#endif
4766 4980
4767#ifdef DAUTH_SUPPORT 4981#ifdef DAUTH_SUPPORT
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 9f0faba7..00843729 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -899,6 +899,45 @@ struct MHD_Connection
899#define RESERVE_EBUF_SIZE 8 899#define RESERVE_EBUF_SIZE 8
900 900
901/** 901/**
902 * Context we pass to epoll() for each of the two sockets
903 * of a `struct MHD_UpgradeResponseHandle`. We need to do
904 * this so we can distinguish the two sockets when epoll()
905 * gives us event notifications.
906 */
907struct UpgradeEpollHandle
908{
909 /**
910 * Reference to the overall response handle this struct is
911 * included within.
912 */
913 struct MHD_UpgradeResponseHandle *urh;
914
915 /**
916 * The socket this event is kind-of about. Note that this is NOT
917 * necessarily the socket we are polling on, as for when we read
918 * from TLS, we epoll() on the connection's socket
919 * (`urh->connection->socket_fd`), while this then the application's
920 * socket (where the application will read from). Nevertheless, for
921 * the application to read, we need to first read from TLS, hence
922 * the two are related.
923 *
924 * Similarly, for writing to TLS, this epoll() will be on the
925 * connection's `socket_fd`, and this will merely be the FD which
926 * the applicatio would write to. Hence this struct must always be
927 * interpreted based on which field in `struct
928 * MHD_UpgradeResponseHandle` it is (`app` or `mhd`).
929 */
930 MHD_socket socket;
931
932 /**
933 * IO-state of the @e socket (or the connection's `socket_fd`).
934 */
935 enum MHD_EpollState celi;
936
937};
938
939
940/**
902 * Handle given to the application to manage special 941 * Handle given to the application to manage special
903 * actions relating to MHD responses that "upgrade" 942 * actions relating to MHD responses that "upgrade"
904 * the HTTP protocol (i.e. to WebSockets). 943 * the HTTP protocol (i.e. to WebSockets).
@@ -960,23 +999,13 @@ struct MHD_UpgradeResponseHandle
960 /** 999 /**
961 * The socket we gave to the application (r/w). 1000 * The socket we gave to the application (r/w).
962 */ 1001 */
963 MHD_socket app_socket; 1002 struct UpgradeEpollHandle app;
964 1003
965 /** 1004 /**
966 * If @a app_sock was a socketpair, our end of it, otherwise 1005 * If @a app_sock was a socketpair, our end of it, otherwise
967 * #MHD_INVALID_SOCKET; (r/w). 1006 * #MHD_INVALID_SOCKET; (r/w).
968 */ 1007 */
969 MHD_socket mhd_socket; 1008 struct UpgradeEpollHandle mhd;
970
971 /**
972 * IO-state of the @e mhd_socket.
973 */
974 enum MHD_EpollState celi_mhd;
975
976 /**
977 * IO-state of the @e connection's socket.
978 */
979 enum MHD_EpollState celi_client;
980 1009
981 /** 1010 /**
982 * Emergency IO buffer we use in case the memory pool has literally 1011 * Emergency IO buffer we use in case the memory pool has literally
@@ -1257,10 +1286,25 @@ struct MHD_Daemon
1257 int epoll_fd; 1286 int epoll_fd;
1258 1287
1259 /** 1288 /**
1260 * MHD_YES if the listen socket is in the 'epoll' set, 1289 * #MHD_YES if the listen socket is in the 'epoll' set,
1261 * MHD_NO if not. 1290 * #MHD_NO if not.
1262 */ 1291 */
1263 int listen_socket_in_epoll; 1292 int listen_socket_in_epoll;
1293
1294#if HTTPS_SUPPORT
1295 /**
1296 * File descriptor associated with the #run_epoll_for_upgrade() loop.
1297 * Only available if #MHD_USE_HTTPS_EPOLL_UPGRADE is set.
1298 */
1299 int epoll_upgrade_fd;
1300
1301 /**
1302 * #MHD_YES if @e epoll_upgrade_fd is in the 'epoll' set,
1303 * #MHD_NO if not.
1304 */
1305 int upgrade_fd_in_epoll;
1306#endif
1307
1264#endif 1308#endif
1265 1309
1266 /** 1310 /**
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index e778ed7f..670be983 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -599,7 +599,8 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
599 enum MHD_UpgradeAction action, 599 enum MHD_UpgradeAction action,
600 ...) 600 ...)
601{ 601{
602 struct MHD_Daemon *daemon = urh->connection->daemon; 602 struct MHD_Connection *connection = urh->connection;
603 struct MHD_Daemon *daemon = connection->daemon;
603 604
604 switch (action) 605 switch (action)
605 { 606 {
@@ -611,18 +612,46 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
611 DLL_remove (daemon->urh_head, 612 DLL_remove (daemon->urh_head,
612 daemon->urh_tail, 613 daemon->urh_tail,
613 urh); 614 urh);
614 /* FIXME: if running in epoll()-mode, do we have 615 if (0 != (daemon->options & MHD_USE_EPOLL))
615 to remove any of the FDs from any epoll-sets here? */ 616 {
616 if ( (MHD_INVALID_SOCKET != urh->app_socket) && 617 /* epoll documentation suggests that closing a FD
617 (0 != MHD_socket_close_ (urh->app_socket)) ) 618 automatically removes it from the epoll set; however,
618 MHD_PANIC ("close failed\n"); 619 this is not true as if we fail to do manually remove it,
619 if ( (MHD_INVALID_SOCKET != urh->mhd_socket) && 620 we are still seeing an event for this fd in epoll,
620 (0 != MHD_socket_close_ (urh->mhd_socket)) ) 621 causing grief (use-after-free...) --- at least on my
621 MHD_PANIC ("close failed\n"); 622 system. */
623 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
624 EPOLL_CTL_DEL,
625 connection->socket_fd,
626 NULL))
627 MHD_PANIC ("Failed to remove FD from epoll set\n");
628 }
629 if (MHD_INVALID_SOCKET != urh->app.socket)
630 {
631 if (0 != MHD_socket_close_ (urh->app.socket))
632 MHD_PANIC ("close failed\n");
633 }
634 if (MHD_INVALID_SOCKET != urh->mhd.socket)
635 {
636 /* epoll documentation suggests that closing a FD
637 automatically removes it from the epoll set; however,
638 this is not true as if we fail to do manually remove it,
639 we are still seeing an event for this fd in epoll,
640 causing grief (use-after-free...) --- at least on my
641 system. */
642 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
643 (0 != epoll_ctl (daemon->epoll_upgrade_fd,
644 EPOLL_CTL_DEL,
645 urh->mhd.socket,
646 NULL)) )
647 MHD_PANIC ("Failed to remove FD from epoll set\n");
648 if (0 != MHD_socket_close_ (urh->mhd.socket))
649 MHD_PANIC ("close failed\n");
650 }
622 } 651 }
623#endif 652#endif
624 MHD_resume_connection (urh->connection); 653 MHD_resume_connection (connection);
625 MHD_connection_close_ (urh->connection, 654 MHD_connection_close_ (connection,
626 MHD_REQUEST_TERMINATED_COMPLETED_OK); 655 MHD_REQUEST_TERMINATED_COMPLETED_OK);
627 free (urh); 656 free (urh);
628 return MHD_YES; 657 return MHD_YES;
@@ -691,6 +720,15 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
691 free (urh); 720 free (urh);
692 return MHD_NO; 721 return MHD_NO;
693 } 722 }
723 if ( (! MHD_itc_nonblocking_(sv[0])) ||
724 (! MHD_itc_nonblocking_(sv[1])) )
725 {
726#ifdef HAVE_MESSAGES
727 MHD_DLOG (daemon,
728 "Failed to make read side of inter-thread control channel non-blocking: %s\n",
729 MHD_pipe_last_strerror_ ());
730#endif
731 }
694 if ( (! MHD_SCKT_FD_FITS_FDSET_(sv[1], NULL)) && 732 if ( (! MHD_SCKT_FD_FITS_FDSET_(sv[1], NULL)) &&
695 (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) ) 733 (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) )
696 { 734 {
@@ -707,8 +745,12 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
707 free (urh); 745 free (urh);
708 return MHD_NO; 746 return MHD_NO;
709 } 747 }
710 urh->app_socket = sv[0]; 748 urh->app.socket = sv[0];
711 urh->mhd_socket = sv[1]; 749 urh->app.urh = urh;
750 urh->app.celi = MHD_EPOLL_STATE_UNREADY;
751 urh->mhd.socket = sv[1];
752 urh->mhd.urh = urh;
753 urh->mhd.celi = MHD_EPOLL_STATE_UNREADY;
712 pool = connection->pool; 754 pool = connection->pool;
713 avail = MHD_pool_get_free (pool); 755 avail = MHD_pool_get_free (pool);
714 if (avail < 8) 756 if (avail < 8)
@@ -740,26 +782,80 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response,
740 connection->client_context, 782 connection->client_context,
741 connection->read_buffer, 783 connection->read_buffer,
742 rbo, 784 rbo,
743 urh->app_socket, 785 urh->app.socket,
744 urh); 786 urh);
745 /* As far as MHD is concerned, this connection is 787 /* As far as MHD is concerned, this connection is
746 suspended; it will be resumed once we are done 788 suspended; it will be resumed once we are done
747 in the #MHD_upgrade_action() function */ 789 in the #MHD_upgrade_action() function */
748 MHD_suspend_connection (connection); 790 MHD_suspend_connection (connection);
749 urh->celi_mhd = MHD_EPOLL_STATE_UNREADY; 791
750 urh->celi_client = MHD_EPOLL_STATE_UNREADY;
751 /* FIXME: is it possible we did not fully drain the client
752 socket yet and are thus read-ready already? This may
753 matter if we are in epoll() edge triggered mode... */
754 /* Launch IO processing by the event loop */ 792 /* Launch IO processing by the event loop */
755 /* FIXME: this will not work (yet) for thread-per-connection processing */ 793 if (0 != (daemon->options & MHD_USE_EPOLL))
756 DLL_insert (connection->daemon->urh_head, 794 {
757 connection->daemon->urh_tail, 795 /* We're running with epoll(), need to add the sockets
796 to the event set of the daemon's `epoll_upgrade_fd` */
797 struct epoll_event event;
798
799 EXTRA_CHECK (MHD_SOCKET_INVALID != daemon->epoll_upgrade_fd);
800 /* First, add network socket */
801 event.events = EPOLLIN | EPOLLOUT;
802 event.data.ptr = &urh->app;
803 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
804 EPOLL_CTL_ADD,
805 connection->socket_fd,
806 &event))
807 {
808#ifdef HAVE_MESSAGES
809 MHD_DLOG (daemon,
810 "Call to epoll_ctl failed: %s\n",
811 MHD_socket_last_strerr_ ());
812#endif
813 if (0 != MHD_socket_close_ (sv[0]))
814 MHD_PANIC ("close failed\n");
815 if (0 != MHD_socket_close_ (sv[1]))
816 MHD_PANIC ("close failed\n");
817 free (urh);
818 return MHD_NO;
819 }
820
821 /* Second, add our end of the UNIX socketpair() */
822 event.events = EPOLLIN | EPOLLOUT;
823 event.data.ptr = &urh->mhd;
824 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
825 EPOLL_CTL_ADD,
826 urh->mhd.socket,
827 &event))
828 {
829 event.events = EPOLLIN | EPOLLOUT;
830 event.data.ptr = &urh->app;
831 if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
832 EPOLL_CTL_DEL,
833 connection->socket_fd,
834 &event))
835 MHD_PANIC ("Error cleaning up while handling epoll error");
836#ifdef HAVE_MESSAGES
837 MHD_DLOG (daemon,
838 "Call to epoll_ctl failed: %s\n",
839 MHD_socket_last_strerr_ ());
840#endif
841 if (0 != MHD_socket_close_ (sv[0]))
842 MHD_PANIC ("close failed\n");
843 if (0 != MHD_socket_close_ (sv[1]))
844 MHD_PANIC ("close failed\n");
845 free (urh);
846 return MHD_NO;
847 }
848 }
849
850 /* This takes care of most event loops: simply add to DLL */
851 DLL_insert (daemon->urh_head,
852 daemon->urh_tail,
758 urh); 853 urh);
854 /* FIXME: None of the above will not work (yet) for thread-per-connection processing */
759 return MHD_YES; 855 return MHD_YES;
760 } 856 }
761 urh->app_socket = MHD_INVALID_SOCKET; 857 urh->app.socket = MHD_INVALID_SOCKET;
762 urh->mhd_socket = MHD_INVALID_SOCKET; 858 urh->mhd.socket = MHD_INVALID_SOCKET;
763#endif 859#endif
764 response->upgrade_handler (response->upgrade_handler_cls, 860 response->upgrade_handler (response->upgrade_handler_cls,
765 connection, 861 connection,