2016-02-27 18:48:19 +01:00
|
|
|
/* Copyright (c) 2015-2016, The Tor Project, Inc. */
|
2015-11-02 15:48:18 +01:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
2016-02-27 18:08:24 +01:00
|
|
|
/**
|
|
|
|
* \file periodic.c
|
|
|
|
*
|
|
|
|
* \brief Generic backend for handling periodic events.
|
|
|
|
*/
|
|
|
|
|
2015-11-02 15:48:18 +01:00
|
|
|
#include "or.h"
|
2015-11-02 21:36:09 +01:00
|
|
|
#include "compat_libevent.h"
|
2015-11-02 15:48:18 +01:00
|
|
|
#include "config.h"
|
|
|
|
#include "periodic.h"
|
|
|
|
|
2015-11-02 21:36:09 +01:00
|
|
|
#ifdef HAVE_EVENT2_EVENT_H
|
|
|
|
#include <event2/event.h>
|
|
|
|
#else
|
|
|
|
#include <event.h>
|
|
|
|
#endif
|
|
|
|
|
2015-11-17 14:26:04 +01:00
|
|
|
/** We disable any interval greater than this number of seconds, on the
|
|
|
|
* grounds that it is probably an absolute time mistakenly passed in as a
|
|
|
|
* relative time.
|
2015-11-16 16:40:23 +01:00
|
|
|
*/
|
2015-11-02 15:48:18 +01:00
|
|
|
static const int MAX_INTERVAL = 10 * 365 * 86400;
|
|
|
|
|
2015-11-16 16:40:23 +01:00
|
|
|
/** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
|
|
|
|
* now. */
|
2015-11-02 15:48:18 +01:00
|
|
|
static void
|
|
|
|
periodic_event_set_interval(periodic_event_item_t *event,
|
|
|
|
time_t next_interval)
|
|
|
|
{
|
2015-11-02 21:36:09 +01:00
|
|
|
tor_assert(next_interval < MAX_INTERVAL);
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = next_interval;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
event_add(event->ev, &tv);
|
2015-11-02 15:48:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
|
|
|
|
* event that needs to be called */
|
|
|
|
static void
|
2015-11-02 21:36:09 +01:00
|
|
|
periodic_event_dispatch(evutil_socket_t fd, short what, void *data)
|
2015-11-02 15:48:18 +01:00
|
|
|
{
|
2015-11-02 21:36:09 +01:00
|
|
|
(void)fd;
|
|
|
|
(void)what;
|
2015-11-02 15:48:18 +01:00
|
|
|
periodic_event_item_t *event = data;
|
|
|
|
|
|
|
|
time_t now = time(NULL);
|
|
|
|
const or_options_t *options = get_options();
|
2016-04-06 01:38:28 +02:00
|
|
|
// log_debug(LD_GENERAL, "Dispatching %s", event->name);
|
2015-11-02 15:48:18 +01:00
|
|
|
int r = event->fn(now, options);
|
|
|
|
int next_interval = 0;
|
|
|
|
|
|
|
|
/* update the last run time if action was taken */
|
|
|
|
if (r==0) {
|
|
|
|
log_err(LD_BUG, "Invalid return value for periodic event from %s.",
|
|
|
|
event->name);
|
|
|
|
tor_assert(r != 0);
|
|
|
|
} else if (r > 0) {
|
|
|
|
event->last_action_time = now;
|
|
|
|
/* If the event is meant to happen after ten years, that's likely
|
|
|
|
* a bug, and somebody gave an absolute time rather than an interval.
|
|
|
|
*/
|
|
|
|
tor_assert(r < MAX_INTERVAL);
|
|
|
|
next_interval = r;
|
|
|
|
} else {
|
|
|
|
/* no action was taken, it is likely a precondition failed,
|
|
|
|
* we should reschedule for next second incase the precondition
|
|
|
|
* passes then */
|
|
|
|
next_interval = 1;
|
|
|
|
}
|
|
|
|
|
2016-04-06 01:38:28 +02:00
|
|
|
// log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
|
|
|
|
// next_interval);
|
2015-11-02 21:36:09 +01:00
|
|
|
struct timeval tv = { next_interval , 0 };
|
|
|
|
event_add(event->ev, &tv);
|
2015-11-02 15:48:18 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 16:40:23 +01:00
|
|
|
/** Schedules <b>event</b> to run as soon as possible from now. */
|
2015-11-02 15:48:18 +01:00
|
|
|
void
|
|
|
|
periodic_event_reschedule(periodic_event_item_t *event)
|
|
|
|
{
|
|
|
|
periodic_event_set_interval(event, 1);
|
|
|
|
}
|
|
|
|
|
2015-11-17 15:26:50 +01:00
|
|
|
/** Initializes the libevent backend for a periodic event. */
|
2015-11-02 15:48:18 +01:00
|
|
|
void
|
2015-11-17 15:26:50 +01:00
|
|
|
periodic_event_setup(periodic_event_item_t *event)
|
2015-11-02 15:48:18 +01:00
|
|
|
{
|
2015-11-17 15:26:50 +01:00
|
|
|
if (event->ev) { /* Already setup? This is a bug */
|
2015-11-02 15:48:18 +01:00
|
|
|
log_err(LD_BUG, "Initial dispatch should only be done once.");
|
|
|
|
tor_assert(0);
|
|
|
|
}
|
|
|
|
|
2015-11-02 21:36:09 +01:00
|
|
|
event->ev = tor_event_new(tor_libevent_get_base(),
|
|
|
|
-1, 0,
|
|
|
|
periodic_event_dispatch,
|
|
|
|
event);
|
|
|
|
tor_assert(event->ev);
|
2015-11-17 15:26:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Handles initial dispatch for periodic events. It should happen 1 second
|
|
|
|
* after the events are created to mimic behaviour before #3199's refactor */
|
|
|
|
void
|
|
|
|
periodic_event_launch(periodic_event_item_t *event)
|
|
|
|
{
|
|
|
|
if (! event->ev) { /* Not setup? This is a bug */
|
|
|
|
log_err(LD_BUG, "periodic_event_launch without periodic_event_setup");
|
|
|
|
tor_assert(0);
|
|
|
|
}
|
2015-11-02 15:48:18 +01:00
|
|
|
|
|
|
|
// Initial dispatch
|
2015-11-02 21:36:09 +01:00
|
|
|
periodic_event_dispatch(-1, EV_TIMEOUT, event);
|
2015-11-02 15:48:18 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 16:40:23 +01:00
|
|
|
/** Release all storage associated with <b>event</b> */
|
2015-11-02 15:48:18 +01:00
|
|
|
void
|
|
|
|
periodic_event_destroy(periodic_event_item_t *event)
|
|
|
|
{
|
|
|
|
if (!event)
|
|
|
|
return;
|
2015-11-02 21:36:09 +01:00
|
|
|
tor_event_free(event->ev);
|
2015-11-02 15:48:18 +01:00
|
|
|
event->last_action_time = 0;
|
|
|
|
}
|
|
|
|
|