Home | History | Annotate | Download | only in events
      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