aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r--src/microhttpd/daemon.c152
1 files changed, 92 insertions, 60 deletions
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;