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