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
This commit is contained in:
Roger Dingledine 2008-06-07 05:27:34 +00:00
parent 9b626988a6
commit 5aeb89447e
7 changed files with 155 additions and 0 deletions

View file

@ -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();

View file

@ -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];

View file

@ -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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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) */

View file

@ -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 "