Document main.c a lot better

This commit is contained in:
Nick Mathewson 2016-10-27 10:25:26 -04:00
parent 172b124006
commit dc79504e2a

View File

@ -8,6 +8,42 @@
* \file main.c * \file main.c
* \brief Toplevel module. Handles signals, multiplexes between * \brief Toplevel module. Handles signals, multiplexes between
* connections, implements main loop, and drives scheduled events. * connections, implements main loop, and drives scheduled events.
*
* For the main loop itself; see run_main_loop_once(). It invokes the rest of
* Tor mostly through Libevent callbacks. Libevent callbacks can happen when
* a timer elapses, a signal is received, a socket is ready to read or write,
* or an event is manually activated.
*
* Most events in Tor are driven from these callbacks:
* <ul>
* <li>conn_read_callback() and conn_write_callback() here, which are
* invoked when a socket is ready to read or write respectively.
* <li>signal_callback(), which handles incoming signals.
* </ul>
* Other events are used for specific purposes, or for building more complex
* control structures. If you search for usage of tor_libevent_new(), you
* will find all the events that we construct in Tor.
*
* Tor has numerous housekeeping operations that need to happen
* regularly. They are handled in different ways:
* <ul>
* <li>The most frequent operations are handled after every read or write
* event, at the end of connection_handle_read() and
* connection_handle_write().
*
* <li>The next most frequent operations happen after each invocation of the
* main loop, in run_main_loop_once().
*
* <li>Once per second, we run all of the operations listed in
* second_elapsed_callback(), and in its child, run_scheduled_events().
*
* <li>Once-a-second operations are handled in second_elapsed_callback().
*
* <li>More infrequent operations take place based on the periodic event
* driver in periodic.c . These are stored in the periodic_events[]
* table.
* </ul>
*
**/ **/
#define MAIN_PRIVATE #define MAIN_PRIVATE
@ -1408,13 +1444,13 @@ run_scheduled_events(time_t now)
pt_configure_remaining_proxies(); pt_configure_remaining_proxies();
} }
/* Periodic callback: Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion
* keys, shut down and restart all cpuworkers, and update our descriptor if
* necessary.
*/
static int static int
rotate_onion_key_callback(time_t now, const or_options_t *options) rotate_onion_key_callback(time_t now, const or_options_t *options)
{ {
/* 1a. Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion keys,
* shut down and restart all cpuworkers, and update the directory if
* necessary.
*/
if (server_mode(options)) { if (server_mode(options)) {
time_t rotation_time = get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME; time_t rotation_time = get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME;
if (rotation_time > now) { if (rotation_time > now) {
@ -1434,6 +1470,9 @@ rotate_onion_key_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE; return PERIODIC_EVENT_NO_UPDATE;
} }
/* Periodic callback: Every 30 seconds, check whether it's time to make new
* Ed25519 subkeys.
*/
static int static int
check_ed_keys_callback(time_t now, const or_options_t *options) check_ed_keys_callback(time_t now, const or_options_t *options)
{ {
@ -1451,6 +1490,11 @@ check_ed_keys_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE; return PERIODIC_EVENT_NO_UPDATE;
} }
/**
* Periodic callback: Every {LAZY,GREEDY}_DESCRIPTOR_RETRY_INTERVAL,
* see about fetching descriptors, microdescriptors, and extrainfo
* documents.
*/
static int static int
launch_descriptor_fetches_callback(time_t now, const or_options_t *options) launch_descriptor_fetches_callback(time_t now, const or_options_t *options)
{ {
@ -1465,6 +1509,10 @@ launch_descriptor_fetches_callback(time_t now, const or_options_t *options)
return GREEDY_DESCRIPTOR_RETRY_INTERVAL; return GREEDY_DESCRIPTOR_RETRY_INTERVAL;
} }
/**
* Periodic event: Rotate our X.509 certificates and TLS keys once every
* MAX_SSL_KEY_LIFETIME_INTERNAL.
*/
static int static int
rotate_x509_certificate_callback(time_t now, const or_options_t *options) rotate_x509_certificate_callback(time_t now, const or_options_t *options)
{ {
@ -1490,6 +1538,10 @@ rotate_x509_certificate_callback(time_t now, const or_options_t *options)
return MAX_SSL_KEY_LIFETIME_INTERNAL; return MAX_SSL_KEY_LIFETIME_INTERNAL;
} }
/**
* Periodic callback: once an hour, grab some more entropy from the
* kernel and feed it to our CSPRNG.
**/
static int static int
add_entropy_callback(time_t now, const or_options_t *options) add_entropy_callback(time_t now, const or_options_t *options)
{ {
@ -1506,6 +1558,10 @@ add_entropy_callback(time_t now, const or_options_t *options)
return ENTROPY_INTERVAL; return ENTROPY_INTERVAL;
} }
/**
* Periodic callback: if we're an authority, make sure we test
* the routers on the network for reachability.
*/
static int static int
launch_reachability_tests_callback(time_t now, const or_options_t *options) launch_reachability_tests_callback(time_t now, const or_options_t *options)
{ {
@ -1517,6 +1573,10 @@ launch_reachability_tests_callback(time_t now, const or_options_t *options)
return REACHABILITY_TEST_INTERVAL; return REACHABILITY_TEST_INTERVAL;
} }
/**
* Periodic callback: if we're an authority, discount the stability
* information (and other rephist information) that's older.
*/
static int static int
downrate_stability_callback(time_t now, const or_options_t *options) downrate_stability_callback(time_t now, const or_options_t *options)
{ {
@ -1528,6 +1588,10 @@ downrate_stability_callback(time_t now, const or_options_t *options)
return safe_timer_diff(now, next); return safe_timer_diff(now, next);
} }
/**
* Periodic callback: if we're an authority, record our measured stability
* information from rephist in an mtbf file.
*/
static int static int
save_stability_callback(time_t now, const or_options_t *options) save_stability_callback(time_t now, const or_options_t *options)
{ {
@ -1540,6 +1604,10 @@ save_stability_callback(time_t now, const or_options_t *options)
return SAVE_STABILITY_INTERVAL; return SAVE_STABILITY_INTERVAL;
} }
/**
* Periodic callback: if we're an authority, check on our authority
* certificate (the one that authenticates our authority signing key).
*/
static int static int
check_authority_cert_callback(time_t now, const or_options_t *options) check_authority_cert_callback(time_t now, const or_options_t *options)
{ {
@ -1552,6 +1620,10 @@ check_authority_cert_callback(time_t now, const or_options_t *options)
return CHECK_V3_CERTIFICATE_INTERVAL; return CHECK_V3_CERTIFICATE_INTERVAL;
} }
/**
* Periodic callback: If our consensus is too old, recalculate whether
* we can actually use it.
*/
static int static int
check_expired_networkstatus_callback(time_t now, const or_options_t *options) check_expired_networkstatus_callback(time_t now, const or_options_t *options)
{ {
@ -1571,6 +1643,9 @@ check_expired_networkstatus_callback(time_t now, const or_options_t *options)
return CHECK_EXPIRED_NS_INTERVAL; return CHECK_EXPIRED_NS_INTERVAL;
} }
/**
* Periodic callback: Write statistics to disk if appropriate.
*/
static int static int
write_stats_file_callback(time_t now, const or_options_t *options) write_stats_file_callback(time_t now, const or_options_t *options)
{ {
@ -1618,6 +1693,9 @@ write_stats_file_callback(time_t now, const or_options_t *options)
return safe_timer_diff(now, next_time_to_write_stats_files); return safe_timer_diff(now, next_time_to_write_stats_files);
} }
/**
* Periodic callback: Write bridge statistics to disk if appropriate.
*/
static int static int
record_bridge_stats_callback(time_t now, const or_options_t *options) record_bridge_stats_callback(time_t now, const or_options_t *options)
{ {
@ -1645,6 +1723,9 @@ record_bridge_stats_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE; return PERIODIC_EVENT_NO_UPDATE;
} }
/**
* Periodic callback: Clean in-memory caches every once in a while
*/
static int static int
clean_caches_callback(time_t now, const or_options_t *options) clean_caches_callback(time_t now, const or_options_t *options)
{ {
@ -1658,6 +1739,10 @@ clean_caches_callback(time_t now, const or_options_t *options)
return CLEAN_CACHES_INTERVAL; return CLEAN_CACHES_INTERVAL;
} }
/**
* Periodic callback: Clean the cache of failed hidden service lookups
* frequently frequently.
*/
static int static int
rend_cache_failure_clean_callback(time_t now, const or_options_t *options) rend_cache_failure_clean_callback(time_t now, const or_options_t *options)
{ {
@ -1669,20 +1754,21 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options)
return 30; return 30;
} }
/**
* Periodic callback: If we're a server and initializing dns failed, retry.
*/
static int static int
retry_dns_callback(time_t now, const or_options_t *options) retry_dns_callback(time_t now, const or_options_t *options)
{ {
(void)now; (void)now;
#define RETRY_DNS_INTERVAL (10*60) #define RETRY_DNS_INTERVAL (10*60)
/* If we're a server and initializing dns failed, retry periodically. */
if (server_mode(options) && has_dns_init_failed()) if (server_mode(options) && has_dns_init_failed())
dns_init(); dns_init();
return RETRY_DNS_INTERVAL; return RETRY_DNS_INTERVAL;
} }
/* 2. Periodically, we consider force-uploading our descriptor /** Periodic callback: consider rebuilding or and re-uploading our descriptor
* (if we've passed our internal checks). */ * (if we've passed our internal checks). */
static int static int
check_descriptor_callback(time_t now, const or_options_t *options) check_descriptor_callback(time_t now, const or_options_t *options)
{ {
@ -1709,6 +1795,11 @@ check_descriptor_callback(time_t now, const or_options_t *options)
return CHECK_DESCRIPTOR_INTERVAL; return CHECK_DESCRIPTOR_INTERVAL;
} }
/**
* Periodic callback: check whether we're reachable (as a relay), and
* whether our bandwidth has changed enough that we need to
* publish a new descriptor.
*/
static int static int
check_for_reachability_bw_callback(time_t now, const or_options_t *options) check_for_reachability_bw_callback(time_t now, const or_options_t *options)
{ {
@ -1745,13 +1836,13 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
return CHECK_DESCRIPTOR_INTERVAL; return CHECK_DESCRIPTOR_INTERVAL;
} }
/**
* Periodic event: once a minute, (or every second if TestingTorNetwork, or
* during client bootstrap), check whether we want to download any
* networkstatus documents. */
static int static int
fetch_networkstatus_callback(time_t now, const or_options_t *options) fetch_networkstatus_callback(time_t now, const or_options_t *options)
{ {
/* 2c. Every minute (or every second if TestingTorNetwork, or during
* client bootstrap), check whether we want to download any networkstatus
* documents. */
/* How often do we check whether we should download network status /* How often do we check whether we should download network status
* documents? */ * documents? */
const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping( const int we_are_bootstrapping = networkstatus_consensus_is_bootstrapping(
@ -1773,12 +1864,13 @@ fetch_networkstatus_callback(time_t now, const or_options_t *options)
return networkstatus_dl_check_interval; return networkstatus_dl_check_interval;
} }
/**
* Periodic callback: Every 60 seconds, we relaunch listeners if any died. */
static int static int
retry_listeners_callback(time_t now, const or_options_t *options) retry_listeners_callback(time_t now, const or_options_t *options)
{ {
(void)now; (void)now;
(void)options; (void)options;
/* 3d. And every 60 seconds, we relaunch listeners if any died. */
if (!net_is_disabled()) { if (!net_is_disabled()) {
retry_all_listeners(NULL, NULL, 0); retry_all_listeners(NULL, NULL, 0);
return 60; return 60;
@ -1786,6 +1878,9 @@ retry_listeners_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE; return PERIODIC_EVENT_NO_UPDATE;
} }
/**
* Periodic callback: as a server, see if we have any old unused circuits
* that should be expired */
static int static int
expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options) expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options)
{ {
@ -1795,6 +1890,10 @@ expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options)
return 11; return 11;
} }
/**
* Periodic event: if we're an exit, see if our DNS server is telling us
* obvious lies.
*/
static int static int
check_dns_honesty_callback(time_t now, const or_options_t *options) check_dns_honesty_callback(time_t now, const or_options_t *options)
{ {
@ -1817,6 +1916,10 @@ check_dns_honesty_callback(time_t now, const or_options_t *options)
return 12*3600 + crypto_rand_int(12*3600); return 12*3600 + crypto_rand_int(12*3600);
} }
/**
* Periodic callback: if we're the bridge authority, write a networkstatus
* file to disk.
*/
static int static int
write_bridge_ns_callback(time_t now, const or_options_t *options) write_bridge_ns_callback(time_t now, const or_options_t *options)
{ {
@ -1829,6 +1932,9 @@ write_bridge_ns_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE; return PERIODIC_EVENT_NO_UPDATE;
} }
/**
* Periodic callback: poke the tor-fw-helper app if we're using one.
*/
static int static int
check_fw_helper_app_callback(time_t now, const or_options_t *options) check_fw_helper_app_callback(time_t now, const or_options_t *options)
{ {
@ -1852,7 +1958,9 @@ check_fw_helper_app_callback(time_t now, const or_options_t *options)
return PORT_FORWARDING_CHECK_INTERVAL; return PORT_FORWARDING_CHECK_INTERVAL;
} }
/** Callback to write heartbeat message in the logs. */ /**
* Periodic callback: write the heartbeat message in the logs.
*/
static int static int
heartbeat_callback(time_t now, const or_options_t *options) heartbeat_callback(time_t now, const or_options_t *options)
{ {
@ -2358,19 +2466,26 @@ run_main_loop_once(void)
/* Make it easier to tell whether libevent failure is our fault or not. */ /* Make it easier to tell whether libevent failure is our fault or not. */
errno = 0; errno = 0;
#endif #endif
/* All active linked conns should get their read events activated. */
/* All active linked conns should get their read events activated,
* so that libevent knows to run their callbacks. */
SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
event_active(conn->read_event, EV_READ, 1)); event_active(conn->read_event, EV_READ, 1));
called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
/* Make sure we know (about) what time it is. */
update_approx_time(time(NULL)); update_approx_time(time(NULL));
/* poll until we have an event, or the second ends, or until we have /* Here it is: the main loop. Here we tell Libevent to poll until we have
* some active linked connections to trigger events for. */ * an event, or the second ends, or until we have some active linked
* connections to trigger events for. Libevent will wait till one
* of these happens, then run all the appropriate callbacks. */
loop_result = event_base_loop(tor_libevent_get_base(), loop_result = event_base_loop(tor_libevent_get_base(),
called_loop_once ? EVLOOP_ONCE : 0); called_loop_once ? EVLOOP_ONCE : 0);
/* let catch() handle things like ^c, and otherwise don't worry about it */ /* Oh, the loop failed. That might be an error that we need to
* catch, but more likely, it's just an interrupted poll() call or something,
* and we should try again. */
if (loop_result < 0) { if (loop_result < 0) {
int e = tor_socket_errno(-1); int e = tor_socket_errno(-1);
/* let the program survive things like ^z */ /* let the program survive things like ^z */
@ -2393,9 +2508,17 @@ run_main_loop_once(void)
} }
} }
/* This will be pretty fast if nothing new is pending. Note that this gets /* And here is where we put callbacks that happen "every time the event loop
* called once per libevent loop, which will make it happen once per group * runs." They must be very fast, or else the whole Tor process will get
* of events that fire, or once per second. */ * slowed down.
*
* Note that this gets called once per libevent loop, which will make it
* happen once per group of events that fire, or once per second. */
/* If there are any pending client connections, try attaching them to
* circuits (if we can.) This will be pretty fast if nothing new is
* pending.
*/
connection_ap_attach_pending(0); connection_ap_attach_pending(0);
return 1; return 1;