From a4fcdc5decfe60bbd95aee2e5586e90c40b73225 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 17 Apr 2018 09:31:50 -0400 Subject: [PATCH] main: Launch periodic events by roles Signed-off-by: David Goulet --- src/or/main.c | 40 +++++++++++++++++++++++++++++++++++++--- src/or/networkstatus.c | 2 +- src/or/networkstatus.h | 2 ++ src/or/periodic.c | 12 +++++++++++- src/or/periodic.h | 14 ++++++++++++-- 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/or/main.c b/src/or/main.c index 5ca6277c15..52e83822ef 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1437,6 +1437,32 @@ find_periodic_event(const char *name) return NULL; } +/** Return a bitmask of the roles this tor instance is configured for using + * the given options. */ +static int +get_my_roles(const or_options_t *options) +{ + tor_assert(options); + + int roles = 0; + int is_bridge = options->BridgeRelay; + int is_client = any_client_port_set(options); + int is_relay = server_mode(options); + int is_dirauth = authdir_mode_v3(options); + int is_bridgeauth = authdir_mode_bridge(options); + int is_hidden_service = !!hs_service_get_num_services() || + !!rend_num_services(); + + if (is_bridge) roles |= PERIODIC_EVENT_ROLE_BRIDGE; + if (is_client) roles |= PERIODIC_EVENT_ROLE_CLIENT; + if (is_relay) roles |= PERIODIC_EVENT_ROLE_RELAY; + if (is_dirauth) roles |= PERIODIC_EVENT_ROLE_DIRAUTH; + if (is_bridgeauth) roles |= PERIODIC_EVENT_ROLE_BRIDGEAUTH; + if (is_hidden_service) roles |= PERIODIC_EVENT_ROLE_HS_SERVICE; + + return roles; +} + /** Event to run initialize_periodic_events_cb */ static struct event *initialize_periodic_events_event = NULL; @@ -1451,10 +1477,17 @@ initialize_periodic_events_cb(evutil_socket_t fd, short events, void *data) (void) fd; (void) events; (void) data; + + int roles = get_my_roles(get_options()); + tor_event_free(initialize_periodic_events_event); - int i; - for (i = 0; periodic_events[i].name; ++i) { - periodic_event_launch(&periodic_events[i]); + + for (int i = 0; periodic_events[i].name; ++i) { + periodic_event_item_t *item = &periodic_events[i]; + if (item->roles & roles && !periodic_event_is_enabled(item)) { + periodic_event_launch(item); + log_debug(LD_GENERAL, "Launching periodic event %s", item->name); + } } } @@ -1466,6 +1499,7 @@ initialize_periodic_events(void) tor_assert(periodic_events_initialized == 0); periodic_events_initialized = 1; + /* Set up all periodic events. We'll launch them by roles. */ int i; for (i = 0; periodic_events[i].name; ++i) { periodic_event_setup(&periodic_events[i]); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 5f19792c7d..b0db0cecbc 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1680,7 +1680,7 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c, * XXXX If we need this elsewhere at any point, we should make it nonstatic * XXXX and move it into another file. */ -static int +int any_client_port_set(const or_options_t *options) { return (options->SocksPort_set || diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index 1851a55e82..04cf277d2f 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -140,6 +140,8 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs); #define vote_routerstatus_free(rs) \ FREE_AND_NULL(vote_routerstatus_t, vote_routerstatus_free_, (rs)) +int any_client_port_set(const or_options_t *options); + #ifdef NETWORKSTATUS_PRIVATE #ifdef TOR_UNIT_TESTS STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c, diff --git a/src/or/periodic.c b/src/or/periodic.c index fa40965de1..42bea3ae65 100644 --- a/src/or/periodic.c +++ b/src/or/periodic.c @@ -78,7 +78,10 @@ periodic_event_dispatch(mainloop_event_t *ev, void *data) void periodic_event_reschedule(periodic_event_item_t *event) { - periodic_event_set_interval(event, 1); + /* Don't reschedule a disabled event. */ + if (periodic_event_is_enabled(event)) { + periodic_event_set_interval(event, 1); + } } /** Initializes the libevent backend for a periodic event. */ @@ -104,9 +107,15 @@ periodic_event_launch(periodic_event_item_t *event) log_err(LD_BUG, "periodic_event_launch without periodic_event_setup"); tor_assert(0); } + /* Event already enabled? This is a bug */ + if (periodic_event_is_enabled(event)) { + log_err(LD_BUG, "periodic_event_launch on an already enabled event"); + tor_assert(0); + } // Initial dispatch periodic_event_dispatch(event->ev, event); + event->enabled = 1; } /** Release all storage associated with event */ @@ -117,5 +126,6 @@ periodic_event_destroy(periodic_event_item_t *event) return; mainloop_event_free(event->ev); event->last_action_time = 0; + event->enabled = 0; } diff --git a/src/or/periodic.h b/src/or/periodic.h index 4544ae2763..1b346a1cc8 100644 --- a/src/or/periodic.h +++ b/src/or/periodic.h @@ -49,11 +49,21 @@ typedef struct periodic_event_item_t { /* Bitmask of roles define above for which this event applies. */ uint32_t roles; + /* Indicate that this event has been enabled that is scheduled. */ + unsigned int enabled : 1; } periodic_event_item_t; /** events will get their interval from first execution */ -#define PERIODIC_EVENT(fn, r) { fn##_callback, 0, NULL, #fn, r } -#define END_OF_PERIODIC_EVENTS { NULL, 0, NULL, NULL, 0 } +#define PERIODIC_EVENT(fn, r) { fn##_callback, 0, NULL, #fn, r, 0 } +#define END_OF_PERIODIC_EVENTS { NULL, 0, NULL, NULL, 0, 0 } + +/* Return true iff the given event was setup before thus is enabled to be + * scheduled. */ +static inline int +periodic_event_is_enabled(const periodic_event_item_t *item) +{ + return item->enabled; +} void periodic_event_launch(periodic_event_item_t *event); void periodic_event_setup(periodic_event_item_t *event); -- 2.11.4.GIT