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:
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,