Line data Source code
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 0 : periodic_event_set_interval(periodic_event_item_t *event,
49 : time_t next_interval)
50 : {
51 0 : tor_assert(next_interval < MAX_INTERVAL);
52 0 : struct timeval tv;
53 0 : tv.tv_sec = next_interval;
54 0 : tv.tv_usec = 0;
55 0 : mainloop_event_schedule(event->ev, &tv);
56 0 : }
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 0 : periodic_event_dispatch(mainloop_event_t *ev, void *data)
62 : {
63 0 : periodic_event_item_t *event = data;
64 0 : tor_assert(ev == event->ev);
65 :
66 0 : time_t now = time(NULL);
67 0 : update_current_time(now);
68 0 : const or_options_t *options = get_options();
69 : // log_debug(LD_GENERAL, "Dispatching %s", event->name);
70 0 : int r = event->fn(now, options);
71 0 : int next_interval = 0;
72 :
73 0 : if (!periodic_event_is_enabled(event)) {
74 : /* The event got disabled from inside its callback, or before: no need to
75 : * reschedule. */
76 0 : return;
77 : }
78 :
79 : /* update the last run time if action was taken */
80 0 : if (r==0) {
81 0 : log_err(LD_BUG, "Invalid return value for periodic event from %s.",
82 : event->name);
83 0 : tor_assert(r != 0);
84 0 : } else if (r > 0) {
85 0 : 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 0 : 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 0 : struct timeval tv = { next_interval , 0 };
101 0 : mainloop_event_schedule(ev, &tv);
102 : }
103 :
104 : /** Schedules <b>event</b> to run as soon as possible from now. */
105 : void
106 129 : periodic_event_reschedule(periodic_event_item_t *event)
107 : {
108 : /* Don't reschedule a disabled or uninitialized event. */
109 129 : if (event->ev && periodic_event_is_enabled(event)) {
110 0 : periodic_event_set_interval(event, 1);
111 : }
112 129 : }
113 :
114 : /** Connects a periodic event to the Libevent backend. Does not launch the
115 : * event immediately. */
116 : void
117 105 : periodic_event_connect(periodic_event_item_t *event)
118 : {
119 105 : if (event->ev) { /* Already setup? This is a bug */
120 0 : log_err(LD_BUG, "Initial dispatch should only be done once.");
121 0 : tor_assert(0);
122 : }
123 :
124 105 : event->ev = mainloop_event_new(periodic_event_dispatch,
125 : event);
126 105 : tor_assert(event->ev);
127 105 : }
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 0 : periodic_event_launch(periodic_event_item_t *event)
133 : {
134 0 : if (! event->ev) { /* Not setup? This is a bug */
135 0 : log_err(LD_BUG, "periodic_event_launch without periodic_event_connect");
136 0 : tor_assert(0);
137 : }
138 : /* Event already enabled? This is a bug */
139 0 : if (periodic_event_is_enabled(event)) {
140 0 : log_err(LD_BUG, "periodic_event_launch on an already enabled event");
141 0 : tor_assert(0);
142 : }
143 :
144 : // Initial dispatch
145 0 : event->enabled = 1;
146 0 : periodic_event_dispatch(event->ev, event);
147 0 : }
148 :
149 : /** Disconnect and unregister the periodic event in <b>event</b> */
150 : static void
151 8295 : periodic_event_disconnect(periodic_event_item_t *event)
152 : {
153 8295 : if (!event)
154 : return;
155 :
156 : /* First disable the event so we first cancel the event and set its enabled
157 : * flag properly. */
158 8295 : periodic_event_disable(event);
159 :
160 8295 : mainloop_event_free(event->ev);
161 8295 : 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 167 : periodic_event_enable(periodic_event_item_t *event)
169 : {
170 167 : tor_assert(event);
171 : /* Safely and silently ignore if this event is already enabled. */
172 167 : if (periodic_event_is_enabled(event)) {
173 : return;
174 : }
175 :
176 76 : tor_assert(event->ev);
177 76 : event->enabled = 1;
178 76 : 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 8437 : periodic_event_disable(periodic_event_item_t *event)
186 : {
187 8437 : tor_assert(event);
188 : /* Safely and silently ignore if this event is already disabled. */
189 8437 : if (!periodic_event_is_enabled(event)) {
190 : return;
191 : }
192 40 : mainloop_event_cancel(event->ev);
193 40 : 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 18 : periodic_event_schedule_and_disable(periodic_event_item_t *event)
202 : {
203 18 : tor_assert(event);
204 18 : if (!periodic_event_is_enabled(event))
205 : return;
206 :
207 12 : periodic_event_disable(event);
208 :
209 12 : 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 8540 : periodic_events_register(periodic_event_item_t *item)
220 : {
221 8540 : if (!the_periodic_events)
222 244 : the_periodic_events = smartlist_new();
223 :
224 8540 : if (BUG(smartlist_contains(the_periodic_events, item)))
225 0 : return;
226 :
227 8540 : smartlist_add(the_periodic_events, item);
228 : }
229 :
230 : /**
231 : * Make all registered periodic events connect to the libevent backend.
232 : */
233 : void
234 3 : periodic_events_connect_all(void)
235 : {
236 3 : if (! the_periodic_events)
237 : return;
238 :
239 108 : SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
240 105 : if (item->ev)
241 0 : continue;
242 105 : periodic_event_connect(item);
243 105 : } 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 1 : periodic_events_reset_all(void)
255 : {
256 1 : if (! the_periodic_events)
257 : return;
258 :
259 36 : SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
260 35 : if (!item->ev)
261 35 : continue;
262 :
263 0 : periodic_event_reschedule(item);
264 35 : } 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 1220 : periodic_events_find(const char *name)
273 : {
274 1220 : if (! the_periodic_events)
275 : return NULL;
276 :
277 14884 : SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
278 14640 : if (strcmp(name, item->name) == 0)
279 976 : return item;
280 13664 : } 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 297 : periodic_events_rescan_by_roles(int roles, bool net_disabled)
292 : {
293 297 : if (! the_periodic_events)
294 : return;
295 :
296 10692 : SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
297 10395 : if (!item->ev)
298 10080 : continue;
299 :
300 315 : int enable = !!(item->roles & roles);
301 :
302 : /* Handle the event flags. */
303 315 : if (net_disabled &&
304 70 : (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 293 : if (enable) {
311 167 : log_debug(LD_GENERAL, "Launching periodic event %s", item->name);
312 167 : periodic_event_enable(item);
313 : } else {
314 148 : log_debug(LD_GENERAL, "Disabling periodic event %s", item->name);
315 148 : if (item->flags & PERIODIC_EVENT_FLAG_RUN_ON_DISABLE) {
316 18 : periodic_event_schedule_and_disable(item);
317 : } else {
318 130 : periodic_event_disable(item);
319 : }
320 : }
321 10395 : } 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 237 : periodic_events_disconnect_all(void)
332 : {
333 237 : if (! the_periodic_events)
334 : return;
335 :
336 8532 : SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) {
337 8295 : periodic_event_disconnect(item);
338 8295 : } SMARTLIST_FOREACH_END(item);
339 :
340 237 : 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 0 : safe_timer_diff(time_t now, time_t next)
352 : {
353 0 : 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 0 : tor_assert(next > TIME_MIN + LONGEST_TIMER_PERIOD);
361 :
362 0 : if (next - LONGEST_TIMER_PERIOD > now)
363 : return LONGEST_TIMER_PERIOD;
364 0 : return (int)(next - now);
365 : } else {
366 : return 1;
367 : }
368 : }
|