Extract our code for answering "what time is it right now".

The other time stuff is higher-level
This commit is contained in:
Nick Mathewson 2018-06-21 17:33:49 -04:00
parent d1cada5a8a
commit 9426751b72
14 changed files with 188 additions and 96 deletions

2
.gitignore vendored
View File

@ -178,6 +178,8 @@ uptime-*.json
/src/lib/libtor-tls.a /src/lib/libtor-tls.a
/src/lib/libtor-tls-testing.a /src/lib/libtor-tls-testing.a
/src/lib/libtor-trace.a /src/lib/libtor-trace.a
/src/lib/libtor-wallclock.a
/src/lib/libtor-wallclock-testing.a
# /src/or/ # /src/or/
/src/or/Makefile /src/or/Makefile

View File

@ -42,6 +42,7 @@ TOR_UTIL_LIBS = \
src/common/libor.a \ src/common/libor.a \
src/lib/libtor-container.a \ src/lib/libtor-container.a \
src/lib/libtor-malloc.a \ src/lib/libtor-malloc.a \
src/lib/libtor-wallclock.a \
src/lib/libtor-err.a \ src/lib/libtor-err.a \
src/lib/libtor-ctime.a src/lib/libtor-ctime.a
@ -51,6 +52,7 @@ TOR_UTIL_TESTING_LIBS = \
src/common/libor-testing.a \ src/common/libor-testing.a \
src/lib/libtor-container-testing.a \ src/lib/libtor-container-testing.a \
src/lib/libtor-malloc-testing.a \ src/lib/libtor-malloc-testing.a \
src/lib/libtor-wallclock-testing.a \
src/lib/libtor-err-testing.a \ src/lib/libtor-err-testing.a \
src/lib/libtor-ctime-testing.a src/lib/libtor-ctime-testing.a

View File

@ -38,12 +38,6 @@
#include "common/torlog.h" #include "common/torlog.h"
#include "common/util.h" #include "common/util.h"
#ifndef HAVE_GETTIMEOFDAY
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#endif
#endif
#ifdef _WIN32 #ifdef _WIN32
#undef HAVE_CLOCK_GETTIME #undef HAVE_CLOCK_GETTIME
#endif #endif
@ -68,53 +62,6 @@ tor_sleep_msec(int msec)
} }
#endif /* defined(TOR_UNIT_TESTS) */ #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_MILLION ((int64_t) (1000 * 1000))
#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) #define ONE_BILLION ((int64_t) (1000 * 1000 * 1000))

View File

@ -19,6 +19,8 @@
#define TOR_COMPAT_TIME_H #define TOR_COMPAT_TIME_H
#include "orconfig.h" #include "orconfig.h"
#include "lib/wallclock/tor_gettimeofday.h"
#ifdef _WIN32 #ifdef _WIN32
#undef HAVE_CLOCK_GETTIME #undef HAVE_CLOCK_GETTIME
#endif #endif
@ -200,8 +202,6 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start,
#endif #endif
} }
MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval));
#ifdef TOR_UNIT_TESTS #ifdef TOR_UNIT_TESTS
void tor_sleep_msec(int msec); void tor_sleep_msec(int msec);
@ -230,4 +230,3 @@ void monotime_reset_ratchets_for_testing(void);
#endif /* defined(COMPAT_TIME_PRIVATE) */ #endif /* defined(COMPAT_TIME_PRIVATE) */
#endif /* !defined(TOR_COMPAT_TIME_H) */ #endif /* !defined(TOR_COMPAT_TIME_H) */

View File

@ -35,6 +35,8 @@
#include "common/torlog.h" #include "common/torlog.h"
#include "lib/container/smartlist.h" #include "lib/container/smartlist.h"
#include "lib/err/torerr.h" #include "lib/err/torerr.h"
#include "lib/wallclock/tor_gettimeofday.h"
#include "lib/wallclock/approx_time.h"
#ifdef HAVE_ANDROID_LOG_H #ifdef HAVE_ANDROID_LOG_H
#include <android/log.h> #include <android/log.h>

View File

@ -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 * Rate limiting
* ===== */ * ===== */

View File

@ -24,6 +24,7 @@
#endif #endif
#include "lib/err/torerr.h" #include "lib/err/torerr.h"
#include "lib/malloc/util_malloc.h" #include "lib/malloc/util_malloc.h"
#include "lib/wallclock/approx_time.h"
#include "common/util_bug.h" #include "common/util_bug.h"
#ifndef O_BINARY #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 parse_http_time(const char *buf, struct tm *tm);
int format_time_interval(char *out, size_t out_len, long interval); 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 */ /* Rate-limiter */
/** A ratelim_t remembers how often an event is occurring, and how often /** A ratelim_t remembers how often an event is occurring, and how often

View File

@ -11,6 +11,7 @@ include src/lib/malloc/include.am
include src/lib/testsupport/include.am include src/lib/testsupport/include.am
include src/lib/tls/include.am include src/lib/tls/include.am
include src/lib/trace/include.am include src/lib/trace/include.am
include src/lib/wallclock/include.am
include src/common/include.am include src/common/include.am
include src/trunnel/include.am include src/trunnel/include.am
include src/or/include.am include src/or/include.am

View File

@ -0,0 +1,4 @@
orconfig.h
lib/err/*.h
lib/wallclock/*.h
lib/testsupport/*.h

View File

@ -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) */

View File

@ -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 <time.h>
/* 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

View File

@ -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

View File

@ -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 <stddef.h>
#include <stdlib.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifndef HAVE_GETTIMEOFDAY
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#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;
}

View File

@ -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