libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit a56fe4fa5782cc7c3994fdbb9c497d30fa36d945
parent 1dcefc38000546ea95612239512cb99687e37876
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Sat, 27 Dec 2025 11:36:36 +0100

Daemon: use earliest connection timeout time for max wait calculations

Diffstat:
Mconfigure.ac | 2+-
Mdoc/examples/external-select.c | 4++--
Msrc/include/microhttpd2.h | 12+++++++-----
Msrc/include/microhttpd2_preamble.h.in | 12+++++++-----
Msrc/mhd2/events_process.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/tests/client_server/libtest_convenience.c | 12++++++++++--
6 files changed, 88 insertions(+), 26 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -735,7 +735,7 @@ AC_CHECK_HEADERS([sys/socket.h sys/select.h netinet/in_systm.h netinet/in.h \ # Check for other optional headers AC_CHECK_HEADERS([sys/msg.h sys/mman.h signal.h], [], [], [AC_INCLUDES_DEFAULT]) -AC_CHECK_TYPES([size_t,ssize_t,ptrdiff_t,intptr_t,uintptr_t,uint8_t],[],[], +AC_CHECK_TYPES([size_t,ssize_t,ptrdiff_t,intptr_t,uintptr_t,uint8_t,time_t,suseconds_t],[],[], [[ /* Keep in sync with src/mhd2/sys_base_types.h */ #include <stdint.h> /* uint_fast_XXt, int_fast_XXt */ diff --git a/doc/examples/external-select.c b/doc/examples/external-select.c @@ -168,8 +168,8 @@ main () /* This will cause MHD to call the #sock_reg_update_cb() */ MHD_daemon_process_reg_events (daemon, &next_wait); - ts.tv_sec = next_wait / 1000000; - ts.tv_usec = next_wait % 1000000; + ts.tv_sec = (time_t) (next_wait / 1000u); + ts.tv_usec = (suseconds_t) ((next_wait % 1000u) * 1000u); /* Real applications may do nicer error handling here */ (void) select (max_fd + 1, &rs, diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -2919,17 +2919,19 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2); * registered FD between any two calls of this function. * * @param daemon the daemon handle - * @param[out] next_max_wait the optional pointer to receive the next maximum - * wait time in microseconds to be used for sockets - * polling function, can be NULL + * @param[out] next_max_wait_milsec the optional pointer to receive the + next maximum wait time in milliseconds + to be used for the sockets polling + function, can be NULL * @return #MHD_SC_OK on success, * error code otherwise * @sa #MHD_D_OPTION_REREGISTER_ALL * @ingroup event */ MHD_EXTERN_ enum MHD_StatusCode -MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon, - uint_fast64_t *MHD_RESTRICT next_max_wait) +MHD_daemon_process_reg_events ( + struct MHD_Daemon *MHD_RESTRICT daemon, + uint_fast64_t *MHD_RESTRICT next_max_wait_milsec) MHD_FN_PAR_NONNULL_ (1); /* ********************* daemon options ************** */ diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in @@ -2919,17 +2919,19 @@ MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2); * registered FD between any two calls of this function. * * @param daemon the daemon handle - * @param[out] next_max_wait the optional pointer to receive the next maximum - * wait time in microseconds to be used for sockets - * polling function, can be NULL + * @param[out] next_max_wait_milsec the optional pointer to receive the + next maximum wait time in milliseconds + to be used for the sockets polling + function, can be NULL * @return #MHD_SC_OK on success, * error code otherwise * @sa #MHD_D_OPTION_REREGISTER_ALL * @ingroup event */ MHD_EXTERN_ enum MHD_StatusCode -MHD_daemon_process_reg_events (struct MHD_Daemon *MHD_RESTRICT daemon, - uint_fast64_t *MHD_RESTRICT next_max_wait) +MHD_daemon_process_reg_events ( + struct MHD_Daemon *MHD_RESTRICT daemon, + uint_fast64_t *MHD_RESTRICT next_max_wait_milsec) MHD_FN_PAR_NONNULL_ (1); /* ********************* daemon options ************** */ diff --git a/src/mhd2/events_process.c b/src/mhd2/events_process.c @@ -74,6 +74,8 @@ #include "mhd_daemon.h" #include "mhd_connection.h" +#include "mhd_mono_clock.h" + #include "conn_timeout.h" #include "conn_mark_ready.h" #include "daemon_logger.h" @@ -188,9 +190,49 @@ log_listen_broken (struct MHD_Daemon *restrict d) } +static MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t +mhd_daemon_get_wait_erliest_timeout (const struct MHD_Daemon *restrict d) +{ + uint_fast64_t ret; + uint_fast64_t cur_milsec; + const struct MHD_Connection *c; + + c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout)); + if ((NULL == c) + && (NULL == mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)))) + return MHD_WAIT_INDEFINITELY; + + /* Do not use mhd_daemon_get_milsec_counter() as actual time is required + here */ + cur_milsec = mhd_monotonic_msec_counter (); + + /* Check just the first connection in the ordered "default timeout" list */ + if (NULL != c) + ret = mhd_conn_get_timeout_left (c, + cur_milsec); + else + ret = MHD_WAIT_INDEFINITELY; + + for (c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)); + (NULL != c) && (0u != ret); + c = mhd_DLINKEDL_GET_PREV (&(c->timeout), + tmout_list)) + { + uint_fast64_t conn_tmout_left; + conn_tmout_left = mhd_conn_get_timeout_left (c, + cur_milsec); + if (ret > conn_tmout_left) + ret = conn_tmout_left; + } + + return ret; +} + + MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t -mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d) +mhd_daemon_get_wait_max (const struct MHD_Daemon *restrict d) { + uint_fast64_t ret; mhd_assert (! mhd_D_HAS_WORKERS (d)); @@ -222,11 +264,19 @@ mhd_daemon_get_wait_max (struct MHD_Daemon *restrict d) return 0; } + ret = mhd_daemon_get_wait_erliest_timeout (d); + #ifdef mhd_DEBUG_POLLING_FDS - fprintf (stderr, - "### mhd_daemon_get_wait_max(daemon) -> MHD_WAIT_INDEFINITELY\n"); + if (MHD_WAIT_INDEFINITELY == ret) + fprintf (stderr, + "### mhd_daemon_get_wait_max(daemon) -> MHD_WAIT_INDEFINITELY\n"); + else + fprintf (stderr, + "### mhd_daemon_get_wait_max(daemon) -> %lu\n", + (unsigned long) ret); #endif - return MHD_WAIT_INDEFINITELY; // TODO: calculate correct timeout value + + return ret; } @@ -1710,7 +1760,7 @@ static MHD_FN_PAR_NONNULL_ALL_ void daemon_close_timedout_conns (struct MHD_Daemon *restrict d) { struct MHD_Connection *c; - struct MHD_Connection *next_c; + struct MHD_Connection *prev_c; #if defined(MHD_SUPPORT_THREADS) mhd_assert (! mhd_D_HAS_WORKERS (d)); @@ -1718,7 +1768,7 @@ daemon_close_timedout_conns (struct MHD_Daemon *restrict d) #endif /* MHD_SUPPORT_THREADS */ /* Check "normal" timeouts list */ - c = mhd_DLINKEDL_GET_FIRST_D (&(d->conns.def_timeout)); + c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.def_timeout)); while (NULL != c) { @@ -1727,27 +1777,27 @@ daemon_close_timedout_conns (struct MHD_Daemon *restrict d) if (mhd_conn_is_timeout_expired (c)) { - next_c = mhd_DLINKEDL_GET_NEXT (&(c->timeout), + prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list); mhd_conn_start_closing_timedout (c); mhd_conn_pre_clean (c); mhd_conn_remove_from_daemon (c); mhd_conn_close_final (c); - c = next_c; + c = prev_c; } else break; /* DL-list is sorted, no need to check the rest of the list */ } /* Check "custom" timeouts list */ - c = mhd_DLINKEDL_GET_FIRST_D (&(d->conns.cust_timeout)); + c = mhd_DLINKEDL_GET_LAST_D (&(d->conns.cust_timeout)); while (NULL != c) { mhd_assert (c->timeout.in_cstm_tmout_list); - next_c = mhd_DLINKEDL_GET_NEXT (&(c->timeout), + prev_c = mhd_DLINKEDL_GET_PREV (&(c->timeout), tmout_list); if (mhd_conn_is_timeout_expired (c)) @@ -1759,7 +1809,7 @@ daemon_close_timedout_conns (struct MHD_Daemon *restrict d) } /* "Custom" timeouts list is not sorted, check all members */ - c = next_c; + c = prev_c; } } diff --git a/src/tests/client_server/libtest_convenience.c b/src/tests/client_server/libtest_convenience.c @@ -462,8 +462,16 @@ MHDT_server_run_external (void *cls, "MHD_daemon_process_reg_events() failed\n"); break; } - timeout.tv_sec = (time_t) (next_wait / 1000000); - timeout.tv_usec = (suseconds_t) (next_wait % 1000000); +#ifdef HAVE_TIME_H + timeout.tv_sec = (time_t) (next_wait / 1000u); +#else + timeout.tv_sec = (long) (next_wait / 1000u); +#endif +#ifdef HAVE_SUSECONDS_T + timeout.tv_usec = (suseconds_t) ((next_wait % 1000u) * 1000u); +#else + timeout.tv_usec = (long) ((next_wait % 1000u) * 1000u); +#endif FD_ZERO (&r); FD_SET (finsig,