1 /* 2 * check_continuity.c - periodically check local clock deltas 3 * Copyright (c) 2013 The Chromium Authors. All rights reserved. 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "config.h" 9 10 #include <time.h> 11 #include <event2/event.h> 12 13 #include "src/conf.h" 14 #include "src/tlsdate.h" 15 #include "src/util.h" 16 17 18 /* Returns < 0 on error, 19 * 0 on sync'd, 20 * and > 0 on desync'd. 21 * Old delta is in |delta|. |delta| is overwritten 22 * if >= 0 is returned. 23 * 24 * This event catches any sort of real-time clock jump. A jump is observed 25 * when settimeofday() or adjtimex() is called, or if the RTC misbehaves on 26 * return from suspend. If a jump is detected between a cycle-oriented clock 27 * (MONOTONIC_RAW) and a potentially RTC managed clock (REALTIME), then a 28 * network resynchronization will be required. To avoid requiring this on 29 * every resume-from-suspend, a larger delta represents the largest time jump 30 * allowed before needing a resync. 31 * 32 * Note, CLOCK_BOOTTIME does not resolve this on platforms without a persistent 33 * clock because the RTC still determines the time considered "suspend time". 34 */ 35 int 36 check_continuity (time_t *delta) 37 { 38 time_t new_delta; 39 struct timespec monotonic, real; 40 if (clock_gettime (CLOCK_REALTIME, &real) < 0) 41 return -1; 42 if (clock_gettime (CLOCK_MONOTONIC_RAW, &monotonic) < 0) 43 return -1; 44 new_delta = real.tv_sec - monotonic.tv_sec; 45 if (*delta) 46 { 47 /* The allowed delta matches the interval for now. */ 48 static const time_t kDelta = CONTINUITY_INTERVAL; 49 if (new_delta < *delta - kDelta || new_delta > *delta + kDelta) 50 { 51 *delta = new_delta; 52 return 1; 53 } 54 } 55 /* First delta after de-sync. */ 56 *delta = new_delta; 57 return 0; 58 } 59 60 /* Sets up a wake event just in case there has not been a wake event 61 * recently enough to catch clock desynchronization. This does not 62 * invalidate the time like the action_invalidate_time event. 63 */ 64 int setup_event_timer_continuity (struct state *state) 65 { 66 struct event *event; 67 struct timeval interval = { state->opts.continuity_interval, 0 }; 68 event = event_new (state->base, -1, EV_TIMEOUT|EV_PERSIST, 69 action_kickoff_time_sync, state); 70 if (!event) 71 { 72 error ("Failed to create interval event"); 73 return 1; 74 } 75 event_priority_set (event, PRI_WAKE); 76 return event_add (event, &interval); 77 } 78