aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2023-11-08 17:58:04 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2023-11-08 20:15:01 +0300
commit32eae456fddba5b48d08f44dda956a0ea1ffffea (patch)
tree94eee654f7ede3adcd44b64e87241d6653e013ae
parent09b7e335d8adc36926543305f3ee8d1b4961b0ab (diff)
downloadlibmicrohttpd-32eae456fddba5b48d08f44dda956a0ea1ffffea.tar.gz
libmicrohttpd-32eae456fddba5b48d08f44dda956a0ea1ffffea.zip
Added new function MHD_run_from_select2() with FD_SETSIZE value
Added wrapper macro MHD_run_from_select() to automatically use current FD_SETSIZE value. This should complete the support for flexible FD_SETSIZE (which is used on most platforms with GNU/Linux as notable exception). This also fixes potential fd_set overrun when sockets with too large numbers are used.
-rw-r--r--src/include/microhttpd.h72
-rw-r--r--src/microhttpd/daemon.c323
-rw-r--r--src/microhttpd/mhd_sockets.c2
-rw-r--r--src/microhttpd/mhd_sockets.h2
4 files changed, 328 insertions, 71 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 221d24fc..9e7e23e2 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -3387,6 +3387,78 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
3387 const fd_set *except_fd_set); 3387 const fd_set *except_fd_set);
3388 3388
3389 3389
3390/**
3391 * Run webserver operations. This method should be called by clients
3392 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
3393 * client-controlled select method is used.
3394 * This function specifies FD_SETSIZE used when provided fd_sets were
3395 * created. It is important on platforms where FD_SETSIZE can be
3396 * overridden.
3397 *
3398 * You can use this function instead of #MHD_run if you called
3399 * 'select()' on the result from #MHD_get_fdset2(). File descriptors in
3400 * the sets that are not controlled by MHD will be ignored. Calling
3401 * this function instead of #MHD_run() is more efficient as MHD will
3402 * not have to call 'select()' again to determine which operations are
3403 * ready.
3404 *
3405 * If #MHD_get_timeout() returned #MHD_YES, than this function must be
3406 * called right after 'select()' returns regardless of detected activity
3407 * on the daemon's FDs.
3408 *
3409 * This function cannot be used with daemon started with
3410 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
3411 *
3412 * @param daemon the daemon to run select loop for
3413 * @param read_fd_set the read set
3414 * @param write_fd_set the write set
3415 * @param except_fd_set the except set
3416 * @param fd_setsize the value of FD_SETSIZE
3417 * @return #MHD_NO on serious errors, #MHD_YES on success
3418 * @sa #MHD_get_fdset2(), #MHD_OPTION_APP_FD_SETSIZE
3419 * @ingroup event
3420 */
3421_MHD_EXTERN enum MHD_Result
3422MHD_run_from_select2 (struct MHD_Daemon *daemon,
3423 const fd_set *read_fd_set,
3424 const fd_set *write_fd_set,
3425 const fd_set *except_fd_set,
3426 unsigned int fd_setsize);
3427
3428
3429/**
3430 * Run webserver operations. This method should be called by clients
3431 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
3432 * client-controlled select method is used.
3433 * This macro automatically substitutes current FD_SETSIZE value.
3434 * It is important on platforms where FD_SETSIZE can be overridden.
3435 *
3436 * You can use this function instead of #MHD_run if you called
3437 * 'select()' on the result from #MHD_get_fdset2(). File descriptors in
3438 * the sets that are not controlled by MHD will be ignored. Calling
3439 * this function instead of #MHD_run() is more efficient as MHD will
3440 * not have to call 'select()' again to determine which operations are
3441 * ready.
3442 *
3443 * If #MHD_get_timeout() returned #MHD_YES, than this function must be
3444 * called right after 'select()' returns regardless of detected activity
3445 * on the daemon's FDs.
3446 *
3447 * This function cannot be used with daemon started with
3448 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
3449 *
3450 * @param daemon the daemon to run select loop for
3451 * @param read_fd_set the read set
3452 * @param write_fd_set the write set
3453 * @param except_fd_set the except set
3454 * @param fd_setsize the value of FD_SETSIZE
3455 * @return #MHD_NO on serious errors, #MHD_YES on success
3456 * @sa #MHD_get_fdset2(), #MHD_OPTION_APP_FD_SETSIZE
3457 * @ingroup event
3458 */
3459#define MHD_run_from_select(d,r,w,e) \
3460 MHD_run_from_select2((d),(r),(w),(e),(unsigned int)(FD_SETSIZE))
3461
3390/* **************** Connection handling functions ***************** */ 3462/* **************** Connection handling functions ***************** */
3391 3463
3392/** 3464/**
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 2489728f..d8151bea 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -726,7 +726,7 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh,
726 fd_set *ws, 726 fd_set *ws,
727 fd_set *es, 727 fd_set *es,
728 MHD_socket *max_fd, 728 MHD_socket *max_fd,
729 unsigned int fd_setsize) 729 int fd_setsize)
730{ 730{
731 const MHD_socket conn_sckt = urh->connection->socket_fd; 731 const MHD_socket conn_sckt = urh->connection->socket_fd;
732 const MHD_socket mhd_sckt = urh->mhd.socket; 732 const MHD_socket mhd_sckt = urh->mhd.socket;
@@ -799,12 +799,14 @@ urh_to_fdset (struct MHD_UpgradeResponseHandle *urh,
799 * @param rs read result from select() 799 * @param rs read result from select()
800 * @param ws write result from select() 800 * @param ws write result from select()
801 * @param es except result from select() 801 * @param es except result from select()
802 * @param fd_setsize value of FD_SETSIZE used when fd_sets were created
802 */ 803 */
803static void 804static void
804urh_from_fdset (struct MHD_UpgradeResponseHandle *urh, 805urh_from_fdset (struct MHD_UpgradeResponseHandle *urh,
805 const fd_set *rs, 806 const fd_set *rs,
806 const fd_set *ws, 807 const fd_set *ws,
807 const fd_set *es) 808 const fd_set *es,
809 int fd_setsize)
808{ 810{
809 const MHD_socket conn_sckt = urh->connection->socket_fd; 811 const MHD_socket conn_sckt = urh->connection->socket_fd;
810 const MHD_socket mhd_sckt = urh->mhd.socket; 812 const MHD_socket mhd_sckt = urh->mhd.socket;
@@ -815,25 +817,49 @@ urh_from_fdset (struct MHD_UpgradeResponseHandle *urh,
815 urh->mhd.celi &= (~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY) 817 urh->mhd.celi &= (~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY)
816 & ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY)); 818 & ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY));
817 819
820 mhd_assert (urh->connection->sk_nonblck);
821
822#ifndef HAS_FD_SETSIZE_OVERRIDABLE
823 (void) fd_setsize; /* Mute compiler warning */
824 mhd_assert (((int) FD_SETSIZE) <= fd_setsize);
825 fd_setsize = FD_SETSIZE; /* Help compiler to optimise */
826#endif /* ! HAS_FD_SETSIZE_OVERRIDABLE */
827
818 if (MHD_INVALID_SOCKET != conn_sckt) 828 if (MHD_INVALID_SOCKET != conn_sckt)
819 { 829 {
820 if (FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (rs))) 830 if (MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (conn_sckt, NULL, fd_setsize))
831 {
832 if (FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (rs)))
833 urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
834 if (FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (ws)))
835 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
836 if ((NULL != es) &&
837 FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (es)))
838 urh->app.celi |= MHD_EPOLL_STATE_ERROR;
839 }
840 else
841 { /* Cannot check readiness. Force ready state is safe as socket is non-blocking */
821 urh->app.celi |= MHD_EPOLL_STATE_READ_READY; 842 urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
822 if (FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (ws)))
823 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; 843 urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY;
824 if ((NULL != es) && 844 }
825 FD_ISSET (conn_sckt, (fd_set *) _MHD_DROP_CONST (es)))
826 urh->app.celi |= MHD_EPOLL_STATE_ERROR;
827 } 845 }
828 if ((MHD_INVALID_SOCKET != mhd_sckt)) 846 if ((MHD_INVALID_SOCKET != mhd_sckt))
829 { 847 {
830 if (FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (rs))) 848 if (MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (mhd_sckt, NULL, fd_setsize))
849 {
850 if (FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (rs)))
851 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
852 if (FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (ws)))
853 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
854 if ((NULL != es) &&
855 FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (es)))
856 urh->mhd.celi |= MHD_EPOLL_STATE_ERROR;
857 }
858 else
859 { /* Cannot check readiness. Force ready state is safe as socket is non-blocking */
831 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; 860 urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
832 if (FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (ws)))
833 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; 861 urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY;
834 if ((NULL != es) && 862 }
835 FD_ISSET (mhd_sckt, (fd_set *) _MHD_DROP_CONST (es)))
836 urh->mhd.celi |= MHD_EPOLL_STATE_ERROR;
837 } 863 }
838} 864}
839 865
@@ -958,7 +984,7 @@ internal_get_fdset2 (struct MHD_Daemon *daemon,
958 fd_set *write_fd_set, 984 fd_set *write_fd_set,
959 fd_set *except_fd_set, 985 fd_set *except_fd_set,
960 MHD_socket *max_fd, 986 MHD_socket *max_fd,
961 unsigned int fd_setsize) 987 int fd_setsize)
962{ 988{
963 struct MHD_Connection *pos; 989 struct MHD_Connection *pos;
964 struct MHD_Connection *posn; 990 struct MHD_Connection *posn;
@@ -1186,7 +1212,7 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon,
1186 return MHD_add_to_fd_set_ (daemon->epoll_fd, 1212 return MHD_add_to_fd_set_ (daemon->epoll_fd,
1187 read_fd_set, 1213 read_fd_set,
1188 max_fd, 1214 max_fd,
1189 fd_setsize) ? MHD_YES : MHD_NO; 1215 (int) fd_setsize) ? MHD_YES : MHD_NO;
1190 } 1216 }
1191#endif 1217#endif
1192 1218
@@ -1195,7 +1221,7 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon,
1195 write_fd_set, 1221 write_fd_set,
1196 except_fd_set, 1222 except_fd_set,
1197 max_fd, 1223 max_fd,
1198 fd_setsize); 1224 (int) fd_setsize);
1199} 1225}
1200 1226
1201 1227
@@ -1806,7 +1832,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con)
1806 urh_from_fdset (urh, 1832 urh_from_fdset (urh,
1807 &rs, 1833 &rs,
1808 &ws, 1834 &ws,
1809 &es); 1835 &es,
1836 (int) FD_SETSIZE);
1810 process_urh (urh); 1837 process_urh (urh);
1811 } 1838 }
1812 } 1839 }
@@ -4372,7 +4399,8 @@ get_timeout_millisec_int (struct MHD_Daemon *daemon,
4372 * @param daemon daemon to run select loop for 4399 * @param daemon daemon to run select loop for
4373 * @param read_fd_set read set 4400 * @param read_fd_set read set
4374 * @param write_fd_set write set 4401 * @param write_fd_set write set
4375 * @param except_fd_set except set (not used, can be NULL) 4402 * @param except_fd_set except set
4403 * @param fd_setsize value of FD_SETSIZE used when fd_sets were created
4376 * @return #MHD_NO on serious errors, #MHD_YES on success 4404 * @return #MHD_NO on serious errors, #MHD_YES on success
4377 * @ingroup event 4405 * @ingroup event
4378 */ 4406 */
@@ -4380,26 +4408,14 @@ static enum MHD_Result
4380internal_run_from_select (struct MHD_Daemon *daemon, 4408internal_run_from_select (struct MHD_Daemon *daemon,
4381 const fd_set *read_fd_set, 4409 const fd_set *read_fd_set,
4382 const fd_set *write_fd_set, 4410 const fd_set *write_fd_set,
4383 const fd_set *except_fd_set) 4411 const fd_set *except_fd_set,
4412 int fd_setsize)
4384{ 4413{
4385 MHD_socket ds; 4414 MHD_socket ds;
4386 struct MHD_Connection *pos;
4387 struct MHD_Connection *prev;
4388#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) 4415#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
4389 struct MHD_UpgradeResponseHandle *urh; 4416 struct MHD_UpgradeResponseHandle *urh;
4390 struct MHD_UpgradeResponseHandle *urhn; 4417 struct MHD_UpgradeResponseHandle *urhn;
4391#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ 4418#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
4392 /* Reset. New value will be set when connections are processed. */
4393 /* Note: no-op for thread-per-connection as it is always false in that mode. */
4394 daemon->data_already_pending = false;
4395
4396 /* Clear ITC to avoid spinning select */
4397 /* Do it before any other processing so new signals
4398 will trigger select again and will be processed */
4399 if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
4400 (FD_ISSET (MHD_itc_r_fd_ (daemon->itc),
4401 (fd_set *) _MHD_DROP_CONST (read_fd_set))) )
4402 MHD_itc_clear_ (daemon->itc);
4403 4419
4404 mhd_assert ((0 == (daemon->options & MHD_USE_SELECT_INTERNALLY)) || \ 4420 mhd_assert ((0 == (daemon->options & MHD_USE_SELECT_INTERNALLY)) || \
4405 (MHD_thread_handle_ID_is_valid_ID_ (daemon->tid))); 4421 (MHD_thread_handle_ID_is_valid_ID_ (daemon->tid)));
@@ -4408,36 +4424,86 @@ internal_run_from_select (struct MHD_Daemon *daemon,
4408 mhd_assert ((0 == (daemon->options & MHD_USE_SELECT_INTERNALLY)) || \ 4424 mhd_assert ((0 == (daemon->options & MHD_USE_SELECT_INTERNALLY)) || \
4409 (MHD_thread_handle_ID_is_current_thread_ (daemon->tid))); 4425 (MHD_thread_handle_ID_is_current_thread_ (daemon->tid)));
4410 4426
4427 mhd_assert (0 < fd_setsize);
4428#ifndef HAS_FD_SETSIZE_OVERRIDABLE
4429 (void) fd_setsize; /* Mute compiler warning */
4430 mhd_assert (((int) FD_SETSIZE) <= fd_setsize);
4431 fd_setsize = FD_SETSIZE; /* Help compiler to optimise */
4432#endif /* ! HAS_FD_SETSIZE_OVERRIDABLE */
4433
4434 /* Clear ITC to avoid spinning select */
4435 /* Do it before any other processing so new signals
4436 will trigger select again and will be processed */
4437 if (MHD_ITC_IS_VALID_ (daemon->itc))
4438 { /* Have ITC */
4439 bool need_to_clear_itc = true; /* ITC is always non-blocking, it is safe to clear even if ITC not activated */
4440 if (MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (MHD_itc_r_fd_ (daemon->itc),
4441 NULL, fd_setsize))
4442 need_to_clear_itc = FD_ISSET (MHD_itc_r_fd_ (daemon->itc), \
4443 (fd_set *) _MHD_DROP_CONST (read_fd_set)); /* Skip clearing, if not needed */
4444 if (need_to_clear_itc)
4445 MHD_itc_clear_ (daemon->itc);
4446 }
4447
4448 /* Reset. New value will be set when connections are processed. */
4449 /* Note: no-op for thread-per-connection as it is always false in that mode. */
4450 daemon->data_already_pending = false;
4451
4411 /* Process externally added connection if any */ 4452 /* Process externally added connection if any */
4412 if (daemon->have_new) 4453 if (daemon->have_new)
4413 new_connections_list_process_ (daemon); 4454 new_connections_list_process_ (daemon);
4414 4455
4415 /* select connection thread handling type */ 4456 /* select connection thread handling type */
4416 if ( (MHD_INVALID_SOCKET != (ds = daemon->listen_fd)) && 4457 ds = daemon->listen_fd;
4417 (! daemon->was_quiesced) && 4458 if ( (MHD_INVALID_SOCKET != ds) &&
4418 (FD_ISSET (ds, 4459 (! daemon->was_quiesced) )
4419 (fd_set *) _MHD_DROP_CONST (read_fd_set))) ) 4460 {
4420 (void) MHD_accept_connection (daemon); 4461 bool need_to_accept;
4462 if (MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (ds, NULL, fd_setsize))
4463 need_to_accept = FD_ISSET (ds,
4464 (fd_set *) _MHD_DROP_CONST (read_fd_set));
4465 else /* Cannot check whether new connection are pending */
4466 need_to_accept = daemon->listen_nonblk; /* Try to accept if non-blocking */
4421 4467
4422 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 4468 if (need_to_accept)
4469 (void) MHD_accept_connection (daemon);
4470 }
4471
4472 if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
4423 { 4473 {
4424 /* do not have a thread per connection, process all connections now */ 4474 /* do not have a thread per connection, process all connections now */
4425 prev = daemon->connections_tail; 4475 struct MHD_Connection *pos;
4426 while (NULL != (pos = prev)) 4476 for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
4427 { 4477 {
4428 prev = pos->prev; 4478 MHD_socket cs;
4429 ds = pos->socket_fd; 4479 bool r_ready;
4430 if (MHD_INVALID_SOCKET == ds) 4480 bool w_ready;
4481 bool has_err;
4482
4483 cs = pos->socket_fd;
4484 if (MHD_INVALID_SOCKET == cs)
4431 continue; 4485 continue;
4486
4487 if (MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (cs, NULL, fd_setsize))
4488 {
4489 r_ready = FD_ISSET (cs,
4490 (fd_set *) _MHD_DROP_CONST (read_fd_set));
4491 w_ready = FD_ISSET (cs,
4492 (fd_set *) _MHD_DROP_CONST (write_fd_set));
4493 has_err = (NULL != except_fd_set) &&
4494 FD_ISSET (cs,
4495 (fd_set *) _MHD_DROP_CONST (except_fd_set));
4496 }
4497 else
4498 { /* Cannot check the real readiness */
4499 r_ready = pos->sk_nonblck;
4500 w_ready = r_ready;
4501 has_err = false;
4502 }
4432 call_handlers (pos, 4503 call_handlers (pos,
4433 FD_ISSET (ds, 4504 r_ready,
4434 (fd_set *) _MHD_DROP_CONST (read_fd_set)), 4505 w_ready,
4435 FD_ISSET (ds, 4506 has_err);
4436 (fd_set *) _MHD_DROP_CONST (write_fd_set)),
4437 (NULL != except_fd_set) ?
4438 (FD_ISSET (ds,
4439 (fd_set *) _MHD_DROP_CONST (except_fd_set))) :
4440 (false));
4441 } 4507 }
4442 } 4508 }
4443 4509
@@ -4450,7 +4516,8 @@ internal_run_from_select (struct MHD_Daemon *daemon,
4450 urh_from_fdset (urh, 4516 urh_from_fdset (urh,
4451 read_fd_set, 4517 read_fd_set,
4452 write_fd_set, 4518 write_fd_set,
4453 except_fd_set); 4519 except_fd_set,
4520 fd_setsize);
4454 /* call generic forwarding function for passing data */ 4521 /* call generic forwarding function for passing data */
4455 process_urh (urh); 4522 process_urh (urh);
4456 /* Finished forwarding? */ 4523 /* Finished forwarding? */
@@ -4471,37 +4538,45 @@ internal_run_from_select (struct MHD_Daemon *daemon,
4471} 4538}
4472 4539
4473 4540
4541#undef MHD_run_from_select
4542
4474/** 4543/**
4475 * Run webserver operations. This method should be called by clients 4544 * Run webserver operations. This method should be called by clients
4476 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the 4545 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
4477 * client-controlled select method is used. 4546 * client-controlled select method is used.
4547 * This function specifies FD_SETSIZE used when provided fd_sets were
4548 * created. It is important on platforms where FD_SETSIZE can be
4549 * overridden.
4478 * 4550 *
4479 * You can use this function instead of #MHD_run if you called 4551 * You can use this function instead of #MHD_run if you called
4480 * `select()` on the result from #MHD_get_fdset. File descriptors in 4552 * 'select()' on the result from #MHD_get_fdset2(). File descriptors in
4481 * the sets that are not controlled by MHD will be ignored. Calling 4553 * the sets that are not controlled by MHD will be ignored. Calling
4482 * this function instead of #MHD_run is more efficient as MHD will 4554 * this function instead of #MHD_run() is more efficient as MHD will
4483 * not have to call `select()` again to determine which operations are 4555 * not have to call 'select()' again to determine which operations are
4484 * ready. 4556 * ready.
4485 * 4557 *
4486 * If #MHD_get_timeout() returned #MHD_YES, than this function must be 4558 * If #MHD_get_timeout() returned #MHD_YES, than this function must be
4487 * called right after `select()` returns regardless of detected activity 4559 * called right after 'select()' returns regardless of detected activity
4488 * on the daemon's FDs. 4560 * on the daemon's FDs.
4489 * 4561 *
4490 * This function cannot be used with daemon started with 4562 * This function cannot be used with daemon started with
4491 * #MHD_USE_INTERNAL_POLLING_THREAD flag. 4563 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
4492 * 4564 *
4493 * @param daemon daemon to run select loop for 4565 * @param daemon the daemon to run select loop for
4494 * @param read_fd_set read set 4566 * @param read_fd_set the read set
4495 * @param write_fd_set write set 4567 * @param write_fd_set the write set
4496 * @param except_fd_set except set 4568 * @param except_fd_set the except set
4569 * @param fd_setsize the value of FD_SETSIZE
4497 * @return #MHD_NO on serious errors, #MHD_YES on success 4570 * @return #MHD_NO on serious errors, #MHD_YES on success
4571 * @sa #MHD_get_fdset2(), #MHD_OPTION_APP_FD_SETSIZE
4498 * @ingroup event 4572 * @ingroup event
4499 */ 4573 */
4500_MHD_EXTERN enum MHD_Result 4574_MHD_EXTERN enum MHD_Result
4501MHD_run_from_select (struct MHD_Daemon *daemon, 4575MHD_run_from_select2 (struct MHD_Daemon *daemon,
4502 const fd_set *read_fd_set, 4576 const fd_set *read_fd_set,
4503 const fd_set *write_fd_set, 4577 const fd_set *write_fd_set,
4504 const fd_set *except_fd_set) 4578 const fd_set *except_fd_set,
4579 unsigned int fd_setsize)
4505{ 4580{
4506 if (MHD_D_IS_USING_POLL_ (daemon) || 4581 if (MHD_D_IS_USING_POLL_ (daemon) ||
4507 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))) 4582 (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)))
@@ -4516,6 +4591,49 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
4516 "set to NULL. Such behavior is deprecated.\n")); 4591 "set to NULL. Such behavior is deprecated.\n"));
4517 } 4592 }
4518#endif /* HAVE_MESSAGES */ 4593#endif /* HAVE_MESSAGES */
4594
4595#ifdef HAS_FD_SETSIZE_OVERRIDABLE
4596 if (0 == fd_setsize)
4597 return MHD_NO;
4598 else if (((unsigned int) INT_MAX) < fd_setsize)
4599 fd_setsize = (unsigned int) INT_MAX;
4600#ifdef HAVE_MESSAGES
4601 else if (daemon->fdset_size > ((int) fd_setsize))
4602 {
4603 if (daemon->fdset_size_set_by_app)
4604 {
4605 MHD_DLOG (daemon,
4606 _ ("%s() called with fd_setsize (%u) " \
4607 "less than value set by MHD_OPTION_APP_FD_SETSIZE (%d). " \
4608 "Some socket FDs may be not processed. " \
4609 "Use MHD_OPTION_APP_FD_SETSIZE with the correct value.\n"),
4610 "MHD_run_from_select2", fd_setsize, daemon->fdset_size);
4611 }
4612 else
4613 {
4614 MHD_DLOG (daemon,
4615 _ ("%s() called with fd_setsize (%u) " \
4616 "less than FD_SETSIZE used by MHD (%d). " \
4617 "Some socket FDs may be not processed. " \
4618 "Consider using MHD_OPTION_APP_FD_SETSIZE option.\n"),
4619 "MHD_run_from_select2", fd_setsize, daemon->fdset_size);
4620 }
4621 }
4622#endif /* HAVE_MESSAGES */
4623#else /* ! HAS_FD_SETSIZE_OVERRIDABLE */
4624 if (((unsigned int) FD_SETSIZE) > fd_setsize)
4625 {
4626#ifdef HAVE_MESSAGES
4627 MHD_DLOG (daemon,
4628 _ ("%s() called with fd_setsize (%u) " \
4629 "less than fixed FD_SETSIZE value (%d) used on the " \
4630 "platform.\n", "MHD_run_from_select2"),
4631 fd_setsize, (int) FD_SETSIZE);
4632#endif /* HAVE_MESSAGES */
4633 return MHD_NO;
4634 }
4635#endif /* ! HAS_FD_SETSIZE_OVERRIDABLE */
4636
4519 if (MHD_D_IS_USING_EPOLL_ (daemon)) 4637 if (MHD_D_IS_USING_EPOLL_ (daemon))
4520 { 4638 {
4521#ifdef EPOLL_SUPPORT 4639#ifdef EPOLL_SUPPORT
@@ -4536,7 +4654,55 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
4536 return internal_run_from_select (daemon, 4654 return internal_run_from_select (daemon,
4537 read_fd_set, 4655 read_fd_set,
4538 write_fd_set, 4656 write_fd_set,
4539 except_fd_set); 4657 except_fd_set,
4658 (int) fd_setsize);
4659}
4660
4661
4662/**
4663 * Run webserver operations. This method should be called by clients
4664 * in combination with #MHD_get_fdset and #MHD_get_timeout() if the
4665 * client-controlled select method is used.
4666 *
4667 * You can use this function instead of #MHD_run if you called
4668 * `select()` on the result from #MHD_get_fdset. File descriptors in
4669 * the sets that are not controlled by MHD will be ignored. Calling
4670 * this function instead of #MHD_run is more efficient as MHD will
4671 * not have to call `select()` again to determine which operations are
4672 * ready.
4673 *
4674 * If #MHD_get_timeout() returned #MHD_YES, than this function must be
4675 * called right after `select()` returns regardless of detected activity
4676 * on the daemon's FDs.
4677 *
4678 * This function cannot be used with daemon started with
4679 * #MHD_USE_INTERNAL_POLLING_THREAD flag.
4680 *
4681 * @param daemon daemon to run select loop for
4682 * @param read_fd_set read set
4683 * @param write_fd_set write set
4684 * @param except_fd_set except set
4685 * @return #MHD_NO on serious errors, #MHD_YES on success
4686 * @ingroup event
4687 */
4688_MHD_EXTERN enum MHD_Result
4689MHD_run_from_select (struct MHD_Daemon *daemon,
4690 const fd_set *read_fd_set,
4691 const fd_set *write_fd_set,
4692 const fd_set *except_fd_set)
4693{
4694 return MHD_run_from_select2 (daemon,
4695 read_fd_set,
4696 write_fd_set,
4697 except_fd_set,
4698#ifdef HAS_FD_SETSIZE_OVERRIDABLE
4699 daemon->fdset_size_set_by_app ?
4700 ((unsigned int) daemon->fdset_size) :
4701 ((unsigned int) _MHD_SYS_DEFAULT_FD_SETSIZE)
4702#else /* ! HAS_FD_SETSIZE_OVERRIDABLE */
4703 ((unsigned int) _MHD_SYS_DEFAULT_FD_SETSIZE)
4704#endif /* ! HAS_FD_SETSIZE_OVERRIDABLE */
4705 );
4540} 4706}
4541 4707
4542 4708
@@ -4587,7 +4753,7 @@ MHD_select (struct MHD_Daemon *daemon,
4587 &ws, 4753 &ws,
4588 &es, 4754 &es,
4589 &maxsock, 4755 &maxsock,
4590 FD_SETSIZE)) 4756 (int) FD_SETSIZE))
4591 { 4757 {
4592#ifdef HAVE_MESSAGES 4758#ifdef HAVE_MESSAGES
4593 MHD_DLOG (daemon, 4759 MHD_DLOG (daemon,
@@ -4604,7 +4770,7 @@ MHD_select (struct MHD_Daemon *daemon,
4604 (! MHD_add_to_fd_set_ (ls, 4770 (! MHD_add_to_fd_set_ (ls,
4605 &rs, 4771 &rs,
4606 &maxsock, 4772 &maxsock,
4607 FD_SETSIZE)) ) 4773 (int) FD_SETSIZE)) )
4608 { 4774 {
4609#ifdef HAVE_MESSAGES 4775#ifdef HAVE_MESSAGES
4610 MHD_DLOG (daemon, 4776 MHD_DLOG (daemon,
@@ -4617,7 +4783,7 @@ MHD_select (struct MHD_Daemon *daemon,
4617 (! MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc), 4783 (! MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc),
4618 &rs, 4784 &rs,
4619 &maxsock, 4785 &maxsock,
4620 FD_SETSIZE)) ) 4786 (int) FD_SETSIZE)) )
4621 { 4787 {
4622 bool retry_succeed; 4788 bool retry_succeed;
4623 4789
@@ -4634,7 +4800,7 @@ MHD_select (struct MHD_Daemon *daemon,
4634 if (MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc), 4800 if (MHD_add_to_fd_set_ (MHD_itc_r_fd_ (daemon->itc),
4635 &rs, 4801 &rs,
4636 &maxsock, 4802 &maxsock,
4637 FD_SETSIZE)) 4803 (int) FD_SETSIZE))
4638 retry_succeed = true; 4804 retry_succeed = true;
4639 } 4805 }
4640#endif /* MHD_WINSOCK_SOCKETS */ 4806#endif /* MHD_WINSOCK_SOCKETS */
@@ -4731,7 +4897,8 @@ MHD_select (struct MHD_Daemon *daemon,
4731 if (MHD_NO != internal_run_from_select (daemon, 4897 if (MHD_NO != internal_run_from_select (daemon,
4732 &rs, 4898 &rs,
4733 &ws, 4899 &ws,
4734 &es)) 4900 &es,
4901 (int) FD_SETSIZE))
4735 return (MHD_NO == err_state) ? MHD_YES : MHD_NO; 4902 return (MHD_NO == err_state) ? MHD_YES : MHD_NO;
4736 return MHD_NO; 4903 return MHD_NO;
4737} 4904}
@@ -5675,6 +5842,24 @@ MHD_run_wait (struct MHD_Daemon *daemon,
5675#endif 5842#endif
5676 if (1) 5843 if (1)
5677 { 5844 {
5845 mhd_assert (MHD_D_IS_USING_SELECT_ (daemon));
5846#ifdef HAS_FD_SETSIZE_OVERRIDABLE
5847#ifdef HAVE_MESSAGES
5848 if (daemon->fdset_size_set_by_app
5849 && (((int) FD_SETSIZE) < daemon->fdset_size))
5850 {
5851 MHD_DLOG (daemon,
5852 _ ("MHD_run()/MHD_run_wait() called for daemon started with " \
5853 "MHD_OPTION_APP_FD_SETSIZE option (%d). " \
5854 "The library was compiled with smaller FD_SETSIZE (%d). " \
5855 "Some socket FDs may be not processed. " \
5856 "Use MHD_run_from_select2() instead of MHD_run() or " \
5857 "do not use MHD_OPTION_APP_FD_SETSIZE option.\n"),
5858 daemon->fdset_size, (int) FD_SETSIZE);
5859 }
5860#endif /* HAVE_MESSAGES */
5861#endif /* HAS_FD_SETSIZE_OVERRIDABLE */
5862
5678 res = MHD_select (daemon, millisec); 5863 res = MHD_select (daemon, millisec);
5679 /* MHD_select does MHD_cleanup_connections already */ 5864 /* MHD_select does MHD_cleanup_connections already */
5680 } 5865 }
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index 2e49652c..bd7f30d3 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -381,7 +381,7 @@ int
381MHD_add_to_fd_set_ (MHD_socket fd, 381MHD_add_to_fd_set_ (MHD_socket fd,
382 fd_set *set, 382 fd_set *set,
383 MHD_socket *max_fd, 383 MHD_socket *max_fd,
384 unsigned int fd_setsize) 384 int fd_setsize)
385{ 385{
386 if ( (NULL == set) || 386 if ( (NULL == set) ||
387 (MHD_INVALID_SOCKET == fd) ) 387 (MHD_INVALID_SOCKET == fd) )
diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h
index 4e0e34d0..3b953c3f 100644
--- a/src/microhttpd/mhd_sockets.h
+++ b/src/microhttpd/mhd_sockets.h
@@ -881,7 +881,7 @@ int
881MHD_add_to_fd_set_ (MHD_socket fd, 881MHD_add_to_fd_set_ (MHD_socket fd,
882 fd_set *set, 882 fd_set *set,
883 MHD_socket *max_fd, 883 MHD_socket *max_fd,
884 unsigned int fd_setsize); 884 int fd_setsize);
885 885
886 886
887/** 887/**