diff options
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 152 |
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 | |||
3824 | MHD_get_timeout (struct MHD_Daemon *daemon, | 3836 | MHD_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; |