aboutsummaryrefslogtreecommitdiff
path: root/src/lib/daemon_select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/daemon_select.c')
-rw-r--r--src/lib/daemon_select.c711
1 files changed, 711 insertions, 0 deletions
diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c
new file mode 100644
index 00000000..f61ba36a
--- /dev/null
+++ b/src/lib/daemon_select.c
@@ -0,0 +1,711 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file lib/daemon_select.c
22 * @brief function to run select()-based event loop of a daemon
23 * @author Christian Grothoff
24 */
25#include "internal.h"
26#include "daemon_select.h"
27
28/**
29 * We defined a macro with the same name as a function we
30 * are implementing here. Need to undef the macro to avoid
31 * causing a conflict.
32 */
33#undef MHD_daemon_get_fdset
34
35/**
36 * Obtain the `select()` sets for this daemon. Daemon's FDs will be
37 * added to fd_sets. To get only daemon FDs in fd_sets, call FD_ZERO
38 * for each fd_set before calling this function. FD_SETSIZE is assumed
39 * to be platform's default.
40 *
41 * This function should only be called in when MHD is configured to
42 * use external select with 'select()' or with 'epoll'. In the latter
43 * case, it will only add the single 'epoll()' file descriptor used by
44 * MHD to the sets. It's necessary to use #MHD_daemon_get_timeout() in
45 * combination with this function.
46 *
47 * This function must be called only for daemon started without
48 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
49 *
50 * @param daemon daemon to get sets from
51 * @param read_fd_set read set
52 * @param write_fd_set write set
53 * @param except_fd_set except set
54 * @param max_fd increased to largest FD added (if larger
55 * than existing value); can be NULL
56 * @return #MHD_SC_OK on success, otherwise error code
57 * @ingroup event
58 */
59enum MHD_StatusCode
60MHD_daemon_get_fdset (struct MHD_Daemon *daemon,
61 fd_set *read_fd_set,
62 fd_set *write_fd_set,
63 fd_set *except_fd_set,
64 MHD_socket *max_fd)
65{
66 return MHD_daemon_get_fdset2 (daemon,
67 read_fd_set,
68 write_fd_set,
69 except_fd_set,
70 max_fd,
71 _MHD_SYS_DEFAULT_FD_SETSIZE);
72}
73
74
75#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
76/**
77 * Obtain the select() file descriptor sets for the
78 * given @a urh.
79 *
80 * @param urh upgrade handle to wait for
81 * @param[out] rs read set to initialize
82 * @param[out] ws write set to initialize
83 * @param[out] es except set to initialize
84 * @param[out] max_fd maximum FD to update
85 * @param fd_setsize value of FD_SETSIZE
86 * @return true on success, false on error
87 */
88static bool
89urh_to_fdset (struct MHD_UpgradeResponseHandle *urh,
90 fd_set *rs,
91 fd_set *ws,
92 fd_set *es,
93 MHD_socket *max_fd,
94 unsigned int fd_setsize)
95{
96 const MHD_socket conn_sckt = urh->connection->socket_fd;
97 const MHD_socket mhd_sckt = urh->mhd.socket;
98 bool res = true;
99
100 /* Do not add to 'es' only if socket is closed
101 * or not used anymore. */
102 if (MHD_INVALID_SOCKET != conn_sckt)
103 {
104 if ( (urh->in_buffer_used < urh->in_buffer_size) &&
105 (! MHD_add_to_fd_set_ (conn_sckt,
106 rs,
107 max_fd,
108 fd_setsize)) )
109 res = false;
110 if ( (0 != urh->out_buffer_used) &&
111 (! MHD_add_to_fd_set_ (conn_sckt,
112 ws,
113 max_fd,
114 fd_setsize)) )
115 res = false;
116 /* Do not monitor again for errors if error was detected before as
117 * error state is remembered. */
118 if ((0 == (urh->app.celi & MHD_EPOLL_STATE_ERROR)) &&
119 ((0 != urh->in_buffer_size) ||
120 (0 != urh->out_buffer_size) ||
121 (0 != urh->out_buffer_used)))
122 MHD_add_to_fd_set_ (conn_sckt,
123 es,
124 max_fd,
125 fd_setsize);
126 }
127 if (MHD_INVALID_SOCKET != mhd_sckt)
128 {
129 if ( (urh->out_buffer_used < urh->out_buffer_size) &&
130 (! MHD_add_to_fd_set_ (mhd_sckt,
131 rs,
132 max_fd,
133 fd_setsize)) )
134 res = false;
135 if ( (0 != urh->in_buffer_used) &&
136 (! MHD_add_to_fd_set_ (mhd_sckt,
137 ws,
138 max_fd,
139 fd_setsize)) )
140 res = false;
141 /* Do not monitor again for errors if error was detected before as
142 * error state is remembered. */
143 if ((0 == (urh->mhd.celi & MHD_EPOLL_STATE_ERROR)) &&
144 ((0 != urh->out_buffer_size) ||
145 (0 != urh->in_buffer_size) ||
146 (0 != urh->in_buffer_used)))
147 MHD_add_to_fd_set_ (mhd_sckt,
148 es,
149 max_fd,
150 fd_setsize);
151 }
152
153 return res;
154}
155#endif
156
157
158/**
159 * Internal version of #MHD_daemon_get_fdset2().
160 *
161 * @param daemon daemon to get sets from
162 * @param read_fd_set read set
163 * @param write_fd_set write set
164 * @param except_fd_set except set
165 * @param max_fd increased to largest FD added (if larger
166 * than existing value); can be NULL
167 * @param fd_setsize value of FD_SETSIZE
168 * @return #MHD_SC_OK on success
169 * @ingroup event
170 */
171static enum MHD_StatusCode
172internal_get_fdset2 (struct MHD_Daemon *daemon,
173 fd_set *read_fd_set,
174 fd_set *write_fd_set,
175 fd_set *except_fd_set,
176 MHD_socket *max_fd,
177 unsigned int fd_setsize)
178
179{
180 struct MHD_Connection *pos;
181 struct MHD_Connection *posn;
182 enum MHD_StatusCode result = MHD_SC_OK;
183 MHD_socket ls;
184
185 if (daemon->shutdown)
186 return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
187
188 ls = daemon->listen_socket;
189 if ( (MHD_INVALID_SOCKET != ls) &&
190 (! daemon->was_quiesced) &&
191 (! MHD_add_to_fd_set_ (ls,
192 read_fd_set,
193 max_fd,
194 fd_setsize)) )
195 result = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
196
197 /* Add all sockets to 'except_fd_set' as well to watch for
198 * out-of-band data. However, ignore errors if INFO_READ
199 * or INFO_WRITE sockets will not fit 'except_fd_set'. */
200 /* Start from oldest connections. Make sense for W32 FDSETs. */
201 for (pos = daemon->connections_tail; NULL != pos; pos = posn)
202 {
203 posn = pos->prev;
204
205 switch (pos->request.event_loop_info)
206 {
207 case MHD_EVENT_LOOP_INFO_READ:
208 if (! MHD_add_to_fd_set_ (pos->socket_fd,
209 read_fd_set,
210 max_fd,
211 fd_setsize))
212 result = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
213#ifdef MHD_POSIX_SOCKETS
214 MHD_add_to_fd_set_ (pos->socket_fd,
215 except_fd_set,
216 max_fd,
217 fd_setsize);
218#endif /* MHD_POSIX_SOCKETS */
219 break;
220 case MHD_EVENT_LOOP_INFO_WRITE:
221 if (! MHD_add_to_fd_set_ (pos->socket_fd,
222 write_fd_set,
223 max_fd,
224 fd_setsize))
225 result = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
226#ifdef MHD_POSIX_SOCKETS
227 MHD_add_to_fd_set_ (pos->socket_fd,
228 except_fd_set,
229 max_fd,
230 fd_setsize);
231#endif /* MHD_POSIX_SOCKETS */
232 break;
233 case MHD_EVENT_LOOP_INFO_BLOCK:
234 if ( (NULL == except_fd_set) ||
235 ! MHD_add_to_fd_set_ (pos->socket_fd,
236 except_fd_set,
237 max_fd,
238 fd_setsize))
239 result = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
240 break;
241 case MHD_EVENT_LOOP_INFO_CLEANUP:
242 /* this should never happen */
243 break;
244 }
245 }
246#ifdef MHD_WINSOCK_SOCKETS
247 /* W32 use limited array for fd_set so add INFO_READ/INFO_WRITE sockets
248 * only after INFO_BLOCK sockets to ensure that INFO_BLOCK sockets will
249 * not be pushed out. */
250 for (pos = daemon->connections_tail; NULL != pos; pos = posn)
251 {
252 posn = pos->prev;
253 MHD_add_to_fd_set_ (pos->socket_fd,
254 except_fd_set,
255 max_fd,
256 fd_setsize);
257 }
258#endif /* MHD_WINSOCK_SOCKETS */
259#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
260 {
261 struct MHD_UpgradeResponseHandle *urh;
262
263 for (urh = daemon->urh_tail; NULL != urh; urh = urh->prev)
264 {
265 if (! urh_to_fdset (urh,
266 read_fd_set,
267 write_fd_set,
268 except_fd_set,
269 max_fd,
270 fd_setsize))
271 result = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
272 }
273 }
274#endif
275 return result;
276}
277
278
279/**
280 * Obtain the `select()` sets for this daemon. Daemon's FDs will be
281 * added to fd_sets. To get only daemon FDs in fd_sets, call FD_ZERO
282 * for each fd_set before calling this function.
283 *
284 * Passing custom FD_SETSIZE as @a fd_setsize allow usage of
285 * larger/smaller than platform's default fd_sets.
286 *
287 * This function should only be called in when MHD is configured to
288 * use external select with 'select()' or with 'epoll'. In the latter
289 * case, it will only add the single 'epoll' file descriptor used by
290 * MHD to the sets. It's necessary to use #MHD_get_timeout() in
291 * combination with this function.
292 *
293 * This function must be called only for daemon started
294 * without #MHD_USE_INTERNAL_POLLING_THREAD flag.
295 *
296 * @param daemon daemon to get sets from
297 * @param read_fd_set read set
298 * @param write_fd_set write set
299 * @param except_fd_set except set
300 * @param max_fd increased to largest FD added (if larger
301 * than existing value); can be NULL
302 * @param fd_setsize value of FD_SETSIZE
303 * @return #MHD_SC_OK on success, otherwise error code
304 * @ingroup event
305 */
306enum MHD_StatusCode
307MHD_daemon_get_fdset2 (struct MHD_Daemon *daemon,
308 fd_set *read_fd_set,
309 fd_set *write_fd_set,
310 fd_set *except_fd_set,
311 MHD_socket *max_fd,
312 unsigned int fd_setsize)
313{
314 if ( (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) ||
315 (MHD_ELS_POLL == daemon->event_loop_syscall) )
316 return MHD_SC_CONFIGURATION_MISSMATCH_FOR_GET_FDSET;
317
318#ifdef EPOLL_SUPPORT
319 if (MHD_ELS_EPOLL == daemon->event_loop_syscall)
320 {
321 if (daemon->shutdown)
322 return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
323
324 /* we're in epoll mode, use the epoll FD as a stand-in for
325 the entire event set */
326
327 return MHD_add_to_fd_set_ (daemon->epoll_fd,
328 read_fd_set,
329 max_fd,
330 fd_setsize)
331 ? MHD_SC_OK
332 : MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
333 }
334#endif
335
336 return internal_get_fdset2 (daemon,
337 read_fd_set,
338 write_fd_set,
339 except_fd_set,
340 max_fd,
341 fd_setsize);
342}
343
344
345/**
346 * Update the @a urh based on the ready FDs in
347 * the @a rs, @a ws, and @a es.
348 *
349 * @param urh upgrade handle to update
350 * @param rs read result from select()
351 * @param ws write result from select()
352 * @param es except result from select()
353 */
354static void
355urh_from_fdset (struct MHD_UpgradeResponseHandle *urh,
356 const fd_set *rs,
357 const fd_set *ws,
358 const fd_set *es)
359{
360 const MHD_socket conn_sckt = urh->connection->socket_fd;
361 const MHD_socket mhd_sckt = urh->mhd.socket;
362
363 /* Reset read/write ready, preserve error state. */
364 urh->app.celi &= (~MHD_EPOLL_STATE_READ_READY & ~MHD_EPOLL_STATE_WRITE_READY);
365 urh->mhd.celi &= (~MHD_EPOLL_STATE_READ_READY & ~MHD_EPOLL_STATE_WRITE_READY);
366
367 if (MHD_INVALID_SOCKET != conn_sckt)
368 {
369 if (FD_ISSET (conn_sckt, rs))
370 urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
371 if (FD_ISSET (conn_sckt, ws))
372 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
373 if (FD_ISSET (conn_sckt, es))
374 urh->app.celi |= MHD_EPOLL_STATE_ERROR;
375 }
376 if ((MHD_INVALID_SOCKET != mhd_sckt))
377 {
378 if (FD_ISSET (mhd_sckt, rs))
379 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
380 if (FD_ISSET (mhd_sckt, ws))
381 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
382 if (FD_ISSET (mhd_sckt, es))
383 urh->mhd.celi |= MHD_EPOLL_STATE_ERROR;
384 }
385}
386
387
388/**
389 * Internal version of #MHD_run_from_select().
390 *
391 * @param daemon daemon to run select loop for
392 * @param read_fd_set read set
393 * @param write_fd_set write set
394 * @param except_fd_set except set
395 * @return #MHD_SC_OK on success
396 * @ingroup event
397 */
398static enum MHD_StatusCode
399internal_run_from_select (struct MHD_Daemon *daemon,
400 const fd_set *read_fd_set,
401 const fd_set *write_fd_set,
402 const fd_set *except_fd_set)
403{
404 MHD_socket ds;
405 struct MHD_Connection *pos;
406 struct MHD_Connection *prev;
407#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
408 struct MHD_UpgradeResponseHandle *urh;
409 struct MHD_UpgradeResponseHandle *urhn;
410#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
411 /* Reset. New value will be set when connections are processed. */
412 /* Note: no-op for thread-per-connection as it is always false in that mode. */
413 daemon->data_already_pending = false;
414
415 /* Clear ITC to avoid spinning select */
416 /* Do it before any other processing so new signals
417 will trigger select again and will be processed */
418 if ( (MHD_ITC_IS_VALID_(daemon->itc)) &&
419 (FD_ISSET (MHD_itc_r_fd_ (daemon->itc),
420 read_fd_set)) )
421 MHD_itc_clear_ (daemon->itc);
422
423 /* select connection thread handling type */
424 if ( (MHD_INVALID_SOCKET != (ds = daemon->listen_socket)) &&
425 (! daemon->was_quiesced) &&
426 (FD_ISSET (ds,
427 read_fd_set)) )
428 (void) MHD_accept_connection (daemon);
429
430 if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model)
431 {
432 /* do not have a thread per connection, process all connections now */
433 prev = daemon->connections_tail;
434 while (NULL != (pos = prev))
435 {
436 prev = pos->prev;
437 ds = pos->socket_fd;
438 if (MHD_INVALID_SOCKET == ds)
439 continue;
440 call_handlers (pos,
441 FD_ISSET (ds,
442 read_fd_set),
443 FD_ISSET (ds,
444 write_fd_set),
445 FD_ISSET (ds,
446 except_fd_set));
447 }
448 }
449
450#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
451 /* handle upgraded HTTPS connections */
452 for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
453 {
454 urhn = urh->prev;
455 /* update urh state based on select() output */
456 urh_from_fdset (urh,
457 read_fd_set,
458 write_fd_set,
459 except_fd_set);
460 /* call generic forwarding function for passing data */
461 process_urh (urh);
462 /* Finished forwarding? */
463 if ( (0 == urh->in_buffer_size) &&
464 (0 == urh->out_buffer_size) &&
465 (0 == urh->in_buffer_used) &&
466 (0 == urh->out_buffer_used) )
467 {
468 MHD_connection_finish_forward_ (urh->connection);
469 urh->clean_ready = true;
470 /* Resuming will move connection to cleanup list. */
471 MHD_resume_connection(urh->connection);
472 }
473 }
474#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
475 MHD_cleanup_connections (daemon);
476 return MHD_SC_OK;
477}
478
479
480/**
481 * Run webserver operations. This method should be called by clients
482 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
483 * client-controlled select method is used.
484 *
485 * You can use this function instead of #MHD_run if you called
486 * `select()` on the result from #MHD_get_fdset. File descriptors in
487 * the sets that are not controlled by MHD will be ignored. Calling
488 * this function instead of #MHD_run is more efficient as MHD will not
489 * have to call `select()` again to determine which operations are
490 * ready.
491 *
492 * This function cannot be used with daemon started with
493 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
494 *
495 * @param daemon daemon to run select loop for
496 * @param read_fd_set read set
497 * @param write_fd_set write set
498 * @param except_fd_set except set
499 * @return #MHD_SC_OK on success
500 * @ingroup event
501 */
502enum MHD_StatusCode
503MHD_daemon_run_from_select (struct MHD_Daemon *daemon,
504 const fd_set *read_fd_set,
505
506 const fd_set *write_fd_set,
507 const fd_set *except_fd_set)
508{
509 if ( (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) ||
510 (MHD_ELS_POLL == daemon->event_loop_syscall) )
511 return MHD_SC_CONFIGURATION_MISSMATCH_FOR_RUN_SELECT;
512 if (MHD_ELS_EPOLL == daemon->event_loop_syscall)
513 {
514#ifdef EPOLL_SUPPORT
515 enum MHD_StatusCode sc;
516
517 sc = MHD_daemon_epoll_ (daemon,
518 MHD_NO);
519 MHD_cleanup_connections (daemon);
520 return sc;
521#else /* ! EPOLL_SUPPORT */
522 return MHD_NO;
523#endif /* ! EPOLL_SUPPORT */
524 }
525
526 /* Resuming external connections when using an extern mainloop */
527 if (! daemon->disallow_suspend_resume)
528 resume_suspended_connections (daemon);
529
530 return internal_run_from_select (daemon,
531 read_fd_set,
532 write_fd_set,
533 except_fd_set);
534}
535
536
537/**
538 * Main internal select() call. Will compute select sets, call
539 * select() and then #internal_run_from_select() with the result.
540 *
541 * @param daemon daemon to run select() loop for
542 * @param may_block #MHD_YES if blocking, #MHD_NO if non-blocking
543 * @return #MHD_SC_OK on success
544 */
545enum MHD_StatusCode
546MHD_daemon_select_ (struct MHD_Daemon *daemon,
547 int may_block)
548{
549 int num_ready;
550 fd_set rs;
551 fd_set ws;
552 fd_set es;
553 MHD_socket maxsock;
554 struct timeval timeout;
555 struct timeval *tv;
556 MHD_UNSIGNED_LONG_LONG ltimeout;
557 int err_state;
558 MHD_socket ls;
559 enum MHD_StatusCode sc;
560 enum MHD_StatusCode sc2;
561
562 timeout.tv_sec = 0;
563 timeout.tv_usec = 0;
564 if (daemon->shutdown)
565 return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
566 FD_ZERO (&rs);
567 FD_ZERO (&ws);
568 FD_ZERO (&es);
569 maxsock = MHD_INVALID_SOCKET;
570 sc = MHD_SC_OK;
571 if ( (! daemon->disallow_suspend_resume) &&
572 (MHD_YES == resume_suspended_connections (daemon)) &&
573 (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) )
574 may_block = MHD_NO;
575
576 if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model)
577 {
578
579 /* single-threaded, go over everything */
580 if (MHD_SC_OK !=
581 (sc = internal_get_fdset2 (daemon,
582 &rs,
583 &ws,
584 &es,
585 &maxsock,
586 FD_SETSIZE)))
587 {
588#ifdef HAVE_MESSAGES
589 MHD_DLOG (daemon,
590 sc,
591 _("Could not obtain daemon fdsets"));
592#endif
593 }
594 }
595 else
596 {
597 /* accept only, have one thread per connection */
598 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
599 (! daemon->was_quiesced) &&
600 (! MHD_add_to_fd_set_ (ls,
601 &rs,
602 &maxsock,
603 FD_SETSIZE)) )
604 {
605#ifdef HAVE_MESSAGES
606 MHD_DLOG (daemon,
607 MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE,
608 _("Could not add listen socket to fdset"));
609#endif
610 return MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
611 }
612 }
613 if ( (MHD_ITC_IS_VALID_(daemon->itc)) &&
614 (! MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc),
615 &rs,
616 &maxsock,
617 FD_SETSIZE)) )
618 {
619#if defined(MHD_WINSOCK_SOCKETS)
620 /* fdset limit reached, new connections
621 cannot be handled. Remove listen socket FD
622 from fdset and retry to add ITC FD. */
623 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
624 (! daemon->was_quiesced) )
625 {
626 FD_CLR (ls,
627 &rs);
628 if (! MHD_add_to_fd_set_ (MHD_itc_r_fd_(daemon->itc),
629 &rs,
630 &maxsock,
631 FD_SETSIZE))
632 {
633#endif /* MHD_WINSOCK_SOCKETS */
634 sc = MHD_SC_SOCKET_OUTSIDE_OF_FDSET_RANGE;
635#ifdef HAVE_MESSAGES
636 MHD_DLOG (daemon,
637 sc,
638 _("Could not add control inter-thread communication channel FD to fdset"));
639#endif
640#if defined(MHD_WINSOCK_SOCKETS)
641 }
642 }
643#endif /* MHD_WINSOCK_SOCKETS */
644 }
645 /* Stop listening if we are at the configured connection limit */
646 /* If we're at the connection limit, no point in really
647 accepting new connections; however, make sure we do not miss
648 the shutdown OR the termination of an existing connection; so
649 only do this optimization if we have a signaling ITC in
650 place. */
651 if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_socket)) &&
652 (MHD_ITC_IS_VALID_(daemon->itc)) &&
653 ( (daemon->connections == daemon->global_connection_limit) ||
654 (daemon->at_limit) ) )
655 {
656 FD_CLR (ls,
657 &rs);
658 }
659 tv = NULL;
660 if (MHD_SC_OK != sc)
661 may_block = MHD_NO;
662 if (MHD_NO == may_block)
663 {
664 timeout.tv_usec = 0;
665 timeout.tv_sec = 0;
666 tv = &timeout;
667 }
668 else if ( (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) &&
669 (MHD_SC_OK ==
670 MHD_daemon_get_timeout (daemon,
671 &ltimeout)) )
672 {
673 /* ltimeout is in ms */
674 timeout.tv_usec = (ltimeout % 1000) * 1000;
675 if (ltimeout / 1000 > TIMEVAL_TV_SEC_MAX)
676 timeout.tv_sec = TIMEVAL_TV_SEC_MAX;
677 else
678 timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE)(ltimeout / 1000);
679 tv = &timeout;
680 }
681 num_ready = MHD_SYS_select_ (maxsock + 1,
682 &rs,
683 &ws,
684 &es,
685 tv);
686 if (daemon->shutdown)
687 return MHD_SC_DAEMON_ALREADY_SHUTDOWN;
688 if (num_ready < 0)
689 {
690 const int err = MHD_socket_get_error_ ();
691
692 if (MHD_SCKT_ERR_IS_EINTR_(err))
693 return sc;
694#ifdef HAVE_MESSAGES
695 MHD_DLOG (daemon,
696 MHD_SC_UNEXPECTED_SELECT_ERROR,
697 _("select failed: %s\n"),
698 MHD_socket_strerr_ (err));
699#endif
700 return MHD_SC_UNEXPECTED_SELECT_ERROR;
701 }
702 if (MHD_SC_OK !=
703 (sc2 = internal_run_from_select (daemon,
704 &rs,
705 &ws,
706 &es)))
707 return sc2;
708 return sc;
709}
710
711/* end of daemon_select.c */