diff options
Diffstat (limited to 'src/or/main.c')
-rw-r--r-- | src/or/main.c | 634 |
1 files changed, 392 insertions, 242 deletions
diff --git a/src/or/main.c b/src/or/main.c index a852d3273d..c3505a2d91 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -59,6 +59,7 @@ #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" +#include "circuitmux_ewma.h" #include "command.h" #include "compress.h" #include "config.h" @@ -70,9 +71,9 @@ #include "control.h" #include "cpuworker.h" #include "crypto_s2k.h" +#include "crypto_rand.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "dns.h" #include "dnsserv.h" #include "dos.h" @@ -103,7 +104,6 @@ #include "routerlist.h" #include "routerparse.h" #include "scheduler.h" -#include "shared_random.h" #include "statefile.h" #include "status.h" #include "tor_api.h" @@ -118,6 +118,10 @@ #include <event2/event.h> +#include "dirauth/dirvote.h" +#include "dirauth/mode.h" +#include "dirauth/shared_random.h" + #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) /* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse @@ -159,13 +163,6 @@ token_bucket_rw_t global_bucket; /* Token bucket for relayed traffic. */ token_bucket_rw_t global_relayed_bucket; -/** What was the read/write bucket before the last second_elapsed_callback() - * call? (used to determine how many bytes we've read). */ -static size_t stats_prev_global_read_bucket; -/** What was the write bucket before the last second_elapsed_callback() call? - * (used to determine how many bytes we've written). */ -static size_t stats_prev_global_write_bucket; - /* DOCDOC stats_prev_n_read */ static uint64_t stats_prev_n_read = 0; /* DOCDOC stats_prev_n_written */ @@ -193,6 +190,8 @@ static uint64_t stats_n_main_loop_idle = 0; static time_t time_of_last_signewnym = 0; /** Is there a signewnym request we're currently waiting to handle? */ static int signewnym_is_pending = 0; +/** Mainloop event for the deferred signewnym call. */ +static mainloop_event_t *handle_deferred_signewnym_ev = NULL; /** How many times have we called newnym? */ static unsigned newnym_epoch = 0; @@ -452,6 +451,7 @@ add_connection_to_closeable_list(connection_t *conn) tor_assert(conn->marked_for_close); assert_connection_ok(conn, time(NULL)); smartlist_add(closeable_connection_lst, conn); + mainloop_schedule_postloop_cleanup(); } /** Return 1 if conn is on the closeable list, else return 0. */ @@ -479,21 +479,37 @@ get_connection_array, (void)) return connection_array; } -/** Provides the traffic read and written over the life of the process. */ - +/** + * Return the amount of network traffic read, in bytes, over the life of this + * process. + */ MOCK_IMPL(uint64_t, get_bytes_read,(void)) { return stats_n_bytes_read; } -/* DOCDOC get_bytes_written */ +/** + * Return the amount of network traffic read, in bytes, over the life of this + * process. + */ MOCK_IMPL(uint64_t, get_bytes_written,(void)) { return stats_n_bytes_written; } +/** + * Increment the amount of network traffic read and written, over the life of + * this process. + */ +void +stats_increment_bytes_read_and_written(uint64_t r, uint64_t w) +{ + stats_n_bytes_read += r; + stats_n_bytes_written += w; +} + /** Set the event mask on <b>conn</b> to <b>events</b>. (The event * mask is a bitmask whose bits are READ_EVENT and WRITE_EVENT) */ @@ -1025,19 +1041,22 @@ conn_close_if_marked(int i) * busy Libevent loops where we keep ending up here and returning * 0 until we are no longer blocked on bandwidth. */ - if (connection_is_writing(conn)) { - conn->write_blocked_on_bw = 1; - connection_stop_writing(conn); + connection_consider_empty_read_buckets(conn); + connection_consider_empty_write_buckets(conn); + + /* Make sure that consider_empty_buckets really disabled the + * connection: */ + if (BUG(connection_is_writing(conn))) { + connection_write_bw_exhausted(conn, true); } - if (connection_is_reading(conn)) { + if (BUG(connection_is_reading(conn))) { /* XXXX+ We should make this code unreachable; if a connection is * marked for close and flushing, there is no point in reading to it * at all. Further, checking at this point is a bit of a hack: it * would make much more sense to react in * connection_handle_read_impl, or to just stop reading in * mark_and_flush */ - conn->read_blocked_on_bw = 1; - connection_stop_reading(conn); + connection_read_bw_exhausted(conn, true/* kludge. */); } } return 0; @@ -1301,6 +1320,16 @@ signewnym_impl(time_t now) control_event_signal(SIGNEWNYM); } +/** Callback: run a deferred signewnym. */ +static void +handle_deferred_signewnym_cb(mainloop_event_t *event, void *arg) +{ + (void)event; + (void)arg; + log_info(LD_CONTROL, "Honoring delayed NEWNYM request"); + signewnym_impl(time(NULL)); +} + /** Return the number of times that signewnym has been called. */ unsigned get_signewnym_epoch(void) @@ -1316,69 +1345,106 @@ static int periodic_events_initialized = 0; #undef CALLBACK #define CALLBACK(name) \ static int name ## _callback(time_t, const or_options_t *) -CALLBACK(rotate_onion_key); -CALLBACK(check_onion_keys_expiry_time); -CALLBACK(check_ed_keys); -CALLBACK(launch_descriptor_fetches); -CALLBACK(rotate_x509_certificate); CALLBACK(add_entropy); -CALLBACK(launch_reachability_tests); -CALLBACK(downrate_stability); -CALLBACK(save_stability); CALLBACK(check_authority_cert); +CALLBACK(check_canonical_channels); +CALLBACK(check_descriptor); +CALLBACK(check_dns_honesty); +CALLBACK(check_ed_keys); CALLBACK(check_expired_networkstatus); -CALLBACK(write_stats_file); -CALLBACK(record_bridge_stats); +CALLBACK(check_for_reachability_bw); +CALLBACK(check_onion_keys_expiry_time); CALLBACK(clean_caches); +CALLBACK(clean_consdiffmgr); +CALLBACK(dirvote); +CALLBACK(downrate_stability); +CALLBACK(expire_old_ciruits_serverside); +CALLBACK(fetch_networkstatus); +CALLBACK(heartbeat); +CALLBACK(hs_service); +CALLBACK(launch_descriptor_fetches); +CALLBACK(launch_reachability_tests); +CALLBACK(reachability_warnings); +CALLBACK(record_bridge_stats); CALLBACK(rend_cache_failure_clean); +CALLBACK(reset_padding_counts); CALLBACK(retry_dns); -CALLBACK(check_descriptor); -CALLBACK(check_for_reachability_bw); -CALLBACK(fetch_networkstatus); CALLBACK(retry_listeners); -CALLBACK(expire_old_ciruits_serverside); -CALLBACK(check_dns_honesty); +CALLBACK(rotate_onion_key); +CALLBACK(rotate_x509_certificate); +CALLBACK(save_stability); +CALLBACK(save_state); CALLBACK(write_bridge_ns); -CALLBACK(heartbeat); -CALLBACK(clean_consdiffmgr); -CALLBACK(reset_padding_counts); -CALLBACK(check_canonical_channels); -CALLBACK(hs_service); +CALLBACK(write_stats_file); #undef CALLBACK /* Now we declare an array of periodic_event_item_t for each periodic event */ -#define CALLBACK(name) PERIODIC_EVENT(name) - -static periodic_event_item_t periodic_events[] = { - CALLBACK(rotate_onion_key), - CALLBACK(check_onion_keys_expiry_time), - CALLBACK(check_ed_keys), - CALLBACK(launch_descriptor_fetches), - CALLBACK(rotate_x509_certificate), - CALLBACK(add_entropy), - CALLBACK(launch_reachability_tests), - CALLBACK(downrate_stability), - CALLBACK(save_stability), - CALLBACK(check_authority_cert), - CALLBACK(check_expired_networkstatus), - CALLBACK(write_stats_file), - CALLBACK(record_bridge_stats), - CALLBACK(clean_caches), - CALLBACK(rend_cache_failure_clean), - CALLBACK(retry_dns), - CALLBACK(check_descriptor), - CALLBACK(check_for_reachability_bw), - CALLBACK(fetch_networkstatus), - CALLBACK(retry_listeners), - CALLBACK(expire_old_ciruits_serverside), - CALLBACK(check_dns_honesty), - CALLBACK(write_bridge_ns), - CALLBACK(heartbeat), - CALLBACK(clean_consdiffmgr), - CALLBACK(reset_padding_counts), - CALLBACK(check_canonical_channels), - CALLBACK(hs_service), +#define CALLBACK(name, r, f) PERIODIC_EVENT(name, r, f) + +STATIC periodic_event_item_t periodic_events[] = { + /* Everyone needs to run those. */ + CALLBACK(add_entropy, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(check_expired_networkstatus, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(clean_caches, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(fetch_networkstatus, PERIODIC_EVENT_ROLE_ALL, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(heartbeat, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(launch_descriptor_fetches, PERIODIC_EVENT_ROLE_ALL, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(reset_padding_counts, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(retry_listeners, PERIODIC_EVENT_ROLE_ALL, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(save_state, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(rotate_x509_certificate, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(write_stats_file, PERIODIC_EVENT_ROLE_ALL, 0), + + /* Routers (bridge and relay) only. */ + CALLBACK(check_descriptor, PERIODIC_EVENT_ROLE_ROUTER, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(check_ed_keys, PERIODIC_EVENT_ROLE_ROUTER, 0), + CALLBACK(check_for_reachability_bw, PERIODIC_EVENT_ROLE_ROUTER, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(check_onion_keys_expiry_time, PERIODIC_EVENT_ROLE_ROUTER, 0), + CALLBACK(expire_old_ciruits_serverside, PERIODIC_EVENT_ROLE_ROUTER, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(reachability_warnings, PERIODIC_EVENT_ROLE_ROUTER, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(retry_dns, PERIODIC_EVENT_ROLE_ROUTER, 0), + CALLBACK(rotate_onion_key, PERIODIC_EVENT_ROLE_ROUTER, 0), + + /* Authorities (bridge and directory) only. */ + CALLBACK(downrate_stability, PERIODIC_EVENT_ROLE_AUTHORITIES, 0), + CALLBACK(launch_reachability_tests, PERIODIC_EVENT_ROLE_AUTHORITIES, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(save_stability, PERIODIC_EVENT_ROLE_AUTHORITIES, 0), + + /* Directory authority only. */ + CALLBACK(check_authority_cert, PERIODIC_EVENT_ROLE_DIRAUTH, 0), + CALLBACK(dirvote, PERIODIC_EVENT_ROLE_DIRAUTH, PERIODIC_EVENT_FLAG_NEED_NET), + + /* Relay only. */ + CALLBACK(check_canonical_channels, PERIODIC_EVENT_ROLE_RELAY, + PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(check_dns_honesty, PERIODIC_EVENT_ROLE_RELAY, + PERIODIC_EVENT_FLAG_NEED_NET), + + /* Hidden Service service only. */ + CALLBACK(hs_service, PERIODIC_EVENT_ROLE_HS_SERVICE, + PERIODIC_EVENT_FLAG_NEED_NET), + + /* Bridge only. */ + CALLBACK(record_bridge_stats, PERIODIC_EVENT_ROLE_BRIDGE, 0), + + /* Client only. */ + CALLBACK(rend_cache_failure_clean, PERIODIC_EVENT_ROLE_CLIENT, 0), + + /* Bridge Authority only. */ + CALLBACK(write_bridge_ns, PERIODIC_EVENT_ROLE_BRIDGEAUTH, 0), + + /* Directory server only. */ + CALLBACK(clean_consdiffmgr, PERIODIC_EVENT_ROLE_DIRSERVER, 0), + END_OF_PERIODIC_EVENTS }; #undef CALLBACK @@ -1388,9 +1454,11 @@ static periodic_event_item_t periodic_events[] = { * can access them by name. We also keep them inside periodic_events[] * so that we can implement "reset all timers" in a reasonable way. */ static periodic_event_item_t *check_descriptor_event=NULL; +static periodic_event_item_t *dirvote_event=NULL; static periodic_event_item_t *fetch_networkstatus_event=NULL; static periodic_event_item_t *launch_descriptor_fetches_event=NULL; static periodic_event_item_t *check_dns_honesty_event=NULL; +static periodic_event_item_t *save_state_event=NULL; /** Reset all the periodic events so we'll do all our actions again as if we * just started up. @@ -1420,6 +1488,34 @@ 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(); + int is_dirserver = dir_server_mode(options); + + 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; + if (is_dirserver) roles |= PERIODIC_EVENT_ROLE_DIRSERVER; + + return roles; +} + /** Event to run initialize_periodic_events_cb */ static struct event *initialize_periodic_events_event = NULL; @@ -1434,11 +1530,10 @@ initialize_periodic_events_cb(evutil_socket_t fd, short events, void *data) (void) fd; (void) events; (void) data; + tor_event_free(initialize_periodic_events_event); - int i; - for (i = 0; periodic_events[i].name; ++i) { - periodic_event_launch(&periodic_events[i]); - } + + rescan_periodic_events(get_options()); } /** Set up all the members of periodic_events[], and configure them all to be @@ -1449,6 +1544,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]); @@ -1458,9 +1554,11 @@ initialize_periodic_events(void) STMT_BEGIN name ## _event = find_periodic_event( #name ); STMT_END NAMED_CALLBACK(check_descriptor); + NAMED_CALLBACK(dirvote); NAMED_CALLBACK(fetch_networkstatus); NAMED_CALLBACK(launch_descriptor_fetches); NAMED_CALLBACK(check_dns_honesty); + NAMED_CALLBACK(save_state); struct timeval one_second = { 1, 0 }; initialize_periodic_events_event = tor_evtimer_new( @@ -1479,6 +1577,57 @@ teardown_periodic_events(void) periodic_events_initialized = 0; } +/** Do a pass at all our periodic events, disable those we don't need anymore + * and enable those we need now using the given options. */ +void +rescan_periodic_events(const or_options_t *options) +{ + tor_assert(options); + + /* Avoid scanning the event list if we haven't initialized it yet. This is + * particularly useful for unit tests in order to avoid initializing main + * loop events everytime. */ + if (!periodic_events_initialized) { + return; + } + + int roles = get_my_roles(options); + + for (int i = 0; periodic_events[i].name; ++i) { + periodic_event_item_t *item = &periodic_events[i]; + + /* Handle the event flags. */ + if (net_is_disabled() && + (item->flags & PERIODIC_EVENT_FLAG_NEED_NET)) { + continue; + } + + /* Enable the event if needed. It is safe to enable an event that was + * already enabled. Same goes for disabling it. */ + if (item->roles & roles) { + log_debug(LD_GENERAL, "Launching periodic event %s", item->name); + periodic_event_enable(item); + } else { + log_debug(LD_GENERAL, "Disabling periodic event %s", item->name); + periodic_event_disable(item); + } + } +} + +/* We just got new options globally set, see if we need to enabled or disable + * periodic events. */ +void +periodic_events_on_new_options(const or_options_t *options) +{ + /* Only if we've already initialized the events, rescan the list which will + * enable or disable events depending on our roles. This will be called at + * bootup and we don't want this function to initialize the events because + * they aren't set up at this stage. */ + if (periodic_events_initialized) { + rescan_periodic_events(options); + } +} + /** * Update our schedule so that we'll check whether we need to update our * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL @@ -1487,8 +1636,9 @@ teardown_periodic_events(void) void reschedule_descriptor_update_check(void) { - tor_assert(check_descriptor_event); - periodic_event_reschedule(check_descriptor_event); + if (check_descriptor_event) { + periodic_event_reschedule(check_descriptor_event); + } } /** @@ -1505,6 +1655,30 @@ reschedule_directory_downloads(void) periodic_event_reschedule(launch_descriptor_fetches_event); } +/** Mainloop callback: clean up circuits, channels, and connections + * that are pending close. */ +static void +postloop_cleanup_cb(mainloop_event_t *ev, void *arg) +{ + (void)ev; + (void)arg; + circuit_close_all_marked(); + close_closeable_connections(); + channel_run_cleanup(); + channel_listener_run_cleanup(); +} + +/** Event to run postloop_cleanup_cb */ +static mainloop_event_t *postloop_cleanup_ev=NULL; + +/** Schedule a post-loop event to clean up marked channels, connections, and + * circuits. */ +void +mainloop_schedule_postloop_cleanup(void) +{ + mainloop_event_activate(postloop_cleanup_ev); +} + #define LONGEST_TIMER_PERIOD (30 * 86400) /** Helper: Return the number of seconds between <b>now</b> and <b>next</b>, * clipped to the range [1 second, LONGEST_TIMER_PERIOD]. */ @@ -1542,17 +1716,6 @@ run_scheduled_events(time_t now) */ consider_hibernation(now); - /* 0b. If we've deferred a signewnym, make sure it gets handled - * eventually. */ - if (signewnym_is_pending && - time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) { - log_info(LD_CONTROL, "Honoring delayed NEWNYM request"); - signewnym_impl(now); - } - - /* 0c. If we've deferred log messages for the controller, handle them now */ - flush_pending_log_callbacks(); - /* Maybe enough time elapsed for us to reconsider a circuit. */ circuit_upgrade_circuits_from_guard_wait(); @@ -1566,10 +1729,6 @@ run_scheduled_events(time_t now) accounting_run_housekeeping(now); } - if (authdir_mode_v3(options)) { - dirvote_act(options, now); - } - /* 3a. Every second, we examine pending circuits and prune the * ones which have been pending for more than a few seconds. * We do this before step 4, so it can try building more if @@ -1603,12 +1762,6 @@ run_scheduled_events(time_t now) circuit_expire_old_circs_as_needed(now); } - if (!net_is_disabled()) { - /* This is usually redundant with circuit_build_needed_circs() above, - * but it is very fast when there is no work to do. */ - connection_ap_attach_pending(0); - } - /* 5. We do housekeeping for each connection... */ channel_update_bad_for_new_circs(NULL, 0); int i; @@ -1616,32 +1769,9 @@ run_scheduled_events(time_t now) run_connection_housekeeping(i, now); } - /* 6. And remove any marked circuits... */ - circuit_close_all_marked(); - - /* 8. and blow away any connections that need to die. have to do this now, - * because if we marked a conn for close and left its socket -1, then - * we'll pass it to poll/select and bad things will happen. - */ - close_closeable_connections(); - - /* 8b. And if anything in our state is ready to get flushed to disk, we - * flush it. */ - or_state_save(now); - - /* 8c. Do channel cleanup just like for connections */ - channel_run_cleanup(); - channel_listener_run_cleanup(); - /* 11b. check pending unconfigured managed proxies */ if (!net_is_disabled() && pt_proxies_configuration_pending()) pt_configure_remaining_proxies(); - - /* 12. launch diff computations. (This is free if there are none to - * launch.) */ - if (dir_server_mode(options)) { - consdiffmgr_rescan(); - } } /* Periodic callback: rotate the onion keys after the period defined by the @@ -1851,6 +1981,40 @@ check_authority_cert_callback(time_t now, const or_options_t *options) } /** + * Scheduled callback: Run directory-authority voting functionality. + * + * The schedule is a bit complicated here, so dirvote_act() manages the + * schedule itself. + **/ +static int +dirvote_callback(time_t now, const or_options_t *options) +{ + if (!authdir_mode_v3(options)) { + tor_assert_nonfatal_unreached(); + return 3600; + } + + time_t next = dirvote_act(options, now); + if (BUG(next == TIME_MAX)) { + /* This shouldn't be returned unless we called dirvote_act() without + * being an authority. If it happens, maybe our configuration will + * fix itself in an hour or so? */ + return 3600; + } + return safe_timer_diff(now, next); +} + +/** Reschedule the directory-authority voting event. Run this whenever the + * schedule has changed. */ +void +reschedule_dirvote(const or_options_t *options) +{ + if (periodic_events_initialized && authdir_mode_v3(options)) { + periodic_event_reschedule(dirvote_event); + } +} + +/** * Periodic callback: If our consensus is too old, recalculate whether * we can actually use it. */ @@ -1873,6 +2037,34 @@ check_expired_networkstatus_callback(time_t now, const or_options_t *options) } /** + * Scheduled callback: Save the state file to disk if appropriate. + */ +static int +save_state_callback(time_t now, const or_options_t *options) +{ + (void) options; + (void) or_state_save(now); // only saves if appropriate + const time_t next_write = get_or_state()->next_write; + if (next_write == TIME_MAX) { + return 86400; + } + return safe_timer_diff(now, next_write); +} + +/** Reschedule the event for saving the state file. + * + * Run this when the state becomes dirty. */ +void +reschedule_or_state_save(void) +{ + if (save_state_event == NULL) { + /* This can happen early on during startup. */ + return; + } + periodic_event_reschedule(save_state_event); +} + +/** * Periodic callback: Write statistics to disk if appropriate. */ static int @@ -2144,6 +2336,54 @@ expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options) return 11; } +/** + * Callback: Send warnings if Tor doesn't find its ports reachable. + */ +static int +reachability_warnings_callback(time_t now, const or_options_t *options) +{ + (void) now; + + if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime()); + } + + if (server_mode(options) && + !net_is_disabled() && + have_completed_a_circuit()) { + /* every 20 minutes, check and complain if necessary */ + const routerinfo_t *me = router_get_my_routerinfo(); + if (me && !check_whether_orport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " + "its ORPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->or_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED ORADDRESS=%s:%d", + address, me->or_port); + tor_free(address); + } + + if (me && !check_whether_dirport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG, + "Your server (%s:%d) has not managed to confirm that its " + "DirPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->dir_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED DIRADDRESS=%s:%d", + address, me->dir_port); + tor_free(address); + } + } + + return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; +} + static int dns_honesty_first_time = 1; /** @@ -2224,7 +2464,7 @@ static int clean_consdiffmgr_callback(time_t now, const or_options_t *options) { (void)now; - if (server_mode(options)) { + if (dir_server_mode(options)) { consdiffmgr_cleanup(); } return CDM_CLEAN_CALLBACK_INTERVAL; @@ -2271,7 +2511,6 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg) size_t bytes_written; size_t bytes_read; int seconds_elapsed; - const or_options_t *options = get_options(); (void)timer; (void)arg; @@ -2294,43 +2533,6 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg) control_event_circ_bandwidth_used(); control_event_circuit_cell_stats(); - if (server_mode(options) && - !net_is_disabled() && - seconds_elapsed > 0 && - have_completed_a_circuit() && - get_uptime() / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT != - (get_uptime()+seconds_elapsed) / - TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - /* every 20 minutes, check and complain if necessary */ - const routerinfo_t *me = router_get_my_routerinfo(); - if (me && !check_whether_orport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " - "its ORPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->or_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED ORADDRESS=%s:%d", - address, me->or_port); - tor_free(address); - } - - if (me && !check_whether_dirport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG, - "Your server (%s:%d) has not managed to confirm that its " - "DirPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->dir_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED DIRADDRESS=%s:%d", - address, me->dir_port); - tor_free(address); - } - } - /** If more than this many seconds have elapsed, probably the clock * jumped: doesn't count. */ #define NUM_JUMPED_SECONDS_BEFORE_WARN 100 @@ -2358,63 +2560,6 @@ systemd_watchdog_callback(periodic_timer_t *timer, void *arg) } #endif /* defined(HAVE_SYSTEMD_209) */ -/** Timer: used to invoke refill_callback(). */ -static periodic_timer_t *refill_timer = NULL; - -/** Millisecond when refall_callback was last invoked. */ -static struct timeval refill_timer_current_millisecond; - -/** Libevent callback: invoked periodically to refill token buckets - * and count r/w bytes. */ -static void -refill_callback(periodic_timer_t *timer, void *arg) -{ - struct timeval now; - - size_t bytes_written; - size_t bytes_read; - int milliseconds_elapsed = 0; - int seconds_rolled_over = 0; - - const or_options_t *options = get_options(); - - (void)timer; - (void)arg; - - tor_gettimeofday(&now); - - /* If this is our first time, no time has passed. */ - if (refill_timer_current_millisecond.tv_sec) { - long mdiff = tv_mdiff(&refill_timer_current_millisecond, &now); - if (mdiff > INT_MAX) - mdiff = INT_MAX; - milliseconds_elapsed = (int)mdiff; - seconds_rolled_over = (int)(now.tv_sec - - refill_timer_current_millisecond.tv_sec); - } - - bytes_written = stats_prev_global_write_bucket - - token_bucket_rw_get_write(&global_bucket); - bytes_read = stats_prev_global_read_bucket - - token_bucket_rw_get_read(&global_bucket); - - stats_n_bytes_read += bytes_read; - stats_n_bytes_written += bytes_written; - if (accounting_is_enabled(options) && milliseconds_elapsed >= 0) - accounting_add_bytes(bytes_read, bytes_written, seconds_rolled_over); - - if (milliseconds_elapsed > 0) { - connection_bucket_refill((time_t)now.tv_sec, - monotime_coarse_get_stamp()); - } - - stats_prev_global_read_bucket = token_bucket_rw_get_read(&global_bucket); - stats_prev_global_write_bucket = token_bucket_rw_get_write(&global_bucket); - - /* remember what time it is, for next time */ - refill_timer_current_millisecond = now; -} - #ifndef _WIN32 /** Called when a possibly ignorable libevent error occurs; ensures that we * don't get into an infinite loop by ignoring too many errors from @@ -2574,6 +2719,20 @@ do_hup(void) return 0; } +/** Initialize some mainloop_event_t objects that we require. */ +STATIC void +initialize_mainloop_events(void) +{ + if (!schedule_active_linked_connections_event) { + schedule_active_linked_connections_event = + mainloop_event_postloop_new(schedule_active_linked_connections_cb, NULL); + } + if (!postloop_cleanup_ev) { + postloop_cleanup_ev = + mainloop_event_postloop_new(postloop_cleanup_cb, NULL); + } +} + /** Tor main loop. */ int do_main_loop(void) @@ -2587,10 +2746,7 @@ do_main_loop(void) initialize_periodic_events(); } - if (!schedule_active_linked_connections_event) { - schedule_active_linked_connections_event = - mainloop_event_postloop_new(schedule_active_linked_connections_cb, NULL); - } + initialize_mainloop_events(); /* initialize dns resolve map, spawn workers if needed */ if (dns_init() < 0) { @@ -2618,8 +2774,6 @@ do_main_loop(void) /* Set up our buckets */ connection_bucket_init(); - stats_prev_global_read_bucket = token_bucket_rw_get_read(&global_bucket); - stats_prev_global_write_bucket = token_bucket_rw_get_write(&global_bucket); /* initialize the bootstrap status events to know we're starting up */ control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); @@ -2669,7 +2823,7 @@ do_main_loop(void) now = time(NULL); directory_info_has_arrived(now, 1, 0); - if (server_mode(get_options())) { + if (server_mode(get_options()) || dir_server_mode(get_options())) { /* launch cpuworkers. Need to do this *after* we've read the onion key. */ cpu_init(); } @@ -2717,20 +2871,6 @@ do_main_loop(void) } #endif /* defined(HAVE_SYSTEMD_209) */ - if (!refill_timer) { - struct timeval refill_interval; - int msecs = get_options()->TokenBucketRefillInterval; - - refill_interval.tv_sec = msecs/1000; - refill_interval.tv_usec = (msecs%1000)*1000; - - refill_timer = periodic_timer_new(tor_libevent_get_base(), - &refill_interval, - refill_callback, - NULL); - tor_assert(refill_timer); - } - #ifdef HAVE_SYSTEMD { const int r = sd_notify(0, "READY=1"); @@ -2951,10 +3091,20 @@ process_signal(int sig) case SIGNEWNYM: { time_t now = time(NULL); if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) { - signewnym_is_pending = 1; + const time_t delay_sec = + time_of_last_signewnym + MAX_SIGNEWNYM_RATE - now; + if (! signewnym_is_pending) { + signewnym_is_pending = 1; + if (!handle_deferred_signewnym_ev) { + handle_deferred_signewnym_ev = + mainloop_event_postloop_new(handle_deferred_signewnym_cb, NULL); + } + const struct timeval delay_tv = { delay_sec, 0 }; + mainloop_event_schedule(handle_deferred_signewnym_ev, &delay_tv); + } log_notice(LD_CONTROL, - "Rate limiting NEWNYM request: delaying by %d second(s)", - (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); + "Rate limiting NEWNYM request: delaying by %d second(s)", + (int)(delay_sec)); } else { signewnym_impl(now); } @@ -3467,6 +3617,7 @@ tor_free_all(int postfork) consdiffmgr_free_all(); hs_free_all(); dos_free_all(); + circuitmux_ewma_free_all(); if (!postfork) { config_free_all(); or_state_free_all(); @@ -3487,11 +3638,12 @@ tor_free_all(int postfork) smartlist_free(active_linked_connection_lst); periodic_timer_free(second_timer); teardown_periodic_events(); - periodic_timer_free(refill_timer); tor_event_free(shutdown_did_not_work_event); tor_event_free(initialize_periodic_events_event); mainloop_event_free(directory_all_unreachable_cb_event); mainloop_event_free(schedule_active_linked_connections_event); + mainloop_event_free(postloop_cleanup_ev); + mainloop_event_free(handle_deferred_signewnym_ev); #ifdef HAVE_SYSTEMD_209 periodic_timer_free(systemd_watchdog_timer); @@ -3499,7 +3651,6 @@ tor_free_all(int postfork) memset(&global_bucket, 0, sizeof(global_bucket)); memset(&global_relayed_bucket, 0, sizeof(global_relayed_bucket)); - stats_prev_global_read_bucket = stats_prev_global_write_bucket = 0; stats_prev_n_read = stats_prev_n_written = 0; stats_n_bytes_read = stats_n_bytes_written = 0; time_of_process_start = 0; @@ -3516,7 +3667,6 @@ tor_free_all(int postfork) heartbeat_callback_first_time = 1; n_libevent_errors = 0; current_second = 0; - memset(&refill_timer_current_millisecond, 0, sizeof(struct timeval)); if (!postfork) { release_lockfile(); |