tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

periodic.c (10671B)


      1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file periodic.c
      6 *
      7 * \brief Generic backend for handling periodic events.
      8 *
      9 * The events in this module are used to track items that need
     10 * to fire once every N seconds, possibly picking a new interval each time
     11 * that they fire.  See periodic_events[] in mainloop.c for examples.
     12 *
     13 * This module manages a global list of periodic_event_item_t objects,
     14 * each corresponding to a single event.  To register an event, pass it to
     15 * periodic_events_register() when initializing your subsystem.
     16 *
     17 * Registering an event makes the periodic event subsystem know about it, but
     18 * doesn't cause the event to get created immediately.  Before the event can
     19 * be started, periodic_event_connect_all() must be called by mainloop.c to
     20 * connect all the events to Libevent.
     21 *
     22 * We expect that periodic_event_item_t objects will be statically allocated;
     23 * we set them up and tear them down here, but we don't take ownership of
     24 * them.
     25 */
     26 
     27 #include "core/or/or.h"
     28 #include "lib/evloop/compat_libevent.h"
     29 #include "app/config/config.h"
     30 #include "core/mainloop/mainloop.h"
     31 #include "core/mainloop/periodic.h"
     32 
     33 /** We disable any interval greater than this number of seconds, on the
     34 * grounds that it is probably an absolute time mistakenly passed in as a
     35 * relative time.
     36 */
     37 static const int MAX_INTERVAL = 10 * 365 * 86400;
     38 
     39 /**
     40 * Global list of periodic events that have been registered with
     41 * <b>periodic_event_register</b>.
     42 **/
     43 static smartlist_t *the_periodic_events = NULL;
     44 
     45 /** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
     46 * now. */
     47 static void
     48 periodic_event_set_interval(periodic_event_item_t *event,
     49                            time_t next_interval)
     50 {
     51  tor_assert(next_interval < MAX_INTERVAL);
     52  struct timeval tv;
     53  tv.tv_sec = next_interval;
     54  tv.tv_usec = 0;
     55  mainloop_event_schedule(event->ev, &tv);
     56 }
     57 
     58 /** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
     59 * event that needs to be called */
     60 static void
     61 periodic_event_dispatch(mainloop_event_t *ev, void *data)
     62 {
     63  periodic_event_item_t *event = data;
     64  tor_assert(ev == event->ev);
     65 
     66  time_t now = time(NULL);
     67  update_current_time(now);
     68  const or_options_t *options = get_options();
     69 //  log_debug(LD_GENERAL, "Dispatching %s", event->name);
     70  int r = event->fn(now, options);
     71  int next_interval = 0;
     72 
     73  if (!periodic_event_is_enabled(event)) {
     74    /* The event got disabled from inside its callback, or before: no need to
     75     * reschedule. */
     76    return;
     77  }
     78 
     79  /* update the last run time if action was taken */
     80  if (r==0) {
     81    log_err(LD_BUG, "Invalid return value for periodic event from %s.",
     82                      event->name);
     83    tor_assert(r != 0);
     84  } else if (r > 0) {
     85    event->last_action_time = now;
     86    /* If the event is meant to happen after ten years, that's likely
     87     * a bug, and somebody gave an absolute time rather than an interval.
     88     */
     89    tor_assert(r < MAX_INTERVAL);
     90    next_interval = r;
     91  } else {
     92    /* no action was taken, it is likely a precondition failed,
     93     * we should reschedule for next second in case the precondition
     94     * passes then */
     95    next_interval = 1;
     96  }
     97 
     98 //  log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
     99 //           next_interval);
    100  struct timeval tv = { next_interval , 0 };
    101  mainloop_event_schedule(ev, &tv);
    102 }
    103 
    104 /** Schedules <b>event</b> to run as soon as possible from now. */
    105 void
    106 periodic_event_reschedule(periodic_event_item_t *event)
    107 {
    108  /* Don't reschedule a disabled or uninitialized event. */
    109  if (event->ev && periodic_event_is_enabled(event)) {
    110    periodic_event_set_interval(event, 1);
    111  }
    112 }
    113 
    114 /** Connects a periodic event to the Libevent backend.  Does not launch the
    115 * event immediately. */
    116 void
    117 periodic_event_connect(periodic_event_item_t *event)
    118 {
    119  if (event->ev) { /* Already setup? This is a bug */
    120    log_err(LD_BUG, "Initial dispatch should only be done once.");
    121    tor_assert(0);
    122  }
    123 
    124  event->ev = mainloop_event_new(periodic_event_dispatch,
    125                                 event);
    126  tor_assert(event->ev);
    127 }
    128 
    129 /** Handles initial dispatch for periodic events. It should happen 1 second
    130 * after the events are created to mimic behaviour before #3199's refactor */
    131 void
    132 periodic_event_launch(periodic_event_item_t *event)
    133 {
    134  if (! event->ev) { /* Not setup? This is a bug */
    135    log_err(LD_BUG, "periodic_event_launch without periodic_event_connect");
    136    tor_assert(0);
    137  }
    138  /* Event already enabled? This is a bug */
    139  if (periodic_event_is_enabled(event)) {
    140    log_err(LD_BUG, "periodic_event_launch on an already enabled event");
    141    tor_assert(0);
    142  }
    143 
    144  // Initial dispatch
    145  event->enabled = 1;
    146  periodic_event_dispatch(event->ev, event);
    147 }
    148 
    149 /** Disconnect and unregister the periodic event in <b>event</b> */
    150 static void
    151 periodic_event_disconnect(periodic_event_item_t *event)
    152 {
    153  if (!event)
    154    return;
    155 
    156  /* First disable the event so we first cancel the event and set its enabled
    157   * flag properly. */
    158  periodic_event_disable(event);
    159 
    160  mainloop_event_free(event->ev);
    161  event->last_action_time = 0;
    162 }
    163 
    164 /** Enable the given event by setting its "enabled" flag and scheduling it to
    165 * run immediately in the event loop. This can be called for an event that is
    166 * already enabled. */
    167 void
    168 periodic_event_enable(periodic_event_item_t *event)
    169 {
    170  tor_assert(event);
    171  /* Safely and silently ignore if this event is already enabled. */
    172  if (periodic_event_is_enabled(event)) {
    173    return;
    174  }
    175 
    176  tor_assert(event->ev);
    177  event->enabled = 1;
    178  mainloop_event_activate(event->ev);
    179 }
    180 
    181 /** Disable the given event which means the event is destroyed and then the
    182 * event's enabled flag is unset. This can be called for an event that is
    183 * already disabled. */
    184 void
    185 periodic_event_disable(periodic_event_item_t *event)
    186 {
    187  tor_assert(event);
    188  /* Safely and silently ignore if this event is already disabled. */
    189  if (!periodic_event_is_enabled(event)) {
    190    return;
    191  }
    192  mainloop_event_cancel(event->ev);
    193  event->enabled = 0;
    194 }
    195 
    196 /**
    197 * Disable an event, then schedule it to run once.
    198 * Do nothing if the event was already disabled.
    199 */
    200 void
    201 periodic_event_schedule_and_disable(periodic_event_item_t *event)
    202 {
    203  tor_assert(event);
    204  if (!periodic_event_is_enabled(event))
    205    return;
    206 
    207  periodic_event_disable(event);
    208 
    209  mainloop_event_activate(event->ev);
    210 }
    211 
    212 /**
    213 * Add <b>item</b> to the list of periodic events.
    214 *
    215 * Note that <b>item</b> should be statically allocated: we do not
    216 * take ownership of it.
    217 **/
    218 void
    219 periodic_events_register(periodic_event_item_t *item)
    220 {
    221  if (!the_periodic_events)
    222    the_periodic_events = smartlist_new();
    223 
    224  if (BUG(smartlist_contains(the_periodic_events, item)))
    225    return;
    226 
    227  smartlist_add(the_periodic_events, item);
    228 }
    229 
    230 /**
    231 * Make all registered periodic events connect to the libevent backend.
    232 */
    233 void
    234 periodic_events_connect_all(void)
    235 {
    236  if (! the_periodic_events)
    237    return;
    238 
    239  SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
    240    if (item->ev)
    241      continue;
    242    periodic_event_connect(item);
    243  } SMARTLIST_FOREACH_END(item);
    244 }
    245 
    246 /**
    247 * Reset all the registered periodic events so we'll do all our actions again
    248 * as if we just started up.
    249 *
    250 * Useful if our clock just moved back a long time from the future,
    251 * so we don't wait until that future arrives again before acting.
    252 */
    253 void
    254 periodic_events_reset_all(void)
    255 {
    256  if (! the_periodic_events)
    257    return;
    258 
    259  SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
    260    if (!item->ev)
    261      continue;
    262 
    263    periodic_event_reschedule(item);
    264  } SMARTLIST_FOREACH_END(item);
    265 }
    266 
    267 /**
    268 * Return the registered periodic event whose name is <b>name</b>.
    269 * Return NULL if no such event is found.
    270 */
    271 periodic_event_item_t *
    272 periodic_events_find(const char *name)
    273 {
    274  if (! the_periodic_events)
    275    return NULL;
    276 
    277  SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
    278    if (strcmp(name, item->name) == 0)
    279      return item;
    280  } SMARTLIST_FOREACH_END(item);
    281  return NULL;
    282 }
    283 
    284 /**
    285 * Start or stop registered periodic events, depending on our current set of
    286 * roles.
    287 *
    288 * Invoked when our list of roles, or the net_disabled flag has changed.
    289 **/
    290 void
    291 periodic_events_rescan_by_roles(int roles, bool net_disabled)
    292 {
    293  if (! the_periodic_events)
    294    return;
    295 
    296  SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
    297    if (!item->ev)
    298      continue;
    299 
    300    int enable = !!(item->roles & roles);
    301 
    302    /* Handle the event flags. */
    303    if (net_disabled &&
    304        (item->flags & PERIODIC_EVENT_FLAG_NEED_NET)) {
    305      enable = 0;
    306    }
    307 
    308    /* Enable the event if needed. It is safe to enable an event that was
    309     * already enabled. Same goes for disabling it. */
    310    if (enable) {
    311      log_debug(LD_GENERAL, "Launching periodic event %s", item->name);
    312      periodic_event_enable(item);
    313    } else {
    314      log_debug(LD_GENERAL, "Disabling periodic event %s", item->name);
    315      if (item->flags & PERIODIC_EVENT_FLAG_RUN_ON_DISABLE) {
    316        periodic_event_schedule_and_disable(item);
    317      } else {
    318        periodic_event_disable(item);
    319      }
    320    }
    321  } SMARTLIST_FOREACH_END(item);
    322 }
    323 
    324 /**
    325 * Invoked at shutdown: disconnect and unregister all periodic events.
    326 *
    327 * Does not free the periodic_event_item_t object themselves, because we do
    328 * not own them.
    329 */
    330 void
    331 periodic_events_disconnect_all(void)
    332 {
    333  if (! the_periodic_events)
    334    return;
    335 
    336  SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
    337    periodic_event_disconnect(item);
    338  } SMARTLIST_FOREACH_END(item);
    339 
    340  smartlist_free(the_periodic_events);
    341 }
    342 
    343 #define LONGEST_TIMER_PERIOD (30 * 86400)
    344 /** Helper: Return the number of seconds between <b>now</b> and <b>next</b>,
    345 * clipped to the range [1 second, LONGEST_TIMER_PERIOD].
    346 *
    347 * We use this to answer the question, "how many seconds is it from now until
    348 * next" in periodic timer callbacks.  Don't use it for other purposes
    349 **/
    350 int
    351 safe_timer_diff(time_t now, time_t next)
    352 {
    353  if (next > now) {
    354    /* There were no computers at signed TIME_MIN (1902 on 32-bit systems),
    355     * and nothing that could run Tor. It's a bug if 'next' is around then.
    356     * On 64-bit systems with signed TIME_MIN, TIME_MIN is before the Big
    357     * Bang. We cannot extrapolate past a singularity, but there was probably
    358     * nothing that could run Tor then, either.
    359     **/
    360    tor_assert(next > TIME_MIN + LONGEST_TIMER_PERIOD);
    361 
    362    if (next - LONGEST_TIMER_PERIOD > now)
    363      return LONGEST_TIMER_PERIOD;
    364    return (int)(next - now);
    365  } else {
    366    return 1;
    367  }
    368 }