diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-12-26 12:02:04 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-12-26 12:41:49 +0300 |
commit | 73c43a7ef7bdccda1b6b6714d2d64b1714e9cdad (patch) | |
tree | ee25bbc5b0ff1c9d773178e7905cff169c53d4d7 /src/microhttpd/daemon.c | |
parent | 0dd7f1732a7623929691d12e937211303d6dbd71 (diff) | |
download | libmicrohttpd-73c43a7ef7bdccda1b6b6714d2d64b1714e9cdad.tar.gz libmicrohttpd-73c43a7ef7bdccda1b6b6714d2d64b1714e9cdad.zip |
Added workaround for system clock jumps back
Same OSes (namely OpenBSD) has system clocks that must be monotonic,
but in practice clocks may jump forward and back up to 500 milliseconds.
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 113 |
1 files changed, 61 insertions, 52 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index d4064dd7..5ca612ea 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -1858,6 +1858,54 @@ thread_main_connection_upgrade (struct MHD_Connection *con) | |||
1858 | 1858 | ||
1859 | 1859 | ||
1860 | /** | 1860 | /** |
1861 | * Get maximum wait period for the connection (the amount of time left before | ||
1862 | * connection time out) | ||
1863 | * @param c the connection to check | ||
1864 | * @return the maximum wait period before the connection must be processed | ||
1865 | * again. | ||
1866 | */ | ||
1867 | static uint64_t | ||
1868 | connection_get_wait (struct MHD_Connection *c) | ||
1869 | { | ||
1870 | const uint64_t now = MHD_monotonic_msec_counter (); | ||
1871 | const uint64_t since_actv = now - c->last_activity; | ||
1872 | const uint64_t timeout = c->connection_timeout_ms; | ||
1873 | uint64_t mseconds_left; | ||
1874 | |||
1875 | mhd_assert (0 != timeout); | ||
1876 | /* Keep the next lines in sync with #connection_check_timedout() to avoid | ||
1877 | * undesired side-effects like busy-waiting. */ | ||
1878 | if (timeout < since_actv) | ||
1879 | { | ||
1880 | if (UINT64_MAX / 2 < since_actv) | ||
1881 | { | ||
1882 | const uint64_t jump_back = c->last_activity - now; | ||
1883 | /* Very unlikely that it is more than quarter-million years pause. | ||
1884 | * More likely that system clock jumps back. */ | ||
1885 | if (5000 >= jump_back) | ||
1886 | { /* Jump back is less than 5 seconds, try to recover. */ | ||
1887 | return 100; /* Set wait time to 0.1 seconds */ | ||
1888 | } | ||
1889 | /* Too large jump back */ | ||
1890 | } | ||
1891 | return 0; /* Connection has timed out */ | ||
1892 | } | ||
1893 | else if (since_actv == timeout) | ||
1894 | { | ||
1895 | /* Exact match for timeout and time from last activity. | ||
1896 | * Maybe this is just a precise match or this happens because the timer | ||
1897 | * resolution is too low. | ||
1898 | * Set wait time to 0.1 seconds to avoid busy-waiting with low | ||
1899 | * timer resolution as connection is not timed-out yet. */ | ||
1900 | return 100; | ||
1901 | } | ||
1902 | mseconds_left = timeout - since_actv; | ||
1903 | |||
1904 | return mseconds_left; | ||
1905 | } | ||
1906 | |||
1907 | |||
1908 | /** | ||
1861 | * Main function of the thread that handles an individual | 1909 | * Main function of the thread that handles an individual |
1862 | * connection when #MHD_USE_THREAD_PER_CONNECTION is set. | 1910 | * connection when #MHD_USE_THREAD_PER_CONNECTION is set. |
1863 | * | 1911 | * |
@@ -1995,35 +2043,16 @@ thread_main_handle_connection (void *data) | |||
1995 | if ( (NULL == tvp) && | 2043 | if ( (NULL == tvp) && |
1996 | (timeout > 0) ) | 2044 | (timeout > 0) ) |
1997 | { | 2045 | { |
1998 | const uint64_t since_actv = MHD_monotonic_msec_counter () | 2046 | const uint64_t mseconds_left = connection_get_wait (con); |
1999 | - con->last_activity; | 2047 | #if (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC |
2000 | if (since_actv > timeout) | 2048 | if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX) |
2001 | { | 2049 | tv.tv_sec = TIMEVAL_TV_SEC_MAX; |
2002 | tv.tv_sec = 0; | ||
2003 | tv.tv_usec = 0; | ||
2004 | } | ||
2005 | else if (since_actv == timeout) | ||
2006 | { | ||
2007 | /* Exact match for timeout and time from last activity. | ||
2008 | * Maybe this is just a precise match or this happens because the timer | ||
2009 | * resolution is too low. | ||
2010 | * Set wait time to 0.1 seconds to avoid busy-waiting with low | ||
2011 | * timer resolution as connection is not yet timed-out */ | ||
2012 | tv.tv_sec = 0; | ||
2013 | tv.tv_usec = 100 * 1000; | ||
2014 | } | ||
2015 | else | 2050 | else |
2016 | { | 2051 | #endif /* (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */ |
2017 | const uint64_t mseconds_left = timeout - since_actv; | 2052 | tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000; |
2018 | #if (SIZEOF_UINT64_T - 1) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC | 2053 | |
2019 | if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX) | 2054 | tv.tv_usec = (mseconds_left % 1000) * 1000; |
2020 | tv.tv_sec = TIMEVAL_TV_SEC_MAX; | ||
2021 | else | ||
2022 | #endif /* (SIZEOF_UINT64_T - 1) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */ | ||
2023 | tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000; | ||
2024 | 2055 | ||
2025 | tv.tv_usec = (mseconds_left % 1000) * 1000; | ||
2026 | } | ||
2027 | tvp = &tv; | 2056 | tvp = &tv; |
2028 | } | 2057 | } |
2029 | if (! use_poll) | 2058 | if (! use_poll) |
@@ -3930,33 +3959,13 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
3930 | 3959 | ||
3931 | if (NULL != earliest_tmot_conn) | 3960 | if (NULL != earliest_tmot_conn) |
3932 | { | 3961 | { |
3933 | const uint64_t since_actv = MHD_monotonic_msec_counter () | 3962 | const uint64_t mssecond_left = connection_get_wait (earliest_tmot_conn); |
3934 | - earliest_tmot_conn->last_activity; | ||
3935 | /* Keep the next lines in sync with #MHD_connection_handle_idle() and | ||
3936 | * with #thread_main_handle_connection(). */ | ||
3937 | if (since_actv > earliest_tmot_conn->connection_timeout_ms) | ||
3938 | *timeout = 0; | ||
3939 | else if (since_actv == earliest_tmot_conn->connection_timeout_ms) | ||
3940 | { | ||
3941 | /* Exact match for timeout and time from last activity. | ||
3942 | * Maybe this is just a precise match or this happens because the timer | ||
3943 | * resolution is too low. | ||
3944 | * Set wait time to 0.1 seconds to avoid busy-waiting with low | ||
3945 | * timer resolution as connection is not yet timed-out */ | ||
3946 | *timeout = 100; | ||
3947 | } | ||
3948 | else | ||
3949 | { | ||
3950 | const uint64_t mssecond_left = earliest_tmot_conn->connection_timeout_ms | ||
3951 | - since_actv; | ||
3952 | |||
3953 | #if SIZEOF_UINT64_T > SIZEOF_UNSIGNED_LONG_LONG | 3963 | #if SIZEOF_UINT64_T > SIZEOF_UNSIGNED_LONG_LONG |
3954 | if (mssecond_left > ULLONG_MAX) | 3964 | if (mssecond_left > ULLONG_MAX) |
3955 | *timeout = ULLONG_MAX; | 3965 | *timeout = ULLONG_MAX; |
3956 | else | 3966 | else |
3957 | #endif /* UINT64 != ULLONG_MAX */ | 3967 | #endif /* UINT64 != ULLONG_MAX */ |
3958 | *timeout = (unsigned long long) mssecond_left; | 3968 | *timeout = (unsigned long long) mssecond_left; |
3959 | } | ||
3960 | return MHD_YES; | 3969 | return MHD_YES; |
3961 | } | 3970 | } |
3962 | return MHD_NO; | 3971 | return MHD_NO; |