aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2008-06-07 05:27:34 +0000
committerRoger Dingledine <arma@torproject.org>2008-06-07 05:27:34 +0000
commit5aeb89447ef1683477f2ac22c91cba5f6444557d (patch)
tree27dc2a94cd2b6d3e63f9a1049d3d78af7953128e
parent9b626988a67647a60a420d81a95a889ea31ac666 (diff)
downloadtor-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.c9
-rw-r--r--src/or/connection_or.c1
-rw-r--r--src/or/control.c91
-rw-r--r--src/or/networkstatus.c8
-rw-r--r--src/or/or.h22
-rw-r--r--src/or/relay.c22
-rw-r--r--src/or/routerlist.c2
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 "