aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-08-30 21:13:54 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-08-30 21:13:54 +0300
commite42ec8f54d28c982307367c483cee34ade5c54f8 (patch)
tree281d148ea44410977876ef5ce2a069e84e2340ee
parent510881918a1bb72b2f9c007ae0ba14685429068c (diff)
downloadlibmicrohttpd-e42ec8f54d28c982307367c483cee34ade5c54f8.tar.gz
libmicrohttpd-e42ec8f54d28c982307367c483cee34ade5c54f8.zip
Switched internal timers to milliseconds resolutions.
This is needed to handle connection timeouts precisely. * Fixed connections expired "just before or after" required timeout * Fixed busy-waiting with low-resolution system timers when connection is about to timeout. Now low-resolution timers are handled automatically. * Added log message if application tries to set ridiculously large timeout
-rw-r--r--src/include/microhttpd.h6
-rw-r--r--src/microhttpd/connection.c50
-rw-r--r--src/microhttpd/daemon.c152
-rw-r--r--src/microhttpd/internal.h25
4 files changed, 148 insertions, 85 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 166e9b47..30ee451f 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
96 * they are parsed as decimal numbers. 96 * they are parsed as decimal numbers.
97 * Example: 0x01093001 = 1.9.30-1. 97 * Example: 0x01093001 = 1.9.30-1.
98 */ 98 */
99#define MHD_VERSION 0x00097310 99#define MHD_VERSION 0x00097311
100 100
101/* If generic headers don't work on your platform, include headers 101/* If generic headers don't work on your platform, include headers
102 which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 102 which define 'va_list', 'size_t', 'ssize_t', 'intptr_t',
@@ -1432,6 +1432,8 @@ enum MHD_OPTION
1432 * After how many seconds of inactivity should a 1432 * After how many seconds of inactivity should a
1433 * connection automatically be timed out? (followed 1433 * connection automatically be timed out? (followed
1434 * by an `unsigned int`; use zero for no timeout). 1434 * by an `unsigned int`; use zero for no timeout).
1435 * Values larger than (UINT64_MAX / 2000 - 1) will
1436 * be clipped to this number.
1435 */ 1437 */
1436 MHD_OPTION_CONNECTION_TIMEOUT = 3, 1438 MHD_OPTION_CONNECTION_TIMEOUT = 3,
1437 1439
@@ -4133,6 +4135,8 @@ enum MHD_CONNECTION_OPTION
4133 * zero for no timeout. 4135 * zero for no timeout.
4134 * If timeout was set to zero (or unset) before, setup of new value by 4136 * If timeout was set to zero (or unset) before, setup of new value by
4135 * MHD_set_connection_option() will reset timeout timer. 4137 * MHD_set_connection_option() will reset timeout timer.
4138 * Values larger than (UINT64_MAX / 2000 - 1) will
4139 * be clipped to this number.
4136 */ 4140 */
4137 MHD_CONNECTION_OPTION_TIMEOUT 4141 MHD_CONNECTION_OPTION_TIMEOUT
4138 4142
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index bcb3f934..de81f08a 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -3487,17 +3487,17 @@ MHD_update_last_activity_ (struct MHD_Connection *connection)
3487{ 3487{
3488 struct MHD_Daemon *daemon = connection->daemon; 3488 struct MHD_Daemon *daemon = connection->daemon;
3489 3489
3490 if (0 == connection->connection_timeout) 3490 if (0 == connection->connection_timeout_ms)
3491 return; /* Skip update of activity for connections 3491 return; /* Skip update of activity for connections
3492 without timeout timer. */ 3492 without timeout timer. */
3493 if (connection->suspended) 3493 if (connection->suspended)
3494 return; /* no activity on suspended connections */ 3494 return; /* no activity on suspended connections */
3495 3495
3496 connection->last_activity = MHD_monotonic_sec_counter (); 3496 connection->last_activity = MHD_monotonic_msec_counter ();
3497 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 3497 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3498 return; /* each connection has personal timeout */ 3498 return; /* each connection has personal timeout */
3499 3499
3500 if (connection->connection_timeout != daemon->connection_timeout) 3500 if (connection->connection_timeout_ms != daemon->connection_timeout_ms)
3501 return; /* custom timeout, no need to move it in "normal" DLL */ 3501 return; /* custom timeout, no need to move it in "normal" DLL */
3502#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) 3502#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
3503 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); 3503 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
@@ -4011,7 +4011,7 @@ cleanup_connection (struct MHD_Connection *connection)
4011 { 4011 {
4012 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 4012 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
4013 { 4013 {
4014 if (connection->connection_timeout == daemon->connection_timeout) 4014 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
4015 XDLL_remove (daemon->normal_timeout_head, 4015 XDLL_remove (daemon->normal_timeout_head,
4016 daemon->normal_timeout_tail, 4016 daemon->normal_timeout_tail,
4017 connection); 4017 connection);
@@ -4584,11 +4584,13 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
4584 } 4584 }
4585 if (! connection->suspended) 4585 if (! connection->suspended)
4586 { 4586 {
4587 time_t timeout; 4587 uint64_t timeout;
4588 timeout = connection->connection_timeout; 4588 timeout = connection->connection_timeout_ms;
4589 /* Keep the next lines in sync with #MHD_get_timeout() to avoid
4590 * undesired side-effects like busy-waiting. */
4589 if ( (0 != timeout) && 4591 if ( (0 != timeout) &&
4590 (timeout <= (MHD_monotonic_sec_counter () 4592 (timeout < (MHD_monotonic_msec_counter ()
4591 - connection->last_activity)) ) 4593 - connection->last_activity)) )
4592 { 4594 {
4593 MHD_connection_close_ (connection, 4595 MHD_connection_close_ (connection,
4594 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); 4596 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
@@ -4719,8 +4721,8 @@ MHD_get_connection_info (struct MHD_Connection *connection,
4719 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO; 4721 connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
4720 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy; 4722 return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
4721 case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT: 4723 case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT:
4722 connection->connection_timeout_dummy = (unsigned 4724 connection->connection_timeout_dummy =
4723 int) connection->connection_timeout; 4725 (unsigned int) connection->connection_timeout_ms * 1000;
4724 return (const union MHD_ConnectionInfo *) &connection-> 4726 return (const union MHD_ConnectionInfo *) &connection->
4725 connection_timeout_dummy; 4727 connection_timeout_dummy;
4726 case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE: 4728 case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE:
@@ -4759,15 +4761,15 @@ MHD_set_connection_option (struct MHD_Connection *connection,
4759 switch (option) 4761 switch (option)
4760 { 4762 {
4761 case MHD_CONNECTION_OPTION_TIMEOUT: 4763 case MHD_CONNECTION_OPTION_TIMEOUT:
4762 if (0 == connection->connection_timeout) 4764 if (0 == connection->connection_timeout_ms)
4763 connection->last_activity = MHD_monotonic_sec_counter (); 4765 connection->last_activity = MHD_monotonic_msec_counter ();
4764#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) 4766#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
4765 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); 4767 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
4766#endif 4768#endif
4767 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 4769 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
4768 (! connection->suspended) ) 4770 (! connection->suspended) )
4769 { 4771 {
4770 if (connection->connection_timeout == daemon->connection_timeout) 4772 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
4771 XDLL_remove (daemon->normal_timeout_head, 4773 XDLL_remove (daemon->normal_timeout_head,
4772 daemon->normal_timeout_tail, 4774 daemon->normal_timeout_tail,
4773 connection); 4775 connection);
@@ -4777,13 +4779,29 @@ MHD_set_connection_option (struct MHD_Connection *connection,
4777 connection); 4779 connection);
4778 } 4780 }
4779 va_start (ap, option); 4781 va_start (ap, option);
4780 connection->connection_timeout = va_arg (ap, 4782 connection->connection_timeout_ms = va_arg (ap,
4781 unsigned int); 4783 unsigned int);
4782 va_end (ap); 4784 va_end (ap);
4785#if (0 == (UINT64_MAX + 0)) || ((UINT_MAX + 0) >= (UINT64_MAX + 0))
4786 if ((UINT64_MAX / 2000 - 1) < connection->connection_timeout_ms)
4787 {
4788#ifdef HAVE_MESSAGES
4789 MHD_DLOG (connection->daemon,
4790 _ ("The specified connection timeout (" PRIu64 ") is too " \
4791 "large. Maximum allowed value (" PRIu64 ") will be used " \
4792 "instead.\n"),
4793 connection->connection_timeout_ms,
4794 (UINT64_MAX / 2000 - 1));
4795#endif
4796 connection->connection_timeout_ms = UINT64_MAX / 2000 - 1;
4797 }
4798 else
4799#endif /* UINTMAX_MAX >= UINT64_MAX */
4800 connection->connection_timeout_ms *= 1000;
4783 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 4801 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
4784 (! connection->suspended) ) 4802 (! connection->suspended) )
4785 { 4803 {
4786 if (connection->connection_timeout == daemon->connection_timeout) 4804 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
4787 XDLL_insert (daemon->normal_timeout_head, 4805 XDLL_insert (daemon->normal_timeout_head,
4788 daemon->normal_timeout_tail, 4806 daemon->normal_timeout_tail,
4789 connection); 4807 connection);
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index d4fd0d6a..090d39d4 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1869,7 +1869,6 @@ thread_main_handle_connection (void *data)
1869 MHD_socket maxsock; 1869 MHD_socket maxsock;
1870 struct timeval tv; 1870 struct timeval tv;
1871 struct timeval *tvp; 1871 struct timeval *tvp;
1872 time_t now;
1873#if WINDOWS 1872#if WINDOWS
1874#ifdef HAVE_POLL 1873#ifdef HAVE_POLL
1875 int extra_slot; 1874 int extra_slot;
@@ -1893,7 +1892,7 @@ thread_main_handle_connection (void *data)
1893 while ( (! daemon->shutdown) && 1892 while ( (! daemon->shutdown) &&
1894 (MHD_CONNECTION_CLOSED != con->state) ) 1893 (MHD_CONNECTION_CLOSED != con->state) )
1895 { 1894 {
1896 const time_t timeout = con->connection_timeout; 1895 uint64_t timeout = con->connection_timeout_ms;
1897#ifdef UPGRADE_SUPPORT 1896#ifdef UPGRADE_SUPPORT
1898 struct MHD_UpgradeResponseHandle *const urh = con->urh; 1897 struct MHD_UpgradeResponseHandle *const urh = con->urh;
1899#else /* ! UPGRADE_SUPPORT */ 1898#else /* ! UPGRADE_SUPPORT */
@@ -1989,22 +1988,34 @@ thread_main_handle_connection (void *data)
1989 if ( (NULL == tvp) && 1988 if ( (NULL == tvp) &&
1990 (timeout > 0) ) 1989 (timeout > 0) )
1991 { 1990 {
1992 now = MHD_monotonic_sec_counter (); 1991 const uint64_t since_actv = MHD_monotonic_msec_counter ()
1993 if (now - con->last_activity > timeout) 1992 - con->last_activity;
1993 if (since_actv > timeout)
1994 {
1994 tv.tv_sec = 0; 1995 tv.tv_sec = 0;
1996 tv.tv_usec = 0;
1997 }
1998 else if (since_actv == timeout)
1999 {
2000 /* Exact match for timeout and time from last activity.
2001 * Maybe this is just a precise match or this happens because the timer
2002 * resolution is too low.
2003 * Set wait time to 0.1 seconds to avoid busy-waiting with low
2004 * timer resolution as connection is not yet timed-out */
2005 tv.tv_sec = 0;
2006 tv.tv_usec = 100 * 1000;
2007 }
1995 else 2008 else
1996 { 2009 {
1997 const time_t seconds_left = timeout - (now - con->last_activity); 2010 const uint64_t mseconds_left = timeout - since_actv;
1998#if ! defined(_WIN32) || defined(__CYGWIN__) 2011#if UINT64_MAX != TIMEVAL_TV_SEC_MAX
1999 tv.tv_sec = seconds_left; 2012 if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
2000#else /* _WIN32 && !__CYGWIN__ */
2001 if (seconds_left > TIMEVAL_TV_SEC_MAX)
2002 tv.tv_sec = TIMEVAL_TV_SEC_MAX; 2013 tv.tv_sec = TIMEVAL_TV_SEC_MAX;
2003 else 2014 else
2004 tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) seconds_left; 2015 tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
2005#endif /* _WIN32 && ! __CYGWIN__ */ 2016#endif /* UINT64_MAX != TIMEVAL_TV_SEC_MAX */
2017 tv.tv_usec = (mseconds_left % 1000) * 1000;
2006 } 2018 }
2007 tv.tv_usec = 0;
2008 tvp = &tv; 2019 tvp = &tv;
2009 } 2020 }
2010 if (! use_poll) 2021 if (! use_poll)
@@ -2474,7 +2485,6 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
2474 connection->sk_nodelay = _MHD_UNKNOWN; 2485 connection->sk_nodelay = _MHD_UNKNOWN;
2475 } 2486 }
2476 2487
2477 connection->connection_timeout = daemon->connection_timeout;
2478 if (NULL == (connection->addr = malloc (addrlen))) 2488 if (NULL == (connection->addr = malloc (addrlen)))
2479 { 2489 {
2480 eno = errno; 2490 eno = errno;
@@ -2500,7 +2510,9 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
2500 connection->is_nonip = sk_is_nonip; 2510 connection->is_nonip = sk_is_nonip;
2501 connection->sk_spipe_suppress = sk_spipe_supprs; 2511 connection->sk_spipe_suppress = sk_spipe_supprs;
2502 connection->daemon = daemon; 2512 connection->daemon = daemon;
2503 connection->last_activity = MHD_monotonic_sec_counter (); 2513 connection->connection_timeout_ms = daemon->connection_timeout_ms;
2514 if (0 != connection->connection_timeout_ms)
2515 connection->last_activity = MHD_monotonic_msec_counter ();
2504 2516
2505 if (0 == (daemon->options & MHD_USE_TLS)) 2517 if (0 == (daemon->options & MHD_USE_TLS))
2506 { 2518 {
@@ -3061,7 +3073,7 @@ internal_suspend_connection_ (struct MHD_Connection *connection)
3061 } 3073 }
3062 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 3074 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
3063 { 3075 {
3064 if (connection->connection_timeout == daemon->connection_timeout) 3076 if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
3065 XDLL_remove (daemon->normal_timeout_head, 3077 XDLL_remove (daemon->normal_timeout_head,
3066 daemon->normal_timeout_tail, 3078 daemon->normal_timeout_tail,
3067 connection); 3079 connection);
@@ -3270,10 +3282,10 @@ resume_suspended_connections (struct MHD_Daemon *daemon)
3270 if (! used_thr_p_c) 3282 if (! used_thr_p_c)
3271 { 3283 {
3272 /* Reset timeout timer on resume. */ 3284 /* Reset timeout timer on resume. */
3273 if (0 != pos->connection_timeout) 3285 if (0 != pos->connection_timeout_ms)
3274 pos->last_activity = MHD_monotonic_sec_counter (); 3286 pos->last_activity = MHD_monotonic_msec_counter ();
3275 3287
3276 if (pos->connection_timeout == daemon->connection_timeout) 3288 if (pos->connection_timeout_ms == daemon->connection_timeout_ms)
3277 XDLL_insert (daemon->normal_timeout_head, 3289 XDLL_insert (daemon->normal_timeout_head,
3278 daemon->normal_timeout_tail, 3290 daemon->normal_timeout_tail,
3279 pos); 3291 pos);
@@ -3824,10 +3836,9 @@ enum MHD_Result
3824MHD_get_timeout (struct MHD_Daemon *daemon, 3836MHD_get_timeout (struct MHD_Daemon *daemon,
3825 MHD_UNSIGNED_LONG_LONG *timeout) 3837 MHD_UNSIGNED_LONG_LONG *timeout)
3826{ 3838{
3827 time_t earliest_deadline; 3839 uint64_t earliest_deadline;
3828 time_t now;
3829 struct MHD_Connection *pos; 3840 struct MHD_Connection *pos;
3830 bool have_timeout; 3841 struct MHD_Connection *earliest_tmot_conn; /**< the connection with earliest timeout */
3831 3842
3832#ifdef MHD_USE_THREADS 3843#ifdef MHD_USE_THREADS
3833 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \ 3844 mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
@@ -3862,44 +3873,63 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
3862 } 3873 }
3863#endif /* EPOLL_SUPPORT */ 3874#endif /* EPOLL_SUPPORT */
3864 3875
3865 have_timeout = false; 3876 earliest_tmot_conn = NULL;
3866 earliest_deadline = 0; /* avoid compiler warnings */ 3877 earliest_deadline = 0; /* mute compiler warning */
3867 for (pos = daemon->manual_timeout_tail; NULL != pos; pos = pos->prevX)
3868 {
3869 if (0 != pos->connection_timeout)
3870 {
3871 if ( (! have_timeout) ||
3872 (earliest_deadline - pos->last_activity > pos->connection_timeout) )
3873 earliest_deadline = pos->last_activity + pos->connection_timeout;
3874 have_timeout = true;
3875 }
3876 }
3877 /* normal timeouts are sorted, so we only need to look at the 'tail' (oldest) */ 3878 /* normal timeouts are sorted, so we only need to look at the 'tail' (oldest) */
3878 pos = daemon->normal_timeout_tail; 3879 pos = daemon->normal_timeout_tail;
3879 if ( (NULL != pos) && 3880 if ( (NULL != pos) &&
3880 (0 != pos->connection_timeout) ) 3881 (0 != pos->connection_timeout_ms) )
3881 { 3882 {
3882 if ( (! have_timeout) || 3883 earliest_tmot_conn = pos;
3883 (earliest_deadline - pos->connection_timeout > pos->last_activity) ) 3884 earliest_deadline = pos->last_activity + pos->connection_timeout_ms;
3884 earliest_deadline = pos->last_activity + pos->connection_timeout;
3885 have_timeout = true;
3886 } 3885 }
3887 3886
3888 if (! have_timeout) 3887 for (pos = daemon->manual_timeout_tail; NULL != pos; pos = pos->prevX)
3889 return MHD_NO;
3890 now = MHD_monotonic_sec_counter ();
3891 if (earliest_deadline < now)
3892 *timeout = 0;
3893 else
3894 { 3888 {
3895 const time_t second_left = earliest_deadline - now; 3889 if (0 != pos->connection_timeout_ms)
3890 {
3891 if ( (NULL == earliest_tmot_conn) ||
3892 (earliest_deadline - pos->last_activity >
3893 pos->connection_timeout_ms) )
3894 {
3895 earliest_tmot_conn = pos;
3896 earliest_deadline = pos->last_activity + pos->connection_timeout_ms;
3897 }
3898 }
3899 }
3896 3900
3897 if (((unsigned long long) second_left) > ULLONG_MAX / 1000) 3901 if (NULL != earliest_tmot_conn)
3898 *timeout = ULLONG_MAX; 3902 {
3903 const uint64_t since_actv = MHD_monotonic_msec_counter ()
3904 - earliest_tmot_conn->last_activity;
3905 /* Keep the next lines in sync with #MHD_connection_handle_idle() and
3906 * with #thread_main_handle_connection(). */
3907 if (since_actv > earliest_tmot_conn->connection_timeout_ms)
3908 *timeout = 0;
3909 else if (since_actv == earliest_tmot_conn->connection_timeout_ms)
3910 {
3911 /* Exact match for timeout and time from last activity.
3912 * Maybe this is just a precise match or this happens because the timer
3913 * resolution is too low.
3914 * Set wait time to 0.1 seconds to avoid busy-waiting with low
3915 * timer resolution as connection is not yet timed-out */
3916 *timeout = 100;
3917 }
3899 else 3918 else
3900 *timeout = 1000LLU * (unsigned long long) second_left; 3919 {
3920 const uint64_t mssecond_left = earliest_tmot_conn->connection_timeout_ms
3921 - since_actv;
3922
3923#if UINT64_MAX != ULLONG_MAX
3924 if (mssecond_left > ULLONG_MAX)
3925 *timeout = ULLONG_MAX;
3926 else
3927#endif /* UINT64 != ULLONG_MAX */
3928 *timeout = (unsigned long long) mssecond_left;
3929 }
3930 return MHD_YES;
3901 } 3931 }
3902 return MHD_YES; 3932 return MHD_NO;
3903} 3933}
3904 3934
3905 3935
@@ -5247,7 +5277,7 @@ close_connection (struct MHD_Connection *pos)
5247#endif 5277#endif
5248 mhd_assert (! pos->suspended); 5278 mhd_assert (! pos->suspended);
5249 mhd_assert (! pos->resuming); 5279 mhd_assert (! pos->resuming);
5250 if (pos->connection_timeout == daemon->connection_timeout) 5280 if (pos->connection_timeout_ms == daemon->connection_timeout_ms)
5251 XDLL_remove (daemon->normal_timeout_head, 5281 XDLL_remove (daemon->normal_timeout_head,
5252 daemon->normal_timeout_tail, 5282 daemon->normal_timeout_tail,
5253 pos); 5283 pos);
@@ -5593,20 +5623,22 @@ parse_options_va (struct MHD_Daemon *daemon,
5593 case MHD_OPTION_CONNECTION_TIMEOUT: 5623 case MHD_OPTION_CONNECTION_TIMEOUT:
5594 uv = va_arg (ap, 5624 uv = va_arg (ap,
5595 unsigned int); 5625 unsigned int);
5596 daemon->connection_timeout = (time_t) uv; 5626#if (0 == (UINT64_MAX + 0)) || ((UINT_MAX + 0) >= (UINT64_MAX + 0))
5597 /* Next comparison could be always false on some platforms and whole branch will 5627 if ((UINT64_MAX / 2000 - 1) < uv)
5598 * be optimized out on those platforms. On others it will be compiled into real
5599 * check. */
5600 if ( ( (MHD_TYPE_IS_SIGNED_ (time_t)) &&
5601 (daemon->connection_timeout < 0) ) || /* Compiler may warn on some platforms, ignore warning. */
5602 (uv != (unsigned int) daemon->connection_timeout) )
5603 { 5628 {
5604#ifdef HAVE_MESSAGES 5629#ifdef HAVE_MESSAGES
5605 MHD_DLOG (daemon, 5630 MHD_DLOG (daemon,
5606 _ ("Warning: Too large timeout value, ignored.\n")); 5631 _ ("The specified connection timeout (%u) is too large. " \
5632 "Maximum allowed value (" PRIu64 ") will be used " \
5633 "instead.\n"),
5634 uv,
5635 (UINT64_MAX / 2000 - 1));
5607#endif 5636#endif
5608 daemon->connection_timeout = 0; 5637 daemon->connection_timeout_ms = UINT64_MAX / 2000 - 1;
5609 } 5638 }
5639 else
5640#endif /* UINTMAX_MAX >= UINT64_MAX */
5641 daemon->connection_timeout_ms = uv * 1000;
5610 break; 5642 break;
5611 case MHD_OPTION_NOTIFY_COMPLETED: 5643 case MHD_OPTION_NOTIFY_COMPLETED:
5612 daemon->notify_completed = va_arg (ap, 5644 daemon->notify_completed = va_arg (ap,
@@ -6444,7 +6476,7 @@ MHD_start_daemon_va (unsigned int flags,
6444 daemon->pool_size = MHD_POOL_SIZE_DEFAULT; 6476 daemon->pool_size = MHD_POOL_SIZE_DEFAULT;
6445 daemon->pool_increment = MHD_BUF_INC_SIZE; 6477 daemon->pool_increment = MHD_BUF_INC_SIZE;
6446 daemon->unescape_callback = &unescape_wrapper; 6478 daemon->unescape_callback = &unescape_wrapper;
6447 daemon->connection_timeout = 0; /* no timeout */ 6479 daemon->connection_timeout_ms = 0; /* no timeout */
6448 MHD_itc_set_invalid_ (daemon->itc); 6480 MHD_itc_set_invalid_ (daemon->itc);
6449#ifdef SOMAXCONN 6481#ifdef SOMAXCONN
6450 daemon->listen_backlog_size = SOMAXCONN; 6482 daemon->listen_backlog_size = SOMAXCONN;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 9db32af1..a9f5e141 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -43,6 +43,13 @@
43#include <stdbool.h> 43#include <stdbool.h>
44#endif 44#endif
45 45
46#ifdef HAVE_INTTYPES_H
47#include <inttypes.h>
48#endif /* HAVE_INTTYPES_H */
49
50#ifndef PRIu64
51#define PRIu64 "llu"
52#endif /* ! PRIu64 */
46 53
47#ifdef MHD_PANIC 54#ifdef MHD_PANIC
48/* Override any defined MHD_PANIC macro with proper one */ 55/* Override any defined MHD_PANIC macro with proper one */
@@ -1143,13 +1150,14 @@ struct MHD_Connection
1143 * Last time this connection had any activity 1150 * Last time this connection had any activity
1144 * (reading or writing). 1151 * (reading or writing).
1145 */ 1152 */
1146 time_t last_activity; 1153 uint64_t last_activity;
1147 1154
1148 /** 1155 /**
1149 * After how many seconds of inactivity should 1156 * After how many milliseconds of inactivity should
1150 * this connection time out? Zero for no timeout. 1157 * this connection time out?
1158 * Zero for no timeout.
1151 */ 1159 */
1152 time_t connection_timeout; 1160 uint64_t connection_timeout_ms;
1153 1161
1154 /** 1162 /**
1155 * Special member to be returned by #MHD_get_connection_info() 1163 * Special member to be returned by #MHD_get_connection_info()
@@ -1707,7 +1715,7 @@ struct MHD_Daemon
1707 * moved back to the tail of the list. 1715 * moved back to the tail of the list.
1708 * 1716 *
1709 * All connections by default start in this list; if a custom 1717 * All connections by default start in this list; if a custom
1710 * timeout that does not match @e connection_timeout is set, they 1718 * timeout that does not match @e connection_timeout_ms is set, they
1711 * are moved to the @e manual_timeout_head-XDLL. 1719 * are moved to the @e manual_timeout_head-XDLL.
1712 * Not used in MHD_USE_THREAD_PER_CONNECTION mode as each thread 1720 * Not used in MHD_USE_THREAD_PER_CONNECTION mode as each thread
1713 * needs only one connection-specific timeout. 1721 * needs only one connection-specific timeout.
@@ -1968,10 +1976,11 @@ struct MHD_Daemon
1968 unsigned int connection_limit; 1976 unsigned int connection_limit;
1969 1977
1970 /** 1978 /**
1971 * After how many seconds of inactivity should 1979 * After how many milliseconds of inactivity should
1972 * connections time out? Zero for no timeout. 1980 * this connection time out?
1981 * Zero for no timeout.
1973 */ 1982 */
1974 time_t connection_timeout; 1983 uint64_t connection_timeout_ms;
1975 1984
1976 /** 1985 /**
1977 * Maximum number of connections per IP, or 0 for 1986 * Maximum number of connections per IP, or 0 for