From fd91ae3325adfdc83f95a284caa746c000ad7e30 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 5 Nov 2008 22:36:49 +0100 Subject: [PATCH] Fix problem with local time changes. --- configure.in | 2 + nest/password.c | 2 +- proto/ospf/packet.c | 2 +- proto/rip/auth.c | 2 +- sysdep/unix/io.c | 90 +++++++++++++++++++++++++++++++++++++-------- sysdep/unix/timer.h | 3 +- 6 files changed, 81 insertions(+), 20 deletions(-) diff --git a/configure.in b/configure.in index 44d55c90..43827325 100644 --- a/configure.in +++ b/configure.in @@ -49,6 +49,8 @@ else fi fi +LIBS=" -lrt" + AC_CANONICAL_HOST AC_PROG_CC diff --git a/nest/password.c b/nest/password.c index 7f1c8dce..80c4c7b4 100644 --- a/nest/password.c +++ b/nest/password.c @@ -22,7 +22,7 @@ password_find(list *l) { WALK_LIST(pi, *l) { - if ((pi->genfrom < now) && (pi->gento > now)) + if ((pi->genfrom < now_real) && (pi->gento > now_real)) return pi; } } diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index ead4b86f..4e8dcaf0 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -165,7 +165,7 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ WALK_LIST(ptmp, *(ifa->passwords)) { if (pkt->u.md5.keyid != ptmp->id) continue; - if ((ptmp->accfrom > now) || (ptmp->accto < now)) continue; + if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue; pass = ptmp; break; } diff --git a/proto/rip/auth.c b/proto/rip/auth.c index 8669e166..1f7050f0 100644 --- a/proto/rip/auth.c +++ b/proto/rip/auth.c @@ -77,7 +77,7 @@ rip_incoming_authentication( struct proto *p, struct rip_block_auth *block, stru WALK_LIST(ptmp, *l) { if (block->keyid != ptmp->id) continue; - if ((ptmp->genfrom > now) || (ptmp->gento < now)) continue; + if ((ptmp->genfrom > now_real) || (ptmp->gento < now_real)) continue; pass = ptmp; break; } diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index ddb3c4d9..5aed1b22 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -83,10 +83,11 @@ tracked_fopen(pool *p, char *name, char *mode) * doesn't guarantee exact timing, only that a timer function * won't be called before the requested time. * - * In BIRD, real time is represented by values of the &bird_clock_t type - * which are integral numbers interpreted as a number of seconds since - * a fixed (but platform dependent) epoch. The current time can be read - * from a variable @now with reasonable accuracy. + * In BIRD, time is represented by values of the &bird_clock_t type + * which are integral numbers interpreted as a relative number of seconds since + * some fixed time point in past. The current time can be read + * from variable @now with reasonable accuracy and is monotonic. There is also + * a current 'absolute' time in variable @now_real reported by OS. * * Each timer is described by a &timer structure containing a pointer * to the handler function (@hook), data private to this function (@data), @@ -99,7 +100,61 @@ tracked_fopen(pool *p, char *name, char *mode) static list near_timers, far_timers; static bird_clock_t first_far_timer = TIME_INFINITY; -bird_clock_t now; +bird_clock_t now, now_real; + +static void +update_times_plain(void) +{ + bird_clock_t new_time = time(NULL); + int delta = new_time - now_real; + + if ((delta >= 0) && (delta < 60)) + now += delta; + else if (now_real != 0) + log(L_WARN "Time jump, delta %d s", delta); + + now_real = new_time; +} + +static void +update_times_gettime(void) +{ + struct timespec ts; + int rv; + + rv = clock_gettime(CLOCK_MONOTONIC, &ts); + if (rv != 0) + die("clock_gettime: %m"); + + if (ts.tv_sec != now) { + if (ts.tv_sec < now) + log(L_ERR "Monotonic timer is broken"); + + now = ts.tv_sec; + now_real = time(NULL); + } +} + +static int clock_monotonic_available; + +static inline void +update_times(void) +{ + if (clock_monotonic_available) + update_times_gettime(); + else + update_times_plain(); +} + +static inline void +init_times(void) +{ + struct timespec ts; + clock_monotonic_available = (clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + if (!clock_monotonic_available) + log(L_WARN "Monotonic timer is missing"); +} + static void tm_free(resource *r) @@ -353,8 +408,8 @@ tm_parse_date(char *x) * @x: destination buffer of size %TM_DATE_BUFFER_SIZE * @t: time * - * This function formats the given time value @t to a textual - * date representation (dd-mm-yyyy). + * This function formats the given relative time value @t to a textual + * date representation (dd-mm-yyyy) in real time.. */ void tm_format_date(char *x, bird_clock_t t) @@ -370,14 +425,15 @@ tm_format_date(char *x, bird_clock_t t) * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE * @t: time * - * This function formats the given time value @t to a textual - * date/time representation (dd-mm-yyyy hh:mm:ss). + * This function formats the given relative time value @t to a textual + * date/time representation (dd-mm-yyyy hh:mm:ss) in real time. */ void tm_format_datetime(char *x, bird_clock_t t) { struct tm *tm; - + bird_clock_t delta = now - t; + t = now_real - delta; tm = localtime(&t); if (strftime(x, TM_DATETIME_BUFFER_SIZE, "%d-%m-%Y %H:%M:%S", tm) == TM_DATETIME_BUFFER_SIZE) strcpy(x, ""); @@ -388,16 +444,17 @@ tm_format_datetime(char *x, bird_clock_t t) * @x: destination buffer of size %TM_RELTIME_BUFFER_SIZE * @t: time * - * This function formats the given time value @t to a short - * textual representation relative to the current time. + * This function formats the given relative time value @t to a short + * textual representation in real time, relative to the current time. */ void tm_format_reltime(char *x, bird_clock_t t) { struct tm *tm; - bird_clock_t delta = (t < now) ? (now - t) : (t - now); static char *month_names[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + bird_clock_t delta = now - t; + t = now_real - delta; tm = localtime(&t); if (delta < 20*3600) bsprintf(x, "%02d:%02d", tm->tm_hour, tm->tm_min); @@ -1217,8 +1274,9 @@ io_init(void) init_list(&sock_list); init_list(&global_event_list); krt_io_init(); - now = time(NULL); - srandom((int) now); + init_times(); + update_times(); + srandom((int) now_real); } void @@ -1235,7 +1293,7 @@ io_loop(void) for(;;) { events = ev_run_list(&global_event_list); - now = time(NULL); + update_times(); tout = tm_first_shot(); if (tout <= now) { diff --git a/sysdep/unix/timer.h b/sysdep/unix/timer.h index 608dabb8..761cb42b 100644 --- a/sysdep/unix/timer.h +++ b/sysdep/unix/timer.h @@ -30,7 +30,8 @@ void tm_start(timer *, unsigned after); void tm_stop(timer *); void tm_dump_all(void); -extern bird_clock_t now; /* Time in seconds since unknown epoch */ +extern bird_clock_t now; /* Relative, monotonic time in seconds */ +extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */ bird_clock_t tm_parse_date(char *); /* Convert date to bird_clock_t */ bird_clock_t tm_parse_datetime(char *); /* Convert date to bird_clock_t */