Reimplement monotonic clock with wide range of platforms support

This commit is contained in:
Evgeny Grin (Karlson2k)
2015-08-27 09:43:09 +00:00
parent 0d2688a98b
commit 70f7ad46eb
14 changed files with 429 additions and 42 deletions
+4
View File
@@ -1,3 +1,7 @@
Thu Aug 27 09:38:44 CEST 2015
Reimplement monotonic clock functions for better
support various platforms. -EG
Fri Aug 14 14:13:55 CEST 2015
Export MHD_get_reason_phrase_for() symbol. -CG
+34
View File
@@ -451,6 +451,40 @@ AC_SEARCH_LIBS([clock_gettime], [rt], [
AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Have clock_gettime])
])
AC_MSG_CHECKING([[for clock_get_time]])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <mach/clock.h>
#include <mach/mach.h>
]],
[[
clock_serv_t cs;
mach_timespec_t mt;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs);
clock_get_time(cs, &mt);
mach_port_deallocate(mach_task_self(), cs);
]])
],
[
AC_DEFINE([HAVE_CLOCK_GET_TIME], [1], [Define to 1 if you have `clock_get_time', `host_get_clock_service' and `mach_port_deallocate' functions.])
AC_MSG_RESULT([[yes]])
],
[AC_MSG_RESULT([[no]])
])
AC_MSG_CHECKING([[for gethrtime]])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <sys/time.h>]], [[hrtime_t hrt = gethrtime(); ]])
],
[
AC_DEFINE([HAVE_GETHRTIME], [1], [Define to 1 if you have `gethrtime' function.])
AC_MSG_RESULT([[yes]])
],
[AC_MSG_RESULT([[no]])
])
# IPv6
AC_MSG_CHECKING(for IPv6)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+1 -1
View File
@@ -130,7 +130,7 @@ typedef intptr_t ssize_t;
* Current version of the library.
* 0x01093001 = 1.9.30-1.
*/
#define MHD_VERSION 0x00094209
#define MHD_VERSION 0x00094210
/**
* MHD-internal return code for "YES".
+1
View File
@@ -62,6 +62,7 @@ libmicrohttpd_la_SOURCES = \
daemon.c \
internal.c internal.h \
memorypool.c memorypool.h \
mhd_mono_clock.c mhd_mono_clock.h \
mhd_limits.h mhd_byteorder.h \
response.c response.h
libmicrohttpd_la_CPPFLAGS = \
+3 -2
View File
@@ -30,6 +30,7 @@
#include "connection.h"
#include "memorypool.h"
#include "response.h"
#include "mhd_mono_clock.h"
#if HAVE_NETINET_TCP_H
/* for TCP_CORK */
@@ -1970,7 +1971,7 @@ update_last_activity (struct MHD_Connection *connection)
{
struct MHD_Daemon *daemon = connection->daemon;
connection->last_activity = MHD_monotonic_time();
connection->last_activity = MHD_monotonic_sec_counter();
if (connection->connection_timeout != daemon->connection_timeout)
return; /* custom timeout, no need to move it in "normal" DLL */
@@ -2656,7 +2657,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
}
timeout = connection->connection_timeout;
if ( (0 != timeout) &&
(timeout <= (MHD_monotonic_time() - connection->last_activity)) )
(timeout <= (MHD_monotonic_sec_counter() - connection->last_activity)) )
{
MHD_connection_close (connection,
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
+3 -2
View File
@@ -30,6 +30,7 @@
#include "connection.h"
#include "memorypool.h"
#include "response.h"
#include "mhd_mono_clock.h"
#include <gnutls/gnutls.h>
@@ -46,7 +47,7 @@ run_tls_handshake (struct MHD_Connection *connection)
{
int ret;
connection->last_activity = MHD_monotonic_time();
connection->last_activity = MHD_monotonic_sec_counter();
if (connection->state == MHD_TLS_CONNECTION_INIT)
{
ret = gnutls_handshake (connection->tls_session);
@@ -139,7 +140,7 @@ MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
MHD_state_to_string (connection->state));
#endif
timeout = connection->connection_timeout;
if ( (timeout != 0) && (timeout <= (MHD_monotonic_time() - connection->last_activity)))
if ( (timeout != 0) && (timeout <= (MHD_monotonic_sec_counter() - connection->last_activity)))
MHD_connection_close (connection,
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
switch (connection->state)
+6 -3
View File
@@ -38,6 +38,7 @@
#include "memorypool.h"
#include "mhd_limits.h"
#include "autoinit_funcs.h"
#include "mhd_mono_clock.h"
#if HAVE_SEARCH_H
#include <search.h>
@@ -822,7 +823,7 @@ MHD_handle_connection (void *data)
#endif
if (NULL == tvp && timeout > 0)
{
now = MHD_monotonic_time();
now = MHD_monotonic_sec_counter();
if (now - con->last_activity > timeout)
tv.tv_sec = 0;
else
@@ -1440,7 +1441,7 @@ internal_add_connection (struct MHD_Daemon *daemon,
connection->addr_len = addrlen;
connection->socket_fd = client_socket;
connection->daemon = daemon;
connection->last_activity = MHD_monotonic_time();
connection->last_activity = MHD_monotonic_sec_counter();
/* set default connection handlers */
MHD_set_http_callbacks_ (connection);
@@ -2175,7 +2176,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
if (MHD_NO == have_timeout)
return MHD_NO;
now = MHD_monotonic_time();
now = MHD_monotonic_sec_counter();
if (earliest_deadline < now)
*timeout = 0;
else
@@ -4878,6 +4879,7 @@ void MHD_init(void)
#endif
gnutls_global_init ();
#endif
MHD_monotonic_sec_counter_init();
}
@@ -4890,6 +4892,7 @@ void MHD_fini(void)
if (mhd_winsock_inited_)
WSACleanup();
#endif
MHD_monotonic_sec_counter_finish();
}
_SET_INIT_AND_DEINIT_FUNCS(MHD_init, MHD_fini);
+3 -2
View File
@@ -26,6 +26,7 @@
#include <limits.h>
#include "internal.h"
#include "md5.h"
#include "mhd_mono_clock.h"
#if defined(_WIN32) && defined(MHD_W32_MUTEX_)
#ifndef WIN32_LEAN_AND_MEAN
@@ -643,7 +644,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) MHD_monotonic_time();
t = (uint32_t) MHD_monotonic_sec_counter();
/*
* First level vetting for the nonce validity: if the timestamp
* attached to the nonce exceeds `nonce_timeout', then the nonce is
@@ -820,7 +821,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) MHD_monotonic_time(),
calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(),
connection->method,
connection->daemon->digest_auth_random,
connection->daemon->digest_auth_rand_size,
-21
View File
@@ -171,25 +171,4 @@ MHD_http_unescape (char *val)
}
/**
* 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.
*
* @return 'current' time
*/
time_t
MHD_monotonic_time (void)
{
#ifdef HAVE_CLOCK_GETTIME
#ifdef CLOCK_MONOTONIC
struct timespec ts;
if (0 == clock_gettime (CLOCK_MONOTONIC, &ts))
return ts.tv_sec;
#endif
#endif
return time (NULL);
}
/* end of internal.c */
-11
View File
@@ -1438,17 +1438,6 @@ struct MHD_Daemon
(element)->prevE = 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.
*
* @return 'current' time
*/
time_t
MHD_monotonic_time(void);
/**
* Convert all occurences of '+' to ' '.
*
+312
View File
@@ -0,0 +1,312 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2015 Karlson2k (Evgeny Grin)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file microhttpd/mhd_mono_clock.h
* @brief internal monotonic clock functions implementations
* @author Karlson2k (Evgeny Grin)
*/
#include "mhd_mono_clock.h"
#ifdef HAVE_CLOCK_GET_TIME
#include <mach/mach.h>
/* for host_get_clock_service(), mach_host_self(), mach_task_self() */
#include <mach/clock.h>
/* for clock_get_time() */
#define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
#endif /* HAVE_CLOCK_GET_TIME */
#ifdef HAVE_CLOCK_GETTIME
#ifdef CLOCK_REALTIME
#define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
#else /* !CLOCK_REALTIME */
#define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
#endif /* !CLOCK_REALTIME */
static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
#endif /* HAVE_CLOCK_GETTIME */
/* sync clocks; reduce chance of value wrap */
static time_t mono_clock_start = 0;
static time_t sys_clock_start = 0;
#ifdef HAVE_GETHRTIME
static hrtime_t hrtime_start = 0;
#endif /* HAVE_GETHRTIME */
#ifdef _WIN32
#if _WIN32_WINNT >= 0x0600
static uint64_t tick_start = 0;
#else /* _WIN32_WINNT < 0x0600 */
static int64_t perf_freq = 0;
static int64_t perf_start = 0;
#endif /* _WIN32_WINNT < 0x0600 */
#endif /* _WIN32 */
/**
* Type of monotonic clock source
*/
enum _MHD_mono_clock_source
{
/**
* No monotonic clock
*/
_MHD_CLOCK_NO_SOURCE = 0,
/**
* clock_gettime() with specific clock
*/
_MHD_CLOCK_GETTIME,
/**
* clock_get_time() with specific clock service
*/
_MHD_CLOCK_GET_TIME,
/**
* gethrtime() / 1000000000
*/
_MHD_CLOCK_GETHRTIME,
/**
* GetTickCount64() / 1000
*/
_MHD_CLOCK_GETTICKCOUNT64,
/**
* QueryPerformanceCounter() / QueryPerformanceFrequency()
*/
_MHD_CLOCK_PERFCOUNTER
};
/**
* Initialise monotonic seconds counter.
*/
void
MHD_monotonic_sec_counter_init (void)
{
#ifdef HAVE_CLOCK_GET_TIME
mach_timespec_t cur_time;
#endif /* HAVE_CLOCK_GET_TIME */
enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
#ifdef HAVE_CLOCK_GETTIME
struct timespec ts;
mono_clock_id = _MHD_UNWANTED_CLOCK;
#endif /* HAVE_CLOCK_GETTIME */
#ifdef HAVE_CLOCK_GET_TIME
mono_clock_service = _MHD_INVALID_CLOCK_SERV;
#endif /* HAVE_CLOCK_GET_TIME */
if (0)
{
} else
#ifdef HAVE_CLOCK_GETTIME
#ifdef CLOCK_MONOTONIC_COARSE
/* Linux-specific fast value-getting clock */
/* Can be affected by frequency adjustment and don't count time in suspend, */
/* but preferred since it's fast */
if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE, &ts))
{
mono_clock_id = CLOCK_MONOTONIC_COARSE;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_MONOTONIC_COARSE */
#ifdef CLOCK_MONOTONIC_FAST
/* FreeBSD/DragonFly fast value-getting clock */
/* Can be affected by frequency adjustment, but preferred since it's fast */
if (0 == clock_gettime (CLOCK_MONOTONIC_FAST, &ts))
{
mono_clock_id = CLOCK_MONOTONIC_FAST;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_MONOTONIC_COARSE */
#ifdef CLOCK_MONOTONIC_RAW
/* Linux-specific clock */
/* Not affected by frequency adjustment, but don't count time in suspend */
if (0 == clock_gettime (CLOCK_MONOTONIC_RAW , &ts))
{
mono_clock_id = CLOCK_MONOTONIC_RAW;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_MONOTONIC_RAW */
#ifdef CLOCK_BOOTTIME
/* Linux-specific clock */
/* Count time in suspend so it's real monotonic on Linux, */
/* but can be slower value-getting than other clocks */
if (0 == clock_gettime(CLOCK_BOOTTIME, &ts))
{
mono_clock_id = CLOCK_BOOTTIME;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_BOOTTIME */
#ifdef CLOCK_MONOTONIC
/* Monotonic clock */
/* Widely supported, may be affected by frequency adjustment */
/* On Linux it's not truly monotonic as it doesn't count time in suspend */
if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
{
mono_clock_id = CLOCK_MONOTONIC;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_BOOTTIME */
#endif /* HAVE_CLOCK_GETTIME */
#ifdef HAVE_CLOCK_GET_TIME
/* Darwin-specific monotonic clock */
/* Should be monotonic as clock_set_time function always unconditionally */
/* failed on latest kernels */
if (KERN_SUCCESS == host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mono_clock_service) &&
KERN_SUCCESS == clock_get_time(mono_clock_service, &cur_time))
{
mono_clock_start = cur_time.tv_sec;
mono_clock_source = _MHD_CLOCK_GET_TIME;
} else
#endif /* HAVE_CLOCK_GET_TIME */
#ifdef _WIN32
#if _WIN32_WINNT >= 0x0600
/* W32 Vista or later specific monotonic clock */
/* Available since Vista, ~15ms accuracy */
if (1)
{
tick_start = GetTickCount64();
mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
} else
#else /* _WIN32_WINNT < 0x0600 */
/* W32 specific monotonic clock */
/* Available on Windows 2000 and later */
if (1)
{
LARGE_INTEGER freq, perf_counter;
QueryPerformanceFrequency(&freq); /* never fail on XP and later */
QueryPerformanceCounter(&perf_counter); /* never fail on XP and later */
perf_freq = freq.QuadPart;
perf_start = perf_counter.QuadPart;
mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
} else
#endif /* _WIN32_WINNT < 0x0600 */
#endif /* _WIN32 */
#ifdef HAVE_CLOCK_GETTIME
#ifdef CLOCK_HIGHRES
/* Solaris-specific monotonic high-resolution clock */
/* Not preferred due to be potentially resource-hungry */
if (0 == clock_gettime(CLOCK_HIGHRES, &ts))
{
mono_clock_id = CLOCK_HIGHRES;
mono_clock_start = ts.tv_sec;
mono_clock_source = _MHD_CLOCK_GETTIME;
} else
#endif /* CLOCK_HIGHRES */
#endif /* HAVE_CLOCK_GETTIME */
#ifdef HAVE_GETHRTIME
/* HP-UX and Solaris monotonic clock */
/* Not preferred due to be potentially resource-hungry */
if (1)
{
hrtime_start = gethrtime();
mono_clock_source = _MHD_CLOCK_GETHRTIME;
} else
#endif /* HAVE_GETHRTIME */
{
/* no suitable clock source was found */
mono_clock_source = _MHD_CLOCK_NO_SOURCE;
}
#ifdef HAVE_CLOCK_GET_TIME
if (_MHD_CLOCK_GET_TIME != mono_clock_source &&
_MHD_INVALID_CLOCK_SERV != mono_clock_service)
{
/* clock service was initialised but clock_get_time failed */
mach_port_deallocate(mach_task_self(), mono_clock_service);
mono_clock_service = _MHD_INVALID_CLOCK_SERV;
}
#endif /* HAVE_CLOCK_GET_TIME */
sys_clock_start = time(NULL);
}
/**
* Deinitialise monotonic seconds counter by freeing any allocated resources
*/
void
MHD_monotonic_sec_counter_finish(void)
{
#ifdef HAVE_CLOCK_GET_TIME
if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
{
mach_port_deallocate(mach_task_self(), mono_clock_service);
mono_clock_service = _MHD_INVALID_CLOCK_SERV;
}
#endif /* HAVE_CLOCK_GET_TIME */
}
/**
* Monotonic seconds counter, useful for timeout calculation.
* Tries to be not affected by manually setting the system real time
* clock or adjustments by NTP synchronization.
*
* @return number of seconds from some fixed moment
*/
time_t
MHD_monotonic_sec_counter (void)
{
#ifdef HAVE_CLOCK_GETTIME
struct timespec ts;
if (_MHD_UNWANTED_CLOCK != mono_clock_id &&
0 == clock_gettime (mono_clock_id , &ts))
return ts.tv_sec - mono_clock_start;
#endif /* HAVE_CLOCK_GETTIME */
#ifdef HAVE_CLOCK_GET_TIME
if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
{
mach_timespec_t cur_time;
if (KERN_SUCCESS == clock_get_time(mono_clock_service, &cur_time))
return cur_time.tv_sec - mono_clock_start;
}
#endif /* HAVE_CLOCK_GET_TIME */
#if defined(_WIN32)
#if _WIN32_WINNT >= 0x0600
if (1)
return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
#else /* _WIN32_WINNT < 0x0600 */
if (0 != perf_freq)
{
LARGE_INTEGER perf_counter;
QueryPerformanceCounter(&perf_counter); /* never fail on XP and later */
return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
}
#endif /* _WIN32_WINNT < 0x0600 */
#endif /* _WIN32 */
#ifdef HAVE_GETHRTIME
if (1)
return (time_t)(((uint64_t)(gethrtime() - hrtime_start)) / 1000000000);
#endif /* HAVE_GETHRTIME */
return time(NULL) - sys_clock_start;
}
+54
View File
@@ -0,0 +1,54 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2015 Karlson2k (Evgeny Grin)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file microhttpd/mhd_mono_clock.h
* @brief internal monotonic clock functions declarations
* @author Karlson2k (Evgeny Grin)
*/
#ifndef MHD_MONO_CLOCK_H
#define MHD_MONO_CLOCK_H 1
#include "platform.h"
/**
* Initialise monotonic seconds counter.
*/
void
MHD_monotonic_sec_counter_init(void);
/**
* Deinitialise monotonic seconds counter by freeing any allocated resources
*/
void
MHD_monotonic_sec_counter_finish(void);
/**
* Monotonic seconds counter, useful for timeout calculation.
* Tries to be not affected by manually setting the system real time
* clock or adjustments by NTP synchronization.
*
* @return number of seconds from some fixed moment
*/
time_t
MHD_monotonic_sec_counter(void);
#endif /* MHD_MONO_CLOCK_H */
+2
View File
@@ -75,6 +75,7 @@
<ClCompile Include="..\..\src\microhttpd\internal.c" />
<ClCompile Include="..\..\src\microhttpd\md5.c" />
<ClCompile Include="..\..\src\microhttpd\memorypool.c" />
<ClCompile Include="..\..\src\microhttpd\mhd_mono_clock.c" />
<ClCompile Include="..\..\src\microhttpd\postprocessor.c" />
<ClCompile Include="..\..\src\microhttpd\reason_phrase.c" />
<ClCompile Include="..\..\src\microhttpd\response.c" />
@@ -94,6 +95,7 @@
<ClInclude Include="..\..\src\microhttpd\memorypool.h" />
<ClInclude Include="..\..\src\microhttpd\mhd_byteorder.h" />
<ClInclude Include="..\..\src\microhttpd\mhd_limits.h" />
<ClInclude Include="..\..\src\microhttpd\mhd_mono_clock.h" />
<ClInclude Include="..\..\src\microhttpd\reason_phrase.h" />
<ClInclude Include="..\..\src\microhttpd\response.h" />
<ClInclude Include="..\..\src\microhttpd\tsearch.h" />
+6
View File
@@ -61,6 +61,9 @@
<ClCompile Include="..\..\src\microhttpd\tsearch.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\microhttpd\mhd_mono_clock.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\microhttpd\base64.h">
@@ -111,6 +114,9 @@
<ClInclude Include="..\..\src\microhttpd\mhd_byteorder.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\microhttpd\mhd_mono_clock.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="microhttpd_dll_res_vc.rc">