From 9426751b72e922b5ee2b00bcc6158f5651a81014 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 21 Jun 2018 17:33:49 -0400 Subject: [PATCH] Extract our code for answering "what time is it right now". The other time stuff is higher-level --- .gitignore | 2 + Makefile.am | 2 + src/common/compat_time.c | 53 ------------------ src/common/compat_time.h | 5 +- src/common/log.c | 2 + src/common/util.c | 31 ----------- src/common/util.h | 10 +--- src/include.am | 1 + src/lib/wallclock/.may_include | 4 ++ src/lib/wallclock/approx_time.c | 38 +++++++++++++ src/lib/wallclock/approx_time.h | 20 +++++++ src/lib/wallclock/include.am | 19 +++++++ src/lib/wallclock/tor_gettimeofday.c | 82 ++++++++++++++++++++++++++++ src/lib/wallclock/tor_gettimeofday.h | 15 +++++ 14 files changed, 188 insertions(+), 96 deletions(-) create mode 100644 src/lib/wallclock/.may_include create mode 100644 src/lib/wallclock/approx_time.c create mode 100644 src/lib/wallclock/approx_time.h create mode 100644 src/lib/wallclock/include.am create mode 100644 src/lib/wallclock/tor_gettimeofday.c create mode 100644 src/lib/wallclock/tor_gettimeofday.h diff --git a/.gitignore b/.gitignore index deb3693811..343517fdf4 100644 --- a/.gitignore +++ b/.gitignore @@ -178,6 +178,8 @@ uptime-*.json /src/lib/libtor-tls.a /src/lib/libtor-tls-testing.a /src/lib/libtor-trace.a +/src/lib/libtor-wallclock.a +/src/lib/libtor-wallclock-testing.a # /src/or/ /src/or/Makefile diff --git a/Makefile.am b/Makefile.am index 1b71e478f9..a83041fbe0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,7 @@ TOR_UTIL_LIBS = \ src/common/libor.a \ src/lib/libtor-container.a \ src/lib/libtor-malloc.a \ + src/lib/libtor-wallclock.a \ src/lib/libtor-err.a \ src/lib/libtor-ctime.a @@ -51,6 +52,7 @@ TOR_UTIL_TESTING_LIBS = \ src/common/libor-testing.a \ src/lib/libtor-container-testing.a \ src/lib/libtor-malloc-testing.a \ + src/lib/libtor-wallclock-testing.a \ src/lib/libtor-err-testing.a \ src/lib/libtor-ctime-testing.a diff --git a/src/common/compat_time.c b/src/common/compat_time.c index 4bb64f1e8f..d3cbd02c6f 100644 --- a/src/common/compat_time.c +++ b/src/common/compat_time.c @@ -38,12 +38,6 @@ #include "common/torlog.h" #include "common/util.h" -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_FTIME -#include -#endif -#endif - #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME #endif @@ -68,53 +62,6 @@ tor_sleep_msec(int msec) } #endif /* defined(TOR_UNIT_TESTS) */ -/** Set *timeval to the current time of day. On error, log and terminate. - * (Same as gettimeofday(timeval,NULL), but never returns -1.) - */ -MOCK_IMPL(void, -tor_gettimeofday, (struct timeval *timeval)) -{ -#ifdef _WIN32 - /* Epoch bias copied from perl: number of units between windows epoch and - * Unix epoch. */ -#define EPOCH_BIAS U64_LITERAL(116444736000000000) -#define UNITS_PER_SEC U64_LITERAL(10000000) -#define USEC_PER_SEC U64_LITERAL(1000000) -#define UNITS_PER_USEC U64_LITERAL(10) - union { - uint64_t ft_64; - FILETIME ft_ft; - } ft; - /* number of 100-nsec units since Jan 1, 1601 */ - GetSystemTimeAsFileTime(&ft.ft_ft); - if (ft.ft_64 < EPOCH_BIAS) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"System time is before 1970; failing."); - exit(1); // exit ok: system clock is broken. - /* LCOV_EXCL_STOP */ - } - ft.ft_64 -= EPOCH_BIAS; - timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); - timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); -#elif defined(HAVE_GETTIMEOFDAY) - if (gettimeofday(timeval, NULL)) { - /* LCOV_EXCL_START */ - /* If gettimeofday dies, we have either given a bad timezone (we didn't), - or segfaulted.*/ - raw_assert_unreached_msg("gettimeofday failed"); - /* LCOV_EXCL_STOP */ - } -#elif defined(HAVE_FTIME) - struct timeb tb; - ftime(&tb); - timeval->tv_sec = tb.time; - timeval->tv_usec = tb.millitm * 1000; -#else -#error "No way to get time." -#endif /* defined(_WIN32) || ... */ - return; -} - #define ONE_MILLION ((int64_t) (1000 * 1000)) #define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) diff --git a/src/common/compat_time.h b/src/common/compat_time.h index 71d94cb86f..2f7e87a633 100644 --- a/src/common/compat_time.h +++ b/src/common/compat_time.h @@ -19,6 +19,8 @@ #define TOR_COMPAT_TIME_H #include "orconfig.h" +#include "lib/wallclock/tor_gettimeofday.h" + #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME #endif @@ -200,8 +202,6 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start, #endif } -MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); - #ifdef TOR_UNIT_TESTS void tor_sleep_msec(int msec); @@ -230,4 +230,3 @@ void monotime_reset_ratchets_for_testing(void); #endif /* defined(COMPAT_TIME_PRIVATE) */ #endif /* !defined(TOR_COMPAT_TIME_H) */ - diff --git a/src/common/log.c b/src/common/log.c index 5224a21970..f452c7413a 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -35,6 +35,8 @@ #include "common/torlog.h" #include "lib/container/smartlist.h" #include "lib/err/torerr.h" +#include "lib/wallclock/tor_gettimeofday.h" +#include "lib/wallclock/approx_time.h" #ifdef HAVE_ANDROID_LOG_H #include diff --git a/src/common/util.c b/src/common/util.c index 877368af59..358a68fd75 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1798,37 +1798,6 @@ format_time_interval(char *out, size_t out_len, long interval) } } -/* ===== - * Cached time - * ===== */ - -#ifndef TIME_IS_FAST -/** Cached estimate of the current time. Updated around once per second; - * may be a few seconds off if we are really busy. This is a hack to avoid - * calling time(NULL) (which not everybody has optimized) on critical paths. - */ -static time_t cached_approx_time = 0; - -/** Return a cached estimate of the current time from when - * update_approx_time() was last called. This is a hack to avoid calling - * time(NULL) on critical paths: please do not even think of calling it - * anywhere else. */ -time_t -approx_time(void) -{ - return cached_approx_time; -} - -/** Update the cached estimate of the current time. This function SHOULD be - * called once per second, and MUST be called before the first call to - * get_approx_time. */ -void -update_approx_time(time_t now) -{ - cached_approx_time = now; -} -#endif /* !defined(TIME_IS_FAST) */ - /* ===== * Rate limiting * ===== */ diff --git a/src/common/util.h b/src/common/util.h index 916bddc1fe..f2df84b194 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -24,6 +24,7 @@ #endif #include "lib/err/torerr.h" #include "lib/malloc/util_malloc.h" +#include "lib/wallclock/approx_time.h" #include "common/util_bug.h" #ifndef O_BINARY @@ -178,15 +179,6 @@ int parse_iso_time_nospace(const char *cp, time_t *t); int parse_http_time(const char *buf, struct tm *tm); int format_time_interval(char *out, size_t out_len, long interval); -/* Cached time */ -#ifdef TIME_IS_FAST -#define approx_time() time(NULL) -#define update_approx_time(t) STMT_NIL -#else -time_t approx_time(void); -void update_approx_time(time_t now); -#endif /* defined(TIME_IS_FAST) */ - /* Rate-limiter */ /** A ratelim_t remembers how often an event is occurring, and how often diff --git a/src/include.am b/src/include.am index 581fd69c79..a2c0cc88b8 100644 --- a/src/include.am +++ b/src/include.am @@ -11,6 +11,7 @@ include src/lib/malloc/include.am include src/lib/testsupport/include.am include src/lib/tls/include.am include src/lib/trace/include.am +include src/lib/wallclock/include.am include src/common/include.am include src/trunnel/include.am include src/or/include.am diff --git a/src/lib/wallclock/.may_include b/src/lib/wallclock/.may_include new file mode 100644 index 0000000000..686d9196fd --- /dev/null +++ b/src/lib/wallclock/.may_include @@ -0,0 +1,4 @@ +orconfig.h +lib/err/*.h +lib/wallclock/*.h +lib/testsupport/*.h diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c new file mode 100644 index 0000000000..2528954f13 --- /dev/null +++ b/src/lib/wallclock/approx_time.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/wallclock/approx_time.h" + +/* ===== + * Cached time + * ===== */ + +#ifndef TIME_IS_FAST +/** Cached estimate of the current time. Updated around once per second; + * may be a few seconds off if we are really busy. This is a hack to avoid + * calling time(NULL) (which not everybody has optimized) on critical paths. + */ +static time_t cached_approx_time = 0; + +/** Return a cached estimate of the current time from when + * update_approx_time() was last called. This is a hack to avoid calling + * time(NULL) on critical paths: please do not even think of calling it + * anywhere else. */ +time_t +approx_time(void) +{ + return cached_approx_time; +} + +/** Update the cached estimate of the current time. This function SHOULD be + * called once per second, and MUST be called before the first call to + * get_approx_time. */ +void +update_approx_time(time_t now) +{ + cached_approx_time = now; +} +#endif /* !defined(TIME_IS_FAST) */ diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h new file mode 100644 index 0000000000..c57ff5bcd3 --- /dev/null +++ b/src/lib/wallclock/approx_time.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_APPROX_TIME_H +#define TOR_APPROX_TIME_H + +#include + +/* Cached time */ +#ifdef TIME_IS_FAST +#define approx_time() time(NULL) +#define update_approx_time(t) STMT_NIL +#else +time_t approx_time(void); +void update_approx_time(time_t now); +#endif /* defined(TIME_IS_FAST) */ + +#endif diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am new file mode 100644 index 0000000000..d414eb4688 --- /dev/null +++ b/src/lib/wallclock/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-wallclock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-wallclock-testing.a +endif + +src_lib_libtor_wallclock_a_SOURCES = \ + src/lib/wallclock/approx_time.c \ + src/lib/wallclock/tor_gettimeofday.c + +src_lib_libtor_wallclock_testing_a_SOURCES = \ + $(src_lib_libtor_wallclock_a_SOURCES) +src_lib_libtor_wallclock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/wallclock/approx_time.h \ + src/lib/wallclock/tor_gettimeofday.h diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c new file mode 100644 index 0000000000..83081d9c98 --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.c @@ -0,0 +1,82 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.c + * \brief Portable wrappers for finding out the current time, running + * timers, etc. + **/ + +#include "orconfig.h" +#include "lib/err/torerr.h" +#include "lib/wallclock/tor_gettimeofday.h" + +#include +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef _WIN32 +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_FTIME +#include +#endif +#endif + +/** Set *timeval to the current time of day. On error, log and terminate. + * (Same as gettimeofday(timeval,NULL), but never returns -1.) + */ +MOCK_IMPL(void, +tor_gettimeofday, (struct timeval *timeval)) +{ +#ifdef _WIN32 + /* Epoch bias copied from perl: number of units between windows epoch and + * Unix epoch. */ +#define EPOCH_BIAS U64_LITERAL(116444736000000000) +#define UNITS_PER_SEC U64_LITERAL(10000000) +#define USEC_PER_SEC U64_LITERAL(1000000) +#define UNITS_PER_USEC U64_LITERAL(10) + union { + uint64_t ft_64; + FILETIME ft_ft; + } ft; + /* number of 100-nsec units since Jan 1, 1601 */ + GetSystemTimeAsFileTime(&ft.ft_ft); + if (ft.ft_64 < EPOCH_BIAS) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"System time is before 1970; failing."); + exit(1); // exit ok: system clock is broken. + /* LCOV_EXCL_STOP */ + } + ft.ft_64 -= EPOCH_BIAS; + timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); + timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(timeval, NULL)) { + /* LCOV_EXCL_START */ + /* If gettimeofday dies, we have either given a bad timezone (we didn't), + or segfaulted.*/ + raw_assert_unreached_msg("gettimeofday failed"); + /* LCOV_EXCL_STOP */ + } +#elif defined(HAVE_FTIME) + struct timeb tb; + ftime(&tb); + timeval->tv_sec = tb.time; + timeval->tv_usec = tb.millitm * 1000; +#else +#error "No way to get time." +#endif /* defined(_WIN32) || ... */ + return; +} diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h new file mode 100644 index 0000000000..728ad9565d --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETTIMEOFDAY_H +#define TOR_GETTIMEOFDAY_H + +#include "lib/testsupport/testsupport.h" + +struct timeval; + +MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); + +#endif