aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-02-15 13:25:50 +0100
committerChristian Grothoff <christian@grothoff.org>2017-02-15 13:25:50 +0100
commit2eb1573d56d2b44702c05650ee41fcbacf4b01ce (patch)
treef65ac24e81d9d4f774863eed852a5f364b77688a
parent2a815fe3330063bea19699729f9c6d6c2c836ebc (diff)
downloadlibmicrohttpd-2eb1573d56d2b44702c05650ee41fcbacf4b01ce.tar.gz
libmicrohttpd-2eb1573d56d2b44702c05650ee41fcbacf4b01ce.zip
fix race related to MHD_quiesce_daemon setting the listen socket to -1 which may disrupt concurrent non-locking activities by instead setting a flag (which suffices given the document semantics of MHD_quiesce_daemon()); renaming the socket_fd to listen_fd to distinguish it better by name
-rw-r--r--src/microhttpd/daemon.c149
-rw-r--r--src/microhttpd/internal.h9
2 files changed, 92 insertions, 66 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index a8997d87..e7d8ebf7 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -796,8 +796,9 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon,
796 fd_setsize) ? MHD_YES : MHD_NO; 796 fd_setsize) ? MHD_YES : MHD_NO;
797 } 797 }
798#endif 798#endif
799 ls = daemon->socket_fd; 799 ls = daemon->listen_fd;
800 if ( (MHD_INVALID_SOCKET != ls) && 800 if ( (MHD_INVALID_SOCKET != ls) &&
801 (! daemon->was_quiesced) &&
801 (! MHD_add_to_fd_set_ (ls, 802 (! MHD_add_to_fd_set_ (ls,
802 read_fd_set, 803 read_fd_set,
803 max_fd, 804 max_fd,
@@ -2669,7 +2670,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
2669 memset (addr, 2670 memset (addr,
2670 0, 2671 0,
2671 sizeof (addrstorage)); 2672 sizeof (addrstorage));
2672 if (MHD_INVALID_SOCKET == (fd = daemon->socket_fd)) 2673 if ( (MHD_INVALID_SOCKET == (fd = daemon->listen_fd)) ||
2674 (daemon->was_quiesced) )
2673 return MHD_NO; 2675 return MHD_NO;
2674#ifdef USE_ACCEPT4 2676#ifdef USE_ACCEPT4
2675 s = accept4 (fd, 2677 s = accept4 (fd,
@@ -3034,7 +3036,8 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
3034#endif 3036#endif
3035 3037
3036 /* select connection thread handling type */ 3038 /* select connection thread handling type */
3037 if ( (MHD_INVALID_SOCKET != (ds = daemon->socket_fd)) && 3039 if ( (MHD_INVALID_SOCKET != (ds = daemon->listen_fd)) &&
3040 (! daemon->was_quiesced) &&
3038 (FD_ISSET (ds, 3041 (FD_ISSET (ds,
3039 read_fd_set)) ) 3042 read_fd_set)) )
3040 (void) MHD_accept_connection (daemon); 3043 (void) MHD_accept_connection (daemon);
@@ -3144,7 +3147,8 @@ MHD_select (struct MHD_Daemon *daemon,
3144 else 3147 else
3145 { 3148 {
3146 /* accept only, have one thread per connection */ 3149 /* accept only, have one thread per connection */
3147 if ( (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) && 3150 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3151 (! daemon->was_quiesced) &&
3148 (! MHD_add_to_fd_set_ (ls, 3152 (! MHD_add_to_fd_set_ (ls,
3149 &rs, 3153 &rs,
3150 &maxsock, 3154 &maxsock,
@@ -3167,7 +3171,8 @@ MHD_select (struct MHD_Daemon *daemon,
3167 /* fdset limit reached, new connections 3171 /* fdset limit reached, new connections
3168 cannot be handled. Remove listen socket FD 3172 cannot be handled. Remove listen socket FD
3169 from fdset and retry to add ITC FD. */ 3173 from fdset and retry to add ITC FD. */
3170 if (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) 3174 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3175 (! daemon->was_quiesced) )
3171 { 3176 {
3172 FD_CLR (ls, 3177 FD_CLR (ls,
3173 &rs); 3178 &rs);
@@ -3193,7 +3198,7 @@ MHD_select (struct MHD_Daemon *daemon,
3193 the shutdown OR the termination of an existing connection; so 3198 the shutdown OR the termination of an existing connection; so
3194 only do this optimization if we have a signaling ITC in 3199 only do this optimization if we have a signaling ITC in
3195 place. */ 3200 place. */
3196 if ( (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) && 3201 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3197 (MHD_ITC_IS_VALID_(daemon->itc)) && 3202 (MHD_ITC_IS_VALID_(daemon->itc)) &&
3198 (0 != (daemon->options & MHD_USE_ITC)) && 3203 (0 != (daemon->options & MHD_USE_ITC)) &&
3199 ( (daemon->connections == daemon->connection_limit) || 3204 ( (daemon->connections == daemon->connection_limit) ||
@@ -3305,7 +3310,8 @@ MHD_poll_all (struct MHD_Daemon *daemon,
3305 } 3310 }
3306 poll_server = 0; 3311 poll_server = 0;
3307 poll_listen = -1; 3312 poll_listen = -1;
3308 if ( (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) && 3313 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3314 (! daemon->was_quiesced) &&
3309 (daemon->connections < daemon->connection_limit) && 3315 (daemon->connections < daemon->connection_limit) &&
3310 (! daemon->at_limit) ) 3316 (! daemon->at_limit) )
3311 { 3317 {
@@ -3516,7 +3522,9 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
3516 poll_count = 0; 3522 poll_count = 0;
3517 poll_listen = -1; 3523 poll_listen = -1;
3518 poll_itc_idx = -1; 3524 poll_itc_idx = -1;
3519 if (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) 3525 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3526 (! daemon->was_quiesced) )
3527
3520 { 3528 {
3521 p[poll_count].fd = ls; 3529 p[poll_count].fd = ls;
3522 p[poll_count].events = POLLIN; 3530 p[poll_count].events = POLLIN;
@@ -3716,7 +3724,8 @@ MHD_epoll (struct MHD_Daemon *daemon,
3716 return MHD_NO; /* we're down! */ 3724 return MHD_NO; /* we're down! */
3717 if (daemon->shutdown) 3725 if (daemon->shutdown)
3718 return MHD_NO; 3726 return MHD_NO;
3719 if ( (MHD_INVALID_SOCKET != (ls = daemon->socket_fd)) && 3727 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
3728 (! daemon->was_quiesced) &&
3720 (daemon->connections < daemon->connection_limit) && 3729 (daemon->connections < daemon->connection_limit) &&
3721 (MHD_NO == daemon->listen_socket_in_epoll) && 3730 (MHD_NO == daemon->listen_socket_in_epoll) &&
3722 (! daemon->at_limit) ) 3731 (! daemon->at_limit) )
@@ -3737,6 +3746,17 @@ MHD_epoll (struct MHD_Daemon *daemon,
3737 } 3746 }
3738 daemon->listen_socket_in_epoll = MHD_YES; 3747 daemon->listen_socket_in_epoll = MHD_YES;
3739 } 3748 }
3749 if ( (daemon->was_quiesced) &&
3750 (MHD_YES == daemon->listen_socket_in_epoll) )
3751 {
3752 if (0 != epoll_ctl (daemon->epoll_fd,
3753 EPOLL_CTL_DEL,
3754 ls,
3755 NULL))
3756 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
3757 daemon->listen_socket_in_epoll = MHD_NO;
3758 }
3759
3740#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 3760#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
3741 if ( (MHD_NO == daemon->upgrade_fd_in_epoll) && 3761 if ( (MHD_NO == daemon->upgrade_fd_in_epoll) &&
3742 (-1 != daemon->epoll_upgrade_fd) ) 3762 (-1 != daemon->epoll_upgrade_fd) )
@@ -3758,9 +3778,10 @@ MHD_epoll (struct MHD_Daemon *daemon,
3758 daemon->upgrade_fd_in_epoll = MHD_YES; 3778 daemon->upgrade_fd_in_epoll = MHD_YES;
3759 } 3779 }
3760#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 3780#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
3761 if ( ( (MHD_YES == daemon->listen_socket_in_epoll) && 3781 if ( (MHD_YES == daemon->listen_socket_in_epoll) &&
3762 (daemon->connections == daemon->connection_limit) ) || 3782 ( (daemon->connections == daemon->connection_limit) ||
3763 (daemon->at_limit) ) 3783 (daemon->at_limit) ||
3784 (daemon->was_quiesced) ) )
3764 { 3785 {
3765 /* we're at the connection limit, disable listen socket 3786 /* we're at the connection limit, disable listen socket
3766 for event loop for now */ 3787 for event loop for now */
@@ -4166,7 +4187,7 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4166 unsigned int i; 4187 unsigned int i;
4167 MHD_socket ret; 4188 MHD_socket ret;
4168 4189
4169 ret = daemon->socket_fd; 4190 ret = daemon->listen_fd;
4170 if (MHD_INVALID_SOCKET == ret) 4191 if (MHD_INVALID_SOCKET == ret)
4171 return MHD_INVALID_SOCKET; 4192 return MHD_INVALID_SOCKET;
4172 if ( (MHD_ITC_IS_INVALID_(daemon->itc)) && 4193 if ( (MHD_ITC_IS_INVALID_(daemon->itc)) &&
@@ -4182,7 +4203,7 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4182 if (NULL != daemon->worker_pool) 4203 if (NULL != daemon->worker_pool)
4183 for (i = 0; i < daemon->worker_pool_size; i++) 4204 for (i = 0; i < daemon->worker_pool_size; i++)
4184 { 4205 {
4185 daemon->worker_pool[i].socket_fd = MHD_INVALID_SOCKET; 4206 daemon->worker_pool[i].was_quiesced = true;
4186#ifdef EPOLL_SUPPORT 4207#ifdef EPOLL_SUPPORT
4187 if ( (0 != (daemon->options & MHD_USE_EPOLL)) && 4208 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4188 (-1 != daemon->worker_pool[i].epoll_fd) && 4209 (-1 != daemon->worker_pool[i].epoll_fd) &&
@@ -4203,10 +4224,7 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4203 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); 4224 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel"));
4204 } 4225 }
4205 } 4226 }
4206 /* FIXME: This creates a race with the rest of the code. 4227 daemon->was_quiesced = true;
4207 We may be adding the FD to the epoll-set concurrently
4208 in another thread! So we DO need to lock (yuck yuck). */
4209 daemon->socket_fd = MHD_INVALID_SOCKET;
4210#ifdef EPOLL_SUPPORT 4228#ifdef EPOLL_SUPPORT
4211 if ( (0 != (daemon->options & MHD_USE_EPOLL)) && 4229 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
4212 (-1 != daemon->epoll_fd) && 4230 (-1 != daemon->epoll_fd) &&
@@ -4219,14 +4237,10 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon)
4219 MHD_PANIC ("Failed to remove listen FD from epoll set\n"); 4237 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
4220 daemon->listen_socket_in_epoll = MHD_NO; 4238 daemon->listen_socket_in_epoll = MHD_NO;
4221 } 4239 }
4222 else
4223#endif 4240#endif
4224 if (MHD_ITC_IS_VALID_(daemon->itc)) 4241 if ( (MHD_ITC_IS_VALID_(daemon->itc)) &&
4225 { 4242 (! MHD_itc_activate_ (daemon->itc, "q")) )
4226 if (! MHD_itc_activate_ (daemon->itc, "q")) 4243 MHD_PANIC (_("failed to signal quiesce via inter-thread communication channel"));
4227 MHD_PANIC (_("failed to signal quiesce via inter-thread communication channel"));
4228 }
4229
4230 return ret; 4244 return ret;
4231} 4245}
4232 4246
@@ -4499,7 +4513,7 @@ parse_options_va (struct MHD_Daemon *daemon,
4499 break; 4513 break;
4500#endif 4514#endif
4501 case MHD_OPTION_LISTEN_SOCKET: 4515 case MHD_OPTION_LISTEN_SOCKET:
4502 daemon->socket_fd = va_arg (ap, 4516 daemon->listen_fd = va_arg (ap,
4503 MHD_socket); 4517 MHD_socket);
4504 break; 4518 break;
4505 case MHD_OPTION_EXTERNAL_LOGGER: 4519 case MHD_OPTION_EXTERNAL_LOGGER:
@@ -4721,7 +4735,8 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon)
4721 return MHD_NO; 4735 return MHD_NO;
4722 } 4736 }
4723#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4737#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4724 if (MHD_INVALID_SOCKET == (ls = daemon->socket_fd)) 4738 if ( (MHD_INVALID_SOCKET == (ls = daemon->listen_fd)) ||
4739 (daemon->was_quiesced) )
4725 return MHD_YES; /* non-listening daemon */ 4740 return MHD_YES; /* non-listening daemon */
4726 event.events = EPOLLIN; 4741 event.events = EPOLLIN;
4727 event.data.ptr = daemon; 4742 event.data.ptr = daemon;
@@ -4789,7 +4804,7 @@ MHD_start_daemon_va (unsigned int flags,
4789{ 4804{
4790 const MHD_SCKT_OPT_BOOL_ on = 1; 4805 const MHD_SCKT_OPT_BOOL_ on = 1;
4791 struct MHD_Daemon *daemon; 4806 struct MHD_Daemon *daemon;
4792 MHD_socket socket_fd; 4807 MHD_socket listen_fd;
4793 struct sockaddr_in servaddr4; 4808 struct sockaddr_in servaddr4;
4794#if HAVE_INET6 4809#if HAVE_INET6
4795 struct sockaddr_in6 servaddr6; 4810 struct sockaddr_in6 servaddr6;
@@ -4887,7 +4902,7 @@ MHD_start_daemon_va (unsigned int flags,
4887 NULL); 4902 NULL);
4888 } 4903 }
4889#endif /* HTTPS_SUPPORT */ 4904#endif /* HTTPS_SUPPORT */
4890 daemon->socket_fd = MHD_INVALID_SOCKET; 4905 daemon->listen_fd = MHD_INVALID_SOCKET;
4891 daemon->listening_address_reuse = 0; 4906 daemon->listening_address_reuse = 0;
4892 daemon->options = flags; 4907 daemon->options = flags;
4893 daemon->port = port; 4908 daemon->port = port;
@@ -5052,12 +5067,12 @@ MHD_start_daemon_va (unsigned int flags,
5052 goto free_and_fail; 5067 goto free_and_fail;
5053 } 5068 }
5054#endif 5069#endif
5055 if ( (MHD_INVALID_SOCKET == daemon->socket_fd) && 5070 if ( (MHD_INVALID_SOCKET == daemon->listen_fd) &&
5056 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) 5071 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
5057 { 5072 {
5058 /* try to open listen socket */ 5073 /* try to open listen socket */
5059 socket_fd = MHD_socket_create_listen_(flags & MHD_USE_IPv6); 5074 listen_fd = MHD_socket_create_listen_(flags & MHD_USE_IPv6);
5060 if (MHD_INVALID_SOCKET == socket_fd) 5075 if (MHD_INVALID_SOCKET == listen_fd)
5061 { 5076 {
5062#ifdef HAVE_MESSAGES 5077#ifdef HAVE_MESSAGES
5063 MHD_DLOG (daemon, 5078 MHD_DLOG (daemon,
@@ -5075,7 +5090,7 @@ MHD_start_daemon_va (unsigned int flags,
5075 * on non-W32 platforms, and do not fail if it doesn't work. 5090 * on non-W32 platforms, and do not fail if it doesn't work.
5076 * Don't use it on W32, because on W32 it will allow multiple 5091 * Don't use it on W32, because on W32 it will allow multiple
5077 * bind to the same address:port, like SO_REUSEPORT on others. */ 5092 * bind to the same address:port, like SO_REUSEPORT on others. */
5078 if (0 > setsockopt (socket_fd, 5093 if (0 > setsockopt (listen_fd,
5079 SOL_SOCKET, 5094 SOL_SOCKET,
5080 SO_REUSEADDR, 5095 SO_REUSEADDR,
5081 (void*)&on, sizeof (on))) 5096 (void*)&on, sizeof (on)))
@@ -5094,7 +5109,7 @@ MHD_start_daemon_va (unsigned int flags,
5094#ifndef _WIN32 5109#ifndef _WIN32
5095 /* Use SO_REUSEADDR on non-W32 platforms, and do not fail if 5110 /* Use SO_REUSEADDR on non-W32 platforms, and do not fail if
5096 * it doesn't work. */ 5111 * it doesn't work. */
5097 if (0 > setsockopt (socket_fd, 5112 if (0 > setsockopt (listen_fd,
5098 SOL_SOCKET, 5113 SOL_SOCKET,
5099 SO_REUSEADDR, 5114 SO_REUSEADDR,
5100 (void*)&on, sizeof (on))) 5115 (void*)&on, sizeof (on)))
@@ -5112,7 +5127,7 @@ MHD_start_daemon_va (unsigned int flags,
5112 /* SO_REUSEADDR on W32 has the same semantics 5127 /* SO_REUSEADDR on W32 has the same semantics
5113 as SO_REUSEPORT on BSD/Linux */ 5128 as SO_REUSEPORT on BSD/Linux */
5114#if defined(_WIN32) || defined(SO_REUSEPORT) 5129#if defined(_WIN32) || defined(SO_REUSEPORT)
5115 if (0 > setsockopt (socket_fd, 5130 if (0 > setsockopt (listen_fd,
5116 SOL_SOCKET, 5131 SOL_SOCKET,
5117#ifndef _WIN32 5132#ifndef _WIN32
5118 SO_REUSEPORT, 5133 SO_REUSEPORT,
@@ -5150,7 +5165,7 @@ MHD_start_daemon_va (unsigned int flags,
5150#if (defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)) || \ 5165#if (defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)) || \
5151 (defined(__sun) && defined(SO_EXCLBIND)) 5166 (defined(__sun) && defined(SO_EXCLBIND))
5152#ifdef SO_EXCLUSIVEADDRUSE 5167#ifdef SO_EXCLUSIVEADDRUSE
5153 if (0 > setsockopt (socket_fd, 5168 if (0 > setsockopt (listen_fd,
5154 SOL_SOCKET, 5169 SOL_SOCKET,
5155#ifdef SO_EXCLUSIVEADDRUSE 5170#ifdef SO_EXCLUSIVEADDRUSE
5156 SO_EXCLUSIVEADDRUSE, 5171 SO_EXCLUSIVEADDRUSE,
@@ -5213,7 +5228,7 @@ MHD_start_daemon_va (unsigned int flags,
5213 servaddr = (struct sockaddr *) &servaddr4; 5228 servaddr = (struct sockaddr *) &servaddr4;
5214 } 5229 }
5215 } 5230 }
5216 daemon->socket_fd = socket_fd; 5231 daemon->listen_fd = listen_fd;
5217 5232
5218 if (0 != (flags & MHD_USE_IPv6)) 5233 if (0 != (flags & MHD_USE_IPv6))
5219 { 5234 {
@@ -5225,7 +5240,7 @@ MHD_start_daemon_va (unsigned int flags,
5225 your IPv6 socket may then also bind against IPv4 anyway... */ 5240 your IPv6 socket may then also bind against IPv4 anyway... */
5226 const MHD_SCKT_OPT_BOOL_ v6_only = 5241 const MHD_SCKT_OPT_BOOL_ v6_only =
5227 (MHD_USE_DUAL_STACK != (flags & MHD_USE_DUAL_STACK)); 5242 (MHD_USE_DUAL_STACK != (flags & MHD_USE_DUAL_STACK));
5228 if (0 > setsockopt (socket_fd, 5243 if (0 > setsockopt (listen_fd,
5229 IPPROTO_IPV6, IPV6_V6ONLY, 5244 IPPROTO_IPV6, IPV6_V6ONLY,
5230 (const void *) &v6_only, 5245 (const void *) &v6_only,
5231 sizeof (v6_only))) 5246 sizeof (v6_only)))
@@ -5239,7 +5254,7 @@ MHD_start_daemon_va (unsigned int flags,
5239#endif 5254#endif
5240#endif 5255#endif
5241 } 5256 }
5242 if (-1 == bind (socket_fd, servaddr, addrlen)) 5257 if (-1 == bind (listen_fd, servaddr, addrlen))
5243 { 5258 {
5244#ifdef HAVE_MESSAGES 5259#ifdef HAVE_MESSAGES
5245 MHD_DLOG (daemon, 5260 MHD_DLOG (daemon,
@@ -5247,7 +5262,7 @@ MHD_start_daemon_va (unsigned int flags,
5247 (unsigned int) port, 5262 (unsigned int) port,
5248 MHD_socket_last_strerr_ ()); 5263 MHD_socket_last_strerr_ ());
5249#endif 5264#endif
5250 MHD_socket_close_chk_ (socket_fd); 5265 MHD_socket_close_chk_ (listen_fd);
5251 goto free_and_fail; 5266 goto free_and_fail;
5252 } 5267 }
5253#ifdef TCP_FASTOPEN 5268#ifdef TCP_FASTOPEN
@@ -5255,7 +5270,7 @@ MHD_start_daemon_va (unsigned int flags,
5255 { 5270 {
5256 if (0 == daemon->fastopen_queue_size) 5271 if (0 == daemon->fastopen_queue_size)
5257 daemon->fastopen_queue_size = MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT; 5272 daemon->fastopen_queue_size = MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT;
5258 if (0 != setsockopt (socket_fd, 5273 if (0 != setsockopt (listen_fd,
5259 IPPROTO_TCP, 5274 IPPROTO_TCP,
5260 TCP_FASTOPEN, 5275 TCP_FASTOPEN,
5261 &daemon->fastopen_queue_size, 5276 &daemon->fastopen_queue_size,
@@ -5269,7 +5284,7 @@ MHD_start_daemon_va (unsigned int flags,
5269 } 5284 }
5270 } 5285 }
5271#endif 5286#endif
5272 if (listen (socket_fd, 5287 if (listen (listen_fd,
5273 daemon->listen_backlog_size) < 0) 5288 daemon->listen_backlog_size) < 0)
5274 { 5289 {
5275#ifdef HAVE_MESSAGES 5290#ifdef HAVE_MESSAGES
@@ -5277,16 +5292,16 @@ MHD_start_daemon_va (unsigned int flags,
5277 _("Failed to listen for connections: %s\n"), 5292 _("Failed to listen for connections: %s\n"),
5278 MHD_socket_last_strerr_ ()); 5293 MHD_socket_last_strerr_ ());
5279#endif 5294#endif
5280 MHD_socket_close_chk_ (socket_fd); 5295 MHD_socket_close_chk_ (listen_fd);
5281 goto free_and_fail; 5296 goto free_and_fail;
5282 } 5297 }
5283 } 5298 }
5284 else 5299 else
5285 { 5300 {
5286 socket_fd = daemon->socket_fd; 5301 listen_fd = daemon->listen_fd;
5287 } 5302 }
5288 5303
5289 if (!MHD_socket_nonblocking_ (socket_fd)) 5304 if (!MHD_socket_nonblocking_ (listen_fd))
5290 { 5305 {
5291#ifdef HAVE_MESSAGES 5306#ifdef HAVE_MESSAGES
5292 MHD_DLOG (daemon, 5307 MHD_DLOG (daemon,
@@ -5299,21 +5314,21 @@ MHD_start_daemon_va (unsigned int flags,
5299 /* Accept must be non-blocking. Multiple children may wake up 5314 /* Accept must be non-blocking. Multiple children may wake up
5300 * to handle a new connection, but only one will win the race. 5315 * to handle a new connection, but only one will win the race.
5301 * The others must immediately return. */ 5316 * The others must immediately return. */
5302 MHD_socket_close_chk_ (socket_fd); 5317 MHD_socket_close_chk_ (listen_fd);
5303 goto free_and_fail; 5318 goto free_and_fail;
5304 } 5319 }
5305 } 5320 }
5306 if ( (!MHD_SCKT_FD_FITS_FDSET_(socket_fd, 5321 if ( (!MHD_SCKT_FD_FITS_FDSET_(listen_fd,
5307 NULL)) && 5322 NULL)) &&
5308 (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL)) ) ) 5323 (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL)) ) )
5309 { 5324 {
5310#ifdef HAVE_MESSAGES 5325#ifdef HAVE_MESSAGES
5311 MHD_DLOG (daemon, 5326 MHD_DLOG (daemon,
5312 _("Socket descriptor larger than FD_SETSIZE: %d > %d\n"), 5327 _("Socket descriptor larger than FD_SETSIZE: %d > %d\n"),
5313 socket_fd, 5328 listen_fd,
5314 FD_SETSIZE); 5329 FD_SETSIZE);
5315#endif 5330#endif
5316 MHD_socket_close_chk_ (socket_fd); 5331 MHD_socket_close_chk_ (listen_fd);
5317 goto free_and_fail; 5332 goto free_and_fail;
5318 } 5333 }
5319 5334
@@ -5341,8 +5356,8 @@ MHD_start_daemon_va (unsigned int flags,
5341 MHD_DLOG (daemon, 5356 MHD_DLOG (daemon,
5342 _("MHD failed to initialize IP connection limit mutex\n")); 5357 _("MHD failed to initialize IP connection limit mutex\n"));
5343#endif 5358#endif
5344 if (MHD_INVALID_SOCKET != socket_fd) 5359 if (MHD_INVALID_SOCKET != listen_fd)
5345 MHD_socket_close_chk_ (socket_fd); 5360 MHD_socket_close_chk_ (listen_fd);
5346 goto free_and_fail; 5361 goto free_and_fail;
5347 } 5362 }
5348 if (! MHD_mutex_init_ (&daemon->cleanup_connection_mutex)) 5363 if (! MHD_mutex_init_ (&daemon->cleanup_connection_mutex))
@@ -5352,8 +5367,8 @@ MHD_start_daemon_va (unsigned int flags,
5352 _("MHD failed to initialize IP connection limit mutex\n")); 5367 _("MHD failed to initialize IP connection limit mutex\n"));
5353#endif 5368#endif
5354 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); 5369 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
5355 if (MHD_INVALID_SOCKET != socket_fd) 5370 if (MHD_INVALID_SOCKET != listen_fd)
5356 MHD_socket_close_chk_ (socket_fd); 5371 MHD_socket_close_chk_ (listen_fd);
5357 goto free_and_fail; 5372 goto free_and_fail;
5358 } 5373 }
5359 5374
@@ -5366,8 +5381,8 @@ MHD_start_daemon_va (unsigned int flags,
5366 MHD_DLOG (daemon, 5381 MHD_DLOG (daemon,
5367 _("Failed to initialize TLS support\n")); 5382 _("Failed to initialize TLS support\n"));
5368#endif 5383#endif
5369 if (MHD_INVALID_SOCKET != socket_fd) 5384 if (MHD_INVALID_SOCKET != listen_fd)
5370 MHD_socket_close_chk_ (socket_fd); 5385 MHD_socket_close_chk_ (listen_fd);
5371 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); 5386 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
5372 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); 5387 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex);
5373 goto free_and_fail; 5388 goto free_and_fail;
@@ -5390,8 +5405,8 @@ MHD_start_daemon_va (unsigned int flags,
5390#endif 5405#endif
5391 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); 5406 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
5392 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); 5407 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex);
5393 if (MHD_INVALID_SOCKET != socket_fd) 5408 if (MHD_INVALID_SOCKET != listen_fd)
5394 MHD_socket_close_chk_ (socket_fd); 5409 MHD_socket_close_chk_ (listen_fd);
5395 goto free_and_fail; 5410 goto free_and_fail;
5396 } 5411 }
5397 if ( (daemon->worker_pool_size > 0) && 5412 if ( (daemon->worker_pool_size > 0) &&
@@ -5507,8 +5522,8 @@ thread_failed:
5507 MHD_USE_INTERNAL_POLLING_THREAD mode. */ 5522 MHD_USE_INTERNAL_POLLING_THREAD mode. */
5508 if (0 == i) 5523 if (0 == i)
5509 { 5524 {
5510 if (MHD_INVALID_SOCKET != socket_fd) 5525 if (MHD_INVALID_SOCKET != listen_fd)
5511 MHD_socket_close_chk_ (socket_fd); 5526 MHD_socket_close_chk_ (listen_fd);
5512 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); 5527 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
5513 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); 5528 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex);
5514 if (NULL != daemon->worker_pool) 5529 if (NULL != daemon->worker_pool)
@@ -5728,7 +5743,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
5728 resume_suspended_connections (daemon); 5743 resume_suspended_connections (daemon);
5729 5744
5730 daemon->shutdown = true; 5745 daemon->shutdown = true;
5731 fd = daemon->socket_fd; 5746 fd = daemon->listen_fd;
5732 5747
5733 if (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) 5748 if (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
5734 { 5749 {
@@ -5750,7 +5765,8 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
5750 { 5765 {
5751 /* fd might be MHD_INVALID_SOCKET here due to 'MHD_quiesce_daemon' */ 5766 /* fd might be MHD_INVALID_SOCKET here due to 'MHD_quiesce_daemon' */
5752 /* No problem if shutdown will be called several times for the same socket. */ 5767 /* No problem if shutdown will be called several times for the same socket. */
5753 (void) shutdown (fd, SHUT_RDWR); 5768 (void) shutdown (fd,
5769 SHUT_RDWR);
5754 } 5770 }
5755#endif 5771#endif
5756 } 5772 }
@@ -5785,8 +5801,10 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
5785 else 5801 else
5786 { 5802 {
5787 /* fd might be MHD_INVALID_SOCKET here due to 'MHD_quiesce_daemon' */ 5803 /* fd might be MHD_INVALID_SOCKET here due to 'MHD_quiesce_daemon' */
5788 if (MHD_INVALID_SOCKET != fd) 5804 if ( (MHD_INVALID_SOCKET != fd) &&
5789 (void) shutdown (fd, SHUT_RDWR); 5805 (! daemon->was_quiesced) )
5806 (void) shutdown (fd,
5807 SHUT_RDWR);
5790 } 5808 }
5791#endif 5809#endif
5792 if (! MHD_join_thread_ (daemon->pid)) 5810 if (! MHD_join_thread_ (daemon->pid))
@@ -5801,7 +5819,8 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
5801 close_all_connections (daemon); 5819 close_all_connections (daemon);
5802 } 5820 }
5803 5821
5804 if (MHD_INVALID_SOCKET != fd) 5822 if ( (MHD_INVALID_SOCKET != fd) &&
5823 (! daemon->was_quiesced) )
5805 MHD_socket_close_chk_ (fd); 5824 MHD_socket_close_chk_ (fd);
5806 5825
5807 if (MHD_ITC_IS_VALID_ (daemon->itc)) 5826 if (MHD_ITC_IS_VALID_ (daemon->itc))
@@ -5867,7 +5886,7 @@ MHD_get_daemon_info (struct MHD_Daemon *daemon,
5867 case MHD_DAEMON_INFO_MAC_KEY_SIZE: 5886 case MHD_DAEMON_INFO_MAC_KEY_SIZE:
5868 return NULL; /* no longer supported */ 5887 return NULL; /* no longer supported */
5869 case MHD_DAEMON_INFO_LISTEN_FD: 5888 case MHD_DAEMON_INFO_LISTEN_FD:
5870 return (const union MHD_DaemonInfo *) &daemon->socket_fd; 5889 return (const union MHD_DaemonInfo *) &daemon->listen_fd;
5871#ifdef EPOLL_SUPPORT 5890#ifdef EPOLL_SUPPORT
5872 case MHD_DAEMON_INFO_EPOLL_FD: 5891 case MHD_DAEMON_INFO_EPOLL_FD:
5873 return (const union MHD_DaemonInfo *) &daemon->epoll_fd; 5892 return (const union MHD_DaemonInfo *) &daemon->epoll_fd;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 5d61705a..111af62f 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -1374,7 +1374,7 @@ struct MHD_Daemon
1374 /** 1374 /**
1375 * Listen socket. 1375 * Listen socket.
1376 */ 1376 */
1377 MHD_socket socket_fd; 1377 MHD_socket listen_fd;
1378 1378
1379 /** 1379 /**
1380 * Whether to allow/disallow/ignore reuse of listening address. 1380 * Whether to allow/disallow/ignore reuse of listening address.
@@ -1426,6 +1426,13 @@ struct MHD_Daemon
1426 volatile bool shutdown; 1426 volatile bool shutdown;
1427 1427
1428 /** 1428 /**
1429 * Has this deamon been quiesced via #MHD_quiesce_daemon()?
1430 * If so, we should no longer use the @e listen_fd (including
1431 * removing it from the @e epoll_fd when possible).
1432 */
1433 volatile bool was_quiesced;
1434
1435 /**
1429 * Did we hit some system or process-wide resource limit while 1436 * Did we hit some system or process-wide resource limit while
1430 * trying to accept() the last time? If so, we don't accept new 1437 * trying to accept() the last time? If so, we don't accept new
1431 * connections until we close an existing one. This effectively 1438 * connections until we close an existing one. This effectively