libmicrohttpd2

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

commit 1dcefc38000546ea95612239512cb99687e37876
parent b35a94479be545ffa0bd655ccf8345cc5509f93c
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Fri, 26 Dec 2025 19:48:14 +0100

Connection timeouts: streamlined timeout logic

Diffstat:
Msrc/mhd2/conn_timeout.c | 74++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/mhd2/conn_timeout.h | 15++++++++++++++-
2 files changed, 52 insertions(+), 37 deletions(-)

diff --git a/src/mhd2/conn_timeout.c b/src/mhd2/conn_timeout.c @@ -48,59 +48,61 @@ #include "mhd_assert.h" +#include "mhd_constexpr.h" + #include "mhd_dlinked_list.h" #include "mhd_daemon.h" #include "mhd_connection.h" #include "daemon_funcs.h" -#include "daemon_logger.h" #include "conn_timeout.h" -MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool -mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c) +MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t +mhd_conn_get_timeout_left (const struct MHD_Connection *restrict c, + uint_fast64_t cur_milsec) { - struct MHD_Daemon *const restrict d = c->daemon; + mhd_constexpr uint_fast64_t uifast64_hibit = + (uint_fast64_t) (~(((uint_fast64_t) (~((uint_fast64_t) 0))) >> 1u)); const uint_fast64_t timeout = c->timeout.milsec; - uint_fast64_t now; - uint_fast64_t since_actv; + uint_fast64_t timedout_time; + uint_fast64_t timeout_left; mhd_assert (! c->suspended); - if (0 == timeout) - return false; + if (0u == timeout) + return (uint_fast64_t) 0xFFFFFFFFFFFFFFFFu; + + /* The logic used in these calculations allows values wrap over the maximum + value (taking into account that maximum timeout time is limited) */ + timedout_time = + c->timeout.last_act + c->timeout.milsec + 1u; /* '+1' to not expire at exactly 'timeout' milliseconds */ + /* Time before timed out moment */ + timeout_left = timedout_time - cur_milsec; - now = mhd_daemon_get_milsec_counter (d); - since_actv = now - c->timeout.last_act; - /* Keep the next lines in sync with #connection_get_wait() to avoid - * undesired side-effects like busy-waiting. */ - if (timeout < since_actv) + if (0u == (timeout_left & uifast64_hibit)) { - const uint_fast64_t jump_back = c->timeout.last_act - now; - if (jump_back < since_actv) - { - /* Very unlikely that it is more than quarter-million years pause. - * More likely that system clock jumps back. */ - if (4000 >= jump_back) - { - c->timeout.last_act = now; /* Avoid repetitive messages. - Warn: the order of connections sorted - by timeout is not updated. */ - mhd_LOG_PRINT (d, MHD_SC_SYS_CLOCK_JUMP_BACK_CORRECTED, \ - mhd_LOG_FMT ("Detected system clock %u " \ - "milliseconds jump back."), - (unsigned int) jump_back); - return false; - } - mhd_LOG_PRINT (d, MHD_SC_SYS_CLOCK_JUMP_BACK_LARGE, \ - mhd_LOG_FMT ("Detected too large system clock %" \ - PRIuFAST64 " milliseconds jump back"), - jump_back); - } - return true; + /* "Timeout left" must be always less or equal the timeout value (plus one) + unless the system clock jumped back. */ + mhd_assert ((timeout_left <= (c->timeout.milsec + 1u)) || + ((cur_milsec - c->timeout.last_act) + > (c->timeout.last_act - cur_milsec))); + + return timeout_left; } - return false; + + return 0u; /* Already timed out */ +} + + +MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool +mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c) +{ + struct MHD_Daemon *const restrict d = c->daemon; + + return (0u == mhd_conn_get_timeout_left (c, + mhd_daemon_get_milsec_counter (d))); } diff --git a/src/mhd2/conn_timeout.h b/src/mhd2/conn_timeout.h @@ -52,6 +52,20 @@ struct MHD_Connection; /* Forward declaration */ + +/** + * Get number of milliseconds before connection will time out. + * @param c the connection to check + * @return zero if connection is timed out already, + * number of millisecond left before connection will time out, + * #UINT64_MAX if connection has no time out + */ +MHD_INTERNAL uint_fast64_t +mhd_conn_get_timeout_left (const struct MHD_Connection *restrict c, + uint_fast64_t cur_milsec) +MHD_FN_PAR_NONNULL_ALL_; + + /** * Check whether connection's timeout is expired. * @param c the connection to check @@ -63,7 +77,6 @@ MHD_INTERNAL bool mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c) MHD_FN_PAR_NONNULL_ALL_; - /** * Initialise activity timeout data. * Add connection to the timeouts list if needed; set activity mark, if needed.