Change various uses of time(NULL) to new MHD_monotonic_time() function to make timeouts immune to the system real time clock changing. Leave one call to time(2) which continues to use the real time for the HTTP Date: header.
If clock_gettime does not support CLOCK_MONOTONIC then fall through to calling time(NULL) instead. This will be problematic if clock_gettime sometimes fails and sometimes succeeds but that shouldn't happen. The autoconf magic was lifted from http://lists.gnu.org/archive/html/autoconf/2010-08/msg00035.html --- configure.ac | 3 +++ src/daemon/connection.c | 6 +++--- src/daemon/connection_https.c | 4 ++-- src/daemon/daemon.c | 7 +++---- src/daemon/digestauth.c | 4 ++-- src/daemon/internal.c | 10 ++++++++++ src/daemon/internal.h | 6 ++++++ 7 files changed, 29 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 41d5472..7b47278 100644 --- a/configure.ac +++ b/configure.ac @@ -190,6 +190,9 @@ AC_CHECK_HEADERS([plibc.h],our_private_plibc_h=0,our_private_plibc_h=1) AM_CONDITIONAL(USE_PRIVATE_PLIBC_H, test x$our_private_plibc_h = x1) AC_CHECK_FUNCS(memmem) +AC_SEARCH_LIBS([clock_gettime], [rt], [ + AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Have clock_gettime]) +]) # IPv6 AC_MSG_CHECKING(for IPv6) diff --git a/src/daemon/connection.c b/src/daemon/connection.c index acc4839..13c465b 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c @@ -1786,7 +1786,7 @@ parse_connection_headers (struct MHD_Connection *connection) int MHD_connection_handle_read (struct MHD_Connection *connection) { - connection->last_activity = time (NULL); + connection->last_activity = MHD_monotonic_time(); if (connection->state == MHD_CONNECTION_CLOSED) return MHD_YES; /* make sure "read" has a reasonable number of bytes @@ -1851,7 +1851,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) { struct MHD_Response *response; int ret; - connection->last_activity = time (NULL); + connection->last_activity = MHD_monotonic_time(); while (1) { #if DEBUG_STATES @@ -2372,7 +2372,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } timeout = connection->connection_timeout; if ( (timeout != 0) && - (timeout <= (time (NULL) - connection->last_activity)) ) + (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) { MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); return MHD_YES; diff --git a/src/daemon/connection_https.c b/src/daemon/connection_https.c index 1330c3a..539b8de 100644 --- a/src/daemon/connection_https.c +++ b/src/daemon/connection_https.c @@ -47,7 +47,7 @@ run_tls_handshake (struct MHD_Connection *connection) { int ret; - connection->last_activity = time (NULL); + connection->last_activity = MHD_monotonic_time(); if (connection->state == MHD_TLS_CONNECTION_INIT) { ret = gnutls_handshake (connection->tls_session); @@ -138,7 +138,7 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection) __FUNCTION__, MHD_state_to_string (connection->state)); #endif timeout = connection->connection_timeout; - if ( (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) + if ( (timeout != 0) && (MHD_monotonic_time() - timeout > connection->last_activity)) MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); switch (connection->state) diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 29d7ced..451bb39 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c @@ -546,7 +546,6 @@ MHD_get_fdset (struct MHD_Daemon *daemon, return MHD_YES; } - /** * Main function of the thread that handles an individual * connection when MHD_USE_THREAD_PER_CONNECTION is set. @@ -578,7 +577,7 @@ MHD_handle_connection (void *data) tvp = NULL; if (timeout > 0) { - now = time (NULL); + now = MHD_monotonic_time(); if (now - con->last_activity > timeout) tv.tv_sec = 0; else @@ -938,7 +937,7 @@ MHD_add_connection (struct MHD_Daemon *daemon, connection->addr_len = addrlen; connection->socket_fd = client_socket; connection->daemon = daemon; - connection->last_activity = time (NULL); + connection->last_activity = MHD_monotonic_time(); /* set default connection handlers */ MHD_set_http_callbacks_ (connection); @@ -1252,7 +1251,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon, } if (!have_timeout) return MHD_NO; - now = time (NULL); + now = MHD_monotonic_time(); if (earliest_deadline < now) *timeout = 0; else diff --git a/src/daemon/digestauth.c b/src/daemon/digestauth.c index 1e976bb..1f9547c 100644 --- a/src/daemon/digestauth.c +++ b/src/daemon/digestauth.c @@ -619,7 +619,7 @@ MHD_digest_auth_check(struct MHD_Connection *connection, /* 8 = 4 hexadecimal numbers for the timestamp */ nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16); - t = (uint32_t) time(NULL); + t = (uint32_t) MHD_monotonic_time(); /* * First level vetting for the nonce validity if the timestamp * attached to the nonce exceeds `nonce_timeout' then the nonce is @@ -751,7 +751,7 @@ MHD_queue_auth_fail_response(struct MHD_Connection *connection, char nonce[HASH_MD5_HEX_LEN + 9]; /* Generating the server nonce */ - calculate_nonce ((uint32_t) time(NULL), + calculate_nonce ((uint32_t) MHD_monotonic_time(), connection->method, connection->daemon->digest_auth_random, connection->daemon->digest_auth_rand_size, diff --git a/src/daemon/internal.c b/src/daemon/internal.c index 3b0a544..453634e 100644 --- a/src/daemon/internal.c +++ b/src/daemon/internal.c @@ -157,4 +157,14 @@ MHD_http_unescape (void *cls, return wpos - val; /* = strlen(val) */ } +time_t MHD_monotonic_time(void) +{ +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return ts.tv_sec; +#endif + return time(NULL); +} + /* end of internal.c */ diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 6e15af2..15900f1 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h @@ -1057,5 +1057,11 @@ struct MHD_Daemon (element)->next = NULL; \ (element)->prev = NULL; } while (0) +/** + * Equivalent to time(NULL) but tries to use some sort of monotonic + * clock that isn't affected by someone setting the system real time + * clock. + */ +time_t MHD_monotonic_time(void); #endif -- 1.7.10
