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