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
check_continuity(time_t * delta)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 */
setup_event_timer_continuity(struct state * state)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