From a248c0ec45f0ce6ffe349d0fc865fd536033f73f Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 25 Oct 2018 13:47:13 +0200 Subject: system: provide a means to replace gettime implementation While gettime() is extensively used in the code, the library previously hadn't provided a way to replace it for testing. This adds a new internal function _gnutls_global_set_gettime_function and makes use of it through virt-time.h. Signed-off-by: Daiki Ueno --- lib/buffers.c | 8 ++++---- lib/dtls.c | 8 ++++---- lib/dtls.h | 2 +- lib/ext/heartbeat.c | 8 ++++---- lib/handshake.c | 2 +- lib/handshake.h | 2 +- lib/libgnutls.map | 2 ++ lib/nettle/rnd.c | 2 +- lib/system.c | 22 ++++++++++++++++++++++ lib/system.h | 19 +++++-------------- tests/virt-time.h | 27 +++++++++++++++++++++------ 11 files changed, 66 insertions(+), 36 deletions(-) diff --git a/lib/buffers.c b/lib/buffers.c index cee0d5fc59..78fe6e22cc 100644 --- a/lib/buffers.c +++ b/lib/buffers.c @@ -252,7 +252,7 @@ _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel, ret = _gnutls_io_check_recv(session, *ms); if (ret < 0) return gnutls_assert_val(ret); - gettime(&t1); + gnutls_gettime(&t1); } *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session)); @@ -287,7 +287,7 @@ _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel, } if (ms && *ms > 0) { - gettime(&t2); + gnutls_gettime(&t2); diff = timespec_sub_ms(&t2, &t1); if (diff < *ms) *ms -= diff; @@ -338,7 +338,7 @@ _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel, goto cleanup; } - gettime(&t1); + gnutls_gettime(&t1); } reset_errno(session); @@ -383,7 +383,7 @@ _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel, (*bufel)->msg.size += i; if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) { - gettime(&t2); + gnutls_gettime(&t2); diff = timespec_sub_ms(&t2, &t1); if (diff < *ms) *ms -= diff; diff --git a/lib/dtls.c b/lib/dtls.c index 07c3495a46..a22379ece1 100644 --- a/lib/dtls.c +++ b/lib/dtls.c @@ -234,7 +234,7 @@ int _dtls_transmit(gnutls_session_t session) unsigned int diff; struct timespec now; - gettime(&now); + gnutls_gettime(&now); /* If we have already sent a flight and we are operating in a * non blocking way, check if it is time to retransmit or just @@ -321,7 +321,7 @@ int _dtls_transmit(gnutls_session_t session) last_type = cur->htype; } - gettime(&session->internals.dtls.last_retransmit); + gnutls_gettime(&session->internals.dtls.last_retransmit); if (session->internals.dtls.flight_init == 0) { session->internals.dtls.flight_init = 1; @@ -391,7 +391,7 @@ int _dtls_transmit(gnutls_session_t session) } keep_up: - gettime(&now); + gnutls_gettime(&now); } while (ret == GNUTLS_E_TIMEDOUT); if (ret < 0) { @@ -789,7 +789,7 @@ unsigned int gnutls_dtls_get_timeout(gnutls_session_t session) struct timespec now; unsigned int diff; - gettime(&now); + gnutls_gettime(&now); diff = timespec_sub_ms(&now, diff --git a/lib/dtls.h b/lib/dtls.h index c7e72cf9b7..717d3bdc6d 100644 --- a/lib/dtls.h +++ b/lib/dtls.h @@ -40,7 +40,7 @@ void _dtls_reset_window(struct record_parameters_st *rp); #define RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, r) { \ struct timespec _now; \ unsigned int _diff; \ - gettime(&_now); \ + gnutls_gettime(&_now); \ \ _diff = timespec_sub_ms(&_now, &session->internals.handshake_start_time); \ if (_diff > session->internals.handshake_timeout_ms) \ diff --git a/lib/ext/heartbeat.c b/lib/ext/heartbeat.c index 1b970fbc46..7ec26a9804 100644 --- a/lib/ext/heartbeat.c +++ b/lib/ext/heartbeat.c @@ -202,7 +202,7 @@ gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size, if (ret < 0) return gnutls_assert_val(ret); - gettime(&session->internals.hb_ping_start); + gnutls_gettime(&session->internals.hb_ping_start); session->internals.hb_local_data.length = data_size; session->internals.hb_state = SHB_SEND2; @@ -220,7 +220,7 @@ gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size, if (ret < 0) return gnutls_assert_val(ret); - gettime(&session->internals.hb_ping_sent); + gnutls_gettime(&session->internals.hb_ping_sent); if (!(flags & GNUTLS_HEARTBEAT_WAIT)) { session->internals.hb_state = SHB_SEND1; @@ -246,7 +246,7 @@ gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size, return gnutls_assert_val(ret); } - gettime(&now); + gnutls_gettime(&now); diff = timespec_sub_ms(&now, &session->internals. @@ -405,7 +405,7 @@ unsigned int gnutls_heartbeat_get_timeout(gnutls_session_t session) struct timespec now; unsigned int diff; - gettime(&now); + gnutls_gettime(&now); diff = timespec_sub_ms(&now, &session->internals.hb_ping_sent); if (diff >= session->internals.hb_actual_retrans_timeout_ms) return 0; diff --git a/lib/handshake.c b/lib/handshake.c index 841c88385d..a20c7a302a 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -2679,7 +2679,7 @@ int gnutls_handshake(gnutls_session_t session) session->internals.hsk_flags = 0; session->internals.handshake_in_progress = 1; session->internals.vc_status = -1; - gettime(&session->internals.handshake_start_time); + gnutls_gettime(&session->internals.handshake_start_time); if (session->internals.handshake_timeout_ms && session->internals.handshake_endtime == 0) session->internals.handshake_endtime = session->internals.handshake_start_time.tv_sec + diff --git a/lib/handshake.h b/lib/handshake.h index 38ef848784..ee5ee7a437 100644 --- a/lib/handshake.h +++ b/lib/handshake.h @@ -116,7 +116,7 @@ inline static int handshake_remaining_time(gnutls_session_t session) { if (session->internals.handshake_endtime) { struct timespec now; - gettime(&now); + gnutls_gettime(&now); if (now.tv_sec < session->internals.handshake_endtime) return (session->internals.handshake_endtime - diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 041fda7b80..ad6613b907 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1326,4 +1326,6 @@ GNUTLS_PRIVATE_3_4 { _gnutls_server_name_set_raw; # Internal symbols needed by tests/suite/resume-with-stek-expiration _gnutls_set_session_ticket_key_rotation_callback; + # Internal symbols needed by tests/virt-time.h + _gnutls_global_set_gettime_function; } GNUTLS_3_4; diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index 9d8b250012..3f816d43ae 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -106,7 +106,7 @@ static int single_prng_init(struct prng_ctx_st *ctx, ctx->forkid = _gnutls_get_forkid(); - gettime(&now); + gnutls_gettime(&now); memcpy(nonce, &now, MIN(sizeof(nonce), sizeof(now))); ctx->last_reseed = now.tv_sec; } diff --git a/lib/system.c b/lib/system.c index 1a17974d58..1bbbf79c84 100644 --- a/lib/system.c +++ b/lib/system.c @@ -44,6 +44,26 @@ static HMODULE Crypt32_dll; /* System specific function wrappers for certificate stores. */ gnutls_time_func gnutls_time; +gnutls_gettime_func gnutls_gettime; + +/* emulate gnulib's gettime using gettimeofday to avoid linking to + * librt */ +static void _gnutls_gettime(struct timespec *t) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + clock_gettime(CLOCK_REALTIME, t); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + t->tv_sec = tv.tv_sec; + t->tv_nsec = tv.tv_usec * 1000; +#endif +} + +void _gnutls_global_set_gettime_function(gnutls_gettime_func gettime_func) +{ + gnutls_gettime = gettime_func; +} int gnutls_system_global_init(void) { @@ -66,6 +86,7 @@ int gnutls_system_global_init(void) Crypt32_dll = crypto; #endif gnutls_time = time; + gnutls_gettime = _gnutls_gettime; return 0; } @@ -75,6 +96,7 @@ void gnutls_system_global_deinit(void) FreeLibrary(Crypt32_dll); #endif gnutls_time = time; + gnutls_gettime = _gnutls_gettime; } diff --git a/lib/system.h b/lib/system.h index 0ae3c63b17..6a948f858d 100644 --- a/lib/system.h +++ b/lib/system.h @@ -77,7 +77,10 @@ ssize_t system_read(gnutls_transport_ptr_t ptr, void *data, # define HAVE_NO_LOCKS #endif +typedef void (*gnutls_gettime_func) (struct timespec *); + extern gnutls_time_func gnutls_time; +extern gnutls_gettime_func gnutls_gettime; static inline void millisleep(unsigned int ms) { @@ -93,26 +96,14 @@ static inline void millisleep(unsigned int ms) #endif } -/* emulate gnulib's gettime using gettimeofday to avoid linking to - * librt */ -inline static void gettime(struct timespec *t) -{ -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) - clock_gettime(CLOCK_REALTIME, t); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - t->tv_sec = tv.tv_sec; - t->tv_nsec = tv.tv_usec * 1000; -#endif -} - int _gnutls_find_config_path(char *path, size_t max_size); int _gnutls_ucs2_to_utf8(const void *data, size_t size, gnutls_datum_t * output, unsigned bigendian); int _gnutls_utf8_to_ucs2(const void *data, size_t size, gnutls_datum_t * output); +void _gnutls_global_set_gettime_function(gnutls_gettime_func gettime_func); + int gnutls_system_global_init(void); void gnutls_system_global_deinit(void); diff --git a/tests/virt-time.h b/tests/virt-time.h index 02c8cdb147..0dd35df299 100644 --- a/tests/virt-time.h +++ b/tests/virt-time.h @@ -29,19 +29,28 @@ #include #include +/* copied from ../lib/system.h so not to include that header from + * every test program */ +typedef void (*gnutls_gettime_func) (struct timespec *); +extern void _gnutls_global_set_gettime_function(gnutls_gettime_func gettime_func); + /* virtualize time in a test. This freezes the time in the test, except for * the advances due to calls to virt_sleep_sec(). This makes the test - * independent of the test system load, and avoids any long delays. - * - * This only affects the parts of the library that utilize gnutls_time(), - * not the higher precision gettime */ -static time_t _now = 0; + * independent of the test system load, and avoids any long delays. */ +static time_t _now; +static struct timespec _now_ts; -#define virt_sec_sleep(s) _now += s +#define virt_sec_sleep(s) { \ + _now += s; \ + _now_ts.tv_sec += s; \ + } #define virt_time_init() { \ _now = time(0); \ gnutls_global_set_time_function(mytime); \ + _now_ts.tv_sec = _now; \ + _now_ts.tv_nsec = 0; \ + _gnutls_global_set_gettime_function(mygettime); \ } @@ -53,4 +62,10 @@ static time_t mytime(time_t * t) return _now; } +static void mygettime(struct timespec * t) +{ + if (t) + *t = _now_ts; +} + #endif -- cgit v1.2.1