Tor  0.4.7.0-alpha-dev
periodic.c
Go to the documentation of this file.
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"
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  **/
44 
45 /** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
46  * now. */
47 static void
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
62 {
63  periodic_event_item_t *event = data;
64  tor_assert(ev == event->ev);
65 
66  time_t now = time(NULL);
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  */
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
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
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 
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
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
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
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
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
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
220 {
221  if (!the_periodic_events)
223 
224  if (BUG(smartlist_contains(the_periodic_events, item)))
225  return;
226 
228 }
229 
230 /**
231  * Make all registered periodic events connect to the libevent backend.
232  */
233 void
235 {
236  if (! the_periodic_events)
237  return;
238 
240  if (item->ev)
241  continue;
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
255 {
256  if (! the_periodic_events)
257  return;
258 
260  if (!item->ev)
261  continue;
262 
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  */
273 {
274  if (! the_periodic_events)
275  return NULL;
276 
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 
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) {
317  } else {
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
332 {
333  if (! the_periodic_events)
334  return;
335 
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 }
void mainloop_event_cancel(mainloop_event_t *event)
mainloop_event_t * mainloop_event_new(void(*cb)(mainloop_event_t *, void *), void *userdata)
int mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
void mainloop_event_activate(mainloop_event_t *event)
Header for compat_libevent.c.
const or_options_t * get_options(void)
Definition: config.c:919
const char * name
Definition: config.c:2434
Header file for config.c.
#define LD_BUG
Definition: log.h:86
#define LD_GENERAL
Definition: log.h:62
void update_current_time(time_t now)
Definition: mainloop.c:2197
Header file for mainloop.c.
Master header file for Tor-specific functionality.
void periodic_event_disable(periodic_event_item_t *event)
Definition: periodic.c:185
static const int MAX_INTERVAL
Definition: periodic.c:37
void periodic_events_rescan_by_roles(int roles, bool net_disabled)
Definition: periodic.c:291
static void periodic_event_dispatch(mainloop_event_t *ev, void *data)
Definition: periodic.c:61
static void periodic_event_set_interval(periodic_event_item_t *event, time_t next_interval)
Definition: periodic.c:48
void periodic_event_schedule_and_disable(periodic_event_item_t *event)
Definition: periodic.c:201
void periodic_event_enable(periodic_event_item_t *event)
Definition: periodic.c:168
static smartlist_t * the_periodic_events
Definition: periodic.c:43
void periodic_events_connect_all(void)
Definition: periodic.c:234
void periodic_events_register(periodic_event_item_t *item)
Definition: periodic.c:219
void periodic_event_launch(periodic_event_item_t *event)
Definition: periodic.c:132
void periodic_event_connect(periodic_event_item_t *event)
Definition: periodic.c:117
int safe_timer_diff(time_t now, time_t next)
Definition: periodic.c:351
void periodic_events_disconnect_all(void)
Definition: periodic.c:331
void periodic_event_reschedule(periodic_event_item_t *event)
Definition: periodic.c:106
void periodic_events_reset_all(void)
Definition: periodic.c:254
static void periodic_event_disconnect(periodic_event_item_t *event)
Definition: periodic.c:151
periodic_event_item_t * periodic_events_find(const char *name)
Definition: periodic.c:272
Header for periodic.c.
smartlist_t * smartlist_new(void)
int smartlist_contains(const smartlist_t *sl, const void *element)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
struct mainloop_event_t * ev
Definition: periodic.h:66
#define tor_assert(expr)
Definition: util_bug.h:102