[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r15008: infrastructure for the 'bootstrap status event' feature, so (tor/trunk/src/or)



Author: arma
Date: 2008-06-07 01:27:34 -0400 (Sat, 07 Jun 2008)
New Revision: 15008

Modified:
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/connection_or.c
   tor/trunk/src/or/control.c
   tor/trunk/src/or/networkstatus.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/relay.c
   tor/trunk/src/or/routerlist.c
Log:
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.


Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/circuitbuild.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -373,6 +373,8 @@
     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 @@
     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_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 @@
         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();

Modified: tor/trunk/src/or/connection_or.c
===================================================================
--- tor/trunk/src/or/connection_or.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/connection_or.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -344,6 +344,7 @@
 
   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];

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/control.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -3823,3 +3823,94 @@
   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;
+}
+

Modified: tor/trunk/src/or/networkstatus.c
===================================================================
--- tor/trunk/src/or/networkstatus.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/networkstatus.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -1196,6 +1196,14 @@
     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)

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/or.h	2008-06-07 05:27:34 UTC (rev 15008)
@@ -3016,6 +3016,27 @@
 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 @@
 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);

Modified: tor/trunk/src/or/relay.c
===================================================================
--- tor/trunk/src/or/relay.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/relay.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -932,6 +932,28 @@
     /* 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) */

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2008-06-07 05:24:47 UTC (rev 15007)
+++ tor/trunk/src/or/routerlist.c	2008-06-07 05:27:34 UTC (rev 15008)
@@ -4217,6 +4217,7 @@
     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 @@
     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 "