mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Document main.c a lot better
This commit is contained in:
parent
172b124006
commit
dc79504e2a
163
src/or/main.c
163
src/or/main.c
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user