aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/daemon.c
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-12-26 12:02:04 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-12-26 12:41:49 +0300
commit73c43a7ef7bdccda1b6b6714d2d64b1714e9cdad (patch)
treeee25bbc5b0ff1c9d773178e7905cff169c53d4d7 /src/microhttpd/daemon.c
parent0dd7f1732a7623929691d12e937211303d6dbd71 (diff)
downloadlibmicrohttpd-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.c113
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 */
1867static uint64_t
1868connection_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;