diff options
author | Roger Dingledine <arma@torproject.org> | 2008-06-07 05:27:34 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2008-06-07 05:27:34 +0000 |
commit | 5aeb89447ef1683477f2ac22c91cba5f6444557d (patch) | |
tree | 27dc2a94cd2b6d3e63f9a1049d3d78af7953128e | |
parent | 9b626988a67647a60a420d81a95a889ea31ac666 (diff) | |
download | tor-5aeb89447ef1683477f2ac22c91cba5f6444557d.tar.gz tor-5aeb89447ef1683477f2ac22c91cba5f6444557d.zip |
infrastructure for the 'bootstrap status event' feature, so we can
tell the controller how we're doing at bootstrapping, and it can
tell the user.
svn:r15008
-rw-r--r-- | src/or/circuitbuild.c | 9 | ||||
-rw-r--r-- | src/or/connection_or.c | 1 | ||||
-rw-r--r-- | src/or/control.c | 91 | ||||
-rw-r--r-- | src/or/networkstatus.c | 8 | ||||
-rw-r--r-- | src/or/or.h | 22 | ||||
-rw-r--r-- | src/or/relay.c | 22 | ||||
-rw-r--r-- | src/or/routerlist.c | 2 |
7 files changed, 155 insertions, 0 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index c686045319..ef251da233 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -373,6 +373,8 @@ circuit_handle_first_hop(origin_circuit_t *circ) circ->_base.n_port = firsthop->extend_info->port; if (!n_conn || n_conn->_base.or_is_obsolete) { /* launch the connection */ + if (circ->build_state->onehop_tunnel) + control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0); n_conn = connection_or_connect(firsthop->extend_info->addr, firsthop->extend_info->port, firsthop->extend_info->identity_digest); @@ -590,6 +592,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) int fast; uint8_t cell_type; log_debug(LD_CIRC,"First skin; sending create cell."); + if (circ->build_state->onehop_tunnel) + control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0); + else + control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0); router = router_get_by_digest(circ->_base.n_conn->identity_digest); fast = should_use_create_fast_for_router(router, circ); @@ -641,6 +647,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); log_info(LD_CIRC,"circuit built!"); circuit_reset_failure_count(0); + if (circ->build_state->onehop_tunnel) + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); if (!has_completed_circuit && !circ->build_state->onehop_tunnel) { or_options_t *options = get_options(); has_completed_circuit=1; @@ -648,6 +656,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) log(LOG_NOTICE, LD_GENERAL, "Tor has successfully opened a circuit. " "Looks like client functionality is working."); + control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0); control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED"); if (server_mode(options) && !check_whether_orport_reachable()) { inform_testing_reachability(); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index cdc71bbd89..f9dd28de31 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -344,6 +344,7 @@ connection_or_finished_connecting(or_connection_t *or_conn) log_debug(LD_OR,"OR connect() to router at %s:%u finished.", conn->address,conn->port); + control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); if (get_options()->HttpsProxy) { char buf[1024]; diff --git a/src/or/control.c b/src/or/control.c index 878f0d2f01..edfa1c775b 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -3823,3 +3823,94 @@ init_cookie_authentication(int enabled) return 0; } +/** Convert the name of a bootstrapping phase <b>s</b> into a string + * suitable for display by the controller. */ +static const char * +bootstrap_status_to_string(bootstrap_status_t s) +{ + switch (s) { + case BOOTSTRAP_STATUS_STARTING: + return "Starting"; + case BOOTSTRAP_STATUS_CONN_DIR: + return "Connecting to directory mirror"; + case BOOTSTRAP_STATUS_HANDSHAKE: + return "Finishing handshake"; + case BOOTSTRAP_STATUS_HANDSHAKE_DIR: + return "Finishing handshake with directory mirror"; + case BOOTSTRAP_STATUS_ONEHOP_CREATE: + return "Establishing one-hop circuit for dir info"; + case BOOTSTRAP_STATUS_REQUESTING_STATUS: + return "Asking for networkstatus consensus"; + case BOOTSTRAP_STATUS_LOADING_STATUS: + return "Loading networkstatus consensus"; + case BOOTSTRAP_STATUS_LOADING_KEYS: + return "Loading authority key certs"; + case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS: + return "Asking for relay descriptors"; + case BOOTSTRAP_STATUS_LOADING_DESCRIPTORS: + return "Loading relay descriptors"; + case BOOTSTRAP_STATUS_CONN_OR: + return "Connecting to entry guard"; + case BOOTSTRAP_STATUS_HANDSHAKE_OR: + return "Finishing handshake with entry guard"; + case BOOTSTRAP_STATUS_CIRCUIT_CREATE: + return "Establishing circuits"; + case BOOTSTRAP_STATUS_DONE: + return "Done!"; + default: + log_warn(LD_BUG, "Unrecognized bootstrap status code %d", s); + return "unknown"; + } +} + +/** Called when Tor has made progress at bootstrapping its directory + * information and initial circuits. <b>status</b> is the new status, + * that is, what task we will be doing next. <b>percent</b> is zero if + * we just started this task, else it represents progress on the task. + */ +int +control_event_bootstrap(bootstrap_status_t status, int percent) +{ + static int last_percent = 0; + + if (last_percent == 100) + return 0; /* already bootstrapped; nothing to be done here. */ + + /* special case for handshaking status, since our tls handshaking code + * can't distinguish what the connection is going to be for. */ + if (status == BOOTSTRAP_STATUS_HANDSHAKE) { + if (last_percent < BOOTSTRAP_STATUS_HANDSHAKE_OR) { + status = BOOTSTRAP_STATUS_HANDSHAKE_DIR; + } else { + status = BOOTSTRAP_STATUS_HANDSHAKE_OR; + } + } + +#if 0 + if (status <= last_percent) + switch (status) { + case BOOTSTRAP_STATUS_CONN_DIR: + case BOOTSTRAP_STATUS_ONEHOP_CREATE: + case BOOTSTRAP_STATUS_HANDSHAKE_DIR: + case BOOTSTRAP_STATUS_REQUESTING_STATUS: + case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS: + boring = 1; + break; + default: ; + } + + if (!boring) +#endif + if (status > last_percent || (percent && percent > last_percent)) + log_notice(LD_CONTROL, "Bootstrapped %d%% (last %d): %s.", + status, last_percent, bootstrap_status_to_string(status)); + + /* ... This is where we tell the controller ... */ + + if (percent > last_percent) /* incremental progress within a milestone */ + last_percent = percent; + if (status > last_percent) /* new milestone reached */ + last_percent = status ; + return 0; +} + diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 7dcdcc5dac..6ae48e2a47 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1196,6 +1196,14 @@ update_certificate_downloads(time_t now) authority_certs_fetch_missing(current_consensus, now); } +/** Return 1 if we have a consensus but we don't have enough certificates + * to start using it yet. */ +int +consensus_is_waiting_for_certs(void) +{ + return consensus_waiting_for_certs ? 1 : 0; +} + /** Return the network status with a given identity digest. */ networkstatus_v2_t * networkstatus_v2_get_by_digest(const char *digest) diff --git a/src/or/or.h b/src/or/or.h index f08df26790..73ac742f98 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3016,6 +3016,27 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); +/** Enum describing various stages of bootstrapping, for use with controller + * bootstrap status events. The values range from 0 to 100. */ +typedef enum { + BOOTSTRAP_STATUS_STARTING=0, + BOOTSTRAP_STATUS_CONN_DIR=5, + BOOTSTRAP_STATUS_HANDSHAKE=-1, + BOOTSTRAP_STATUS_HANDSHAKE_DIR=10, + BOOTSTRAP_STATUS_ONEHOP_CREATE=15, + BOOTSTRAP_STATUS_REQUESTING_STATUS=20, + BOOTSTRAP_STATUS_LOADING_STATUS=25, + BOOTSTRAP_STATUS_LOADING_KEYS=40, + BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45, + BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50, + BOOTSTRAP_STATUS_CONN_OR=80, + BOOTSTRAP_STATUS_HANDSHAKE_OR=85, + BOOTSTRAP_STATUS_CIRCUIT_CREATE=90, + BOOTSTRAP_STATUS_DONE=100 +} bootstrap_status_t; + +int control_event_bootstrap(bootstrap_status_t status, int percent); + #ifdef CONTROL_PRIVATE /* Used only by control.c and test.c */ size_t write_escaped_data(const char *data, size_t len, char **out); @@ -3442,6 +3463,7 @@ void update_consensus_networkstatus_fetch_time(time_t now); int should_delay_dir_fetches(or_options_t *options); void update_networkstatus_downloads(time_t now); void update_certificate_downloads(time_t now); +int consensus_is_waiting_for_certs(void); networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest); networkstatus_t *networkstatus_get_latest_consensus(void); networkstatus_t *networkstatus_get_live_consensus(time_t now); diff --git a/src/or/relay.c b/src/or/relay.c index 0510ab4d4b..1c2ab79a21 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -932,6 +932,28 @@ connection_edge_process_relay_cell_not_open( /* don't send a socks reply to transparent conns */ if (!conn->socks_request->has_finished) connection_ap_handshake_socks_reply(conn, NULL, 0, 0); + + /* Was it a linked dir conn? If so, a dir request just started to + * fetch something; this could be a bootstrap status milestone. */ + log_debug(LD_APP, "considering"); + if (TO_CONN(conn)->linked_conn && + TO_CONN(conn)->linked_conn->type == CONN_TYPE_DIR) { + connection_t *dirconn = TO_CONN(conn)->linked_conn; + log_debug(LD_APP, "it is! %d", dirconn->purpose); + switch (dirconn->purpose) { + case DIR_PURPOSE_FETCH_CERTIFICATE: + if (consensus_is_waiting_for_certs()) + control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_KEYS, 0); + break; + case DIR_PURPOSE_FETCH_CONSENSUS: + control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_STATUS, 0); + break; + case DIR_PURPOSE_FETCH_SERVERDESC: + control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, 0); + break; + } + } + /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1) < 0) { /* (We already sent an end cell if possible) */ diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 5bd00f7b39..f00e36712a 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -4217,6 +4217,7 @@ update_router_have_minimum_dir_info(void) tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable descriptors.", num_present, num_usable); res = 0; + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); } else if (num_present < 2) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "Only %d descriptor%s here and believed reachable!", @@ -4231,6 +4232,7 @@ update_router_have_minimum_dir_info(void) log(LOG_NOTICE, LD_DIR, "We now have enough directory information to build circuits."); control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); + control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0); } if (!res && have_min_dir_info) { log(LOG_NOTICE, LD_DIR,"Our directory information is no longer up-to-date " |