[or-cvs] Initial, somewhat dodgy implementation of helper nodes. It...

Nick Mathewson nickm at seul.org
Fri Jul 22 17:32:27 UTC 2005


Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv22840/src/or

Modified Files:
	circuitbuild.c config.c connection.c connection_or.c 
	directory.c or.h 
Log Message:
Initial, somewhat dodgy implementation of helper nodes.  It has too many XXXXs, it logs too verbosely, and it doesnt do persistence.

Index: circuitbuild.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuitbuild.c,v
retrieving revision 1.124
retrieving revision 1.125
diff -u -d -r1.124 -r1.125
--- circuitbuild.c	20 Jul 2005 20:33:13 -0000	1.124
+++ circuitbuild.c	22 Jul 2005 17:32:25 -0000	1.125
@@ -17,6 +17,15 @@
 /** A global list of all circuits at this hop. */
 extern circuit_t *global_circuitlist;
 
+typedef struct {
+  char nickname[MAX_NICKNAME_LEN+1];
+  char identity[DIGEST_LEN];
+  time_t down_since;
+  time_t unlisted_since;
+} helper_node_t;
+
+static smartlist_t *helper_nodes;
+
 /********* END VARIABLES ************/
 
 static int circuit_deliver_create_cell(circuit_t *circ,
@@ -27,6 +36,10 @@
                               cpath_build_state_t *state);
 static int count_acceptable_routers(smartlist_t *routers);
 static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
+static void pick_helper_nodes(void);
+static routerinfo_t *choose_random_helper(void);
+static void clear_helper_nodes(void);
+static void remove_dead_helpers(void);
 
 /** Iterate over values of circ_id, starting from conn-\>next_circ_id,
  * and with the high bit specified by circ_id_type (see
@@ -1368,7 +1381,10 @@
   return choice;
 }
 
-/** DOCDOC */
+/** DOCDOC
+ *
+ * state == null means 'pick a helper.'
+ */
 static routerinfo_t *
 choose_good_entry_server(cpath_build_state_t *state)
 {
@@ -1376,7 +1392,11 @@
   smartlist_t *excluded = smartlist_create();
   or_options_t *options = get_options();
 
-  if ((r = build_state_get_exit_router(state))) {
+  if (state && options->UseHelperNodes) {
+    return choose_random_helper();
+  }
+
+  if (state && (r = build_state_get_exit_router(state))) {
     smartlist_add(excluded, r);
     routerlist_add_family(excluded, r);
   }
@@ -1400,7 +1420,8 @@
     }
   }
   choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes,
-           excluded, state->need_uptime, state->need_capacity,
+           excluded, state ? state->need_uptime : 1,
+           state ? state->need_capacity : 0,
            options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
            options->StrictEntryNodes);
   smartlist_free(excluded);
@@ -1569,3 +1590,203 @@
   return state->chosen_exit->nickname;
 }
 
+/** DOCDOC */
+static int
+n_live_helpers(void)
+{
+  int n = 0;
+  SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
+                    if (! helper->down_since && ! helper->unlisted_since)
+                      ++n;);
+  return n;
+}
+
+/** DOCDOC */
+static void
+pick_helper_nodes(void)
+{
+  or_options_t *options = get_options();
+
+  if (! options->UseHelperNodes)
+    return;
+
+  if (helper_nodes == NULL)
+    helper_nodes = smartlist_create();
+
+  while (smartlist_len(helper_nodes) < options->NumHelperNodes) {
+    routerinfo_t *entry = choose_good_entry_server(NULL);
+    /* XXXX deal with duplicate entries. */
+    helper_node_t *helper = tor_malloc_zero(sizeof(helper_node_t));
+    /* XXXX Downgrade this to info before release. */
+    log_fn(LOG_NOTICE, "Chose '%s' as helper node.", entry->nickname);
+    strlcpy(helper->nickname, entry->nickname, sizeof(helper->nickname));
+    memcpy(helper->identity, entry->identity_digest, DIGEST_LEN);
+    smartlist_add(helper_nodes, helper);
+  }
+}
+
+/** DOCDOC */
+static void
+clear_helper_nodes(void)
+{
+  SMARTLIST_FOREACH(helper_nodes, helper_node_t *, h, tor_free(h));
+  smartlist_clear(helper_nodes);
+}
+
+#define HELPER_ALLOW_DOWNTIME 48*60*60
+#define HELPER_ALLOW_UNLISTED 48*60*60
+
+/** DOCDOC */
+static void
+remove_dead_helpers(void)
+{
+  char dbuf[HEX_DIGEST_LEN+1];
+  char tbuf[ISO_TIME_LEN+1];
+  time_t now = time(NULL);
+  int i;
+
+  for (i = 0; i < smartlist_len(helper_nodes); ) {
+    helper_node_t *helper = smartlist_get(helper_nodes, i);
+    char *why = NULL;
+    time_t since = 0;
+    if (helper->unlisted_since + HELPER_ALLOW_UNLISTED > now) {
+      why = "unlisted";
+      since = helper->unlisted_since;
+    } else if (helper->down_since + HELPER_ALLOW_DOWNTIME > now) {
+      why = "down";
+      since = helper->unlisted_since;
+    }
+    if (why) {
+      base16_encode(dbuf, sizeof(dbuf), helper->identity, DIGEST_LEN);
+      format_local_iso_time(tbuf, since);
+      log_fn(LOG_WARN, "Helper node '%s' (%s) has been %s since %s; removing.",
+             helper->nickname, dbuf, why, tbuf);
+      tor_free(helper);
+      smartlist_del(helper_nodes, i);
+    } else
+      ++i;
+  }
+}
+
+/** DOCDOC */
+void
+helper_nodes_set_status_from_directory(void)
+{
+  /* Don't call this on startup; only on a fresh download.  Otherwise we'll
+   * think that things are unlisted. */
+  routerlist_t *routers;
+  time_t now;
+  int changed = 0;
+  if (! helper_nodes)
+    return;
+
+  router_get_routerlist(&routers);
+  if (! routers)
+    return;
+
+  now = time(NULL);
+
+  /*XXXX Most of these warns should be non-warns. */
+
+  SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
+    {
+      routerinfo_t *r = router_get_by_digest(helper->identity);
+      if (! r) {
+        if (! helper->unlisted_since) {
+        /* Watch out for skew here. XXXX */
+          helper->unlisted_since = routers->published_on;
+          ++changed;
+          log_fn(LOG_WARN,"Helper node '%s' is not published in latest directory",
+                 helper->nickname);
+        }
+      } else {
+        if (helper->unlisted_since) {
+          log_fn(LOG_WARN,"Helper node '%s' is listed again in latest directory",
+                 helper->nickname);
+          ++changed;
+        }
+        helper->unlisted_since = 0;
+        if (! r->is_running) {
+          if (! helper->down_since) {
+            helper->down_since = now;
+            log_fn(LOG_WARN, "Helper node '%s' is now down.", helper->nickname);
+            ++changed;
+          }
+        } else {
+          if (helper->down_since) {
+            log_fn(LOG_WARN,"Helper node '%s' is up in latest directory",
+                   helper->nickname);
+            ++changed;
+          }
+          helper->down_since = 0;
+        }
+      }
+    });
+
+  if (changed)
+    log_fn(LOG_WARN, "    (%d/%d helpers are usable)",
+           n_live_helpers(), smartlist_len(helper_nodes));
+
+  remove_dead_helpers();
+  pick_helper_nodes();
+}
+
+/** DOCDOC */
+void
+helper_node_set_status(const char *digest, int succeeded)
+{
+  if (! helper_nodes)
+    return;
+
+  SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
+    {
+      if (!memcmp(helper->identity, digest, DIGEST_LEN)) {
+        if (succeeded) {
+          if (helper->down_since) {
+            /*XXXX shouldn't warn. */
+            log_fn(LOG_WARN,
+                   "Connection to formerly down helper node '%s' succeeeded. "
+                   "%d/%d helpers usable.", helper->nickname,
+                   n_live_helpers(), smartlist_len(helper_nodes));
+          }
+          helper->down_since = 0;
+        } else if (!helper->down_since) {
+          helper->down_since = time(NULL);
+          log_fn(LOG_WARN,
+                 "Connection to helper node '%s' failed. %d/%d helpers usable.",
+                 helper->nickname, n_live_helpers(), smartlist_len(helper_nodes));
+        }
+      }
+    });
+}
+
+/** DOCDOC */
+static routerinfo_t *
+choose_random_helper(void)
+{
+  smartlist_t *live_helpers = smartlist_create();
+  routerinfo_t *r;
+
+  if (! helper_nodes)
+    pick_helper_nodes();
+
+ retry:
+  SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
+                    if (! helper->down_since && ! helper->unlisted_since) {
+                      if ((r = router_get_by_digest(helper->identity)))
+                        smartlist_add(live_helpers, r);
+                    });
+
+  if (! smartlist_len(live_helpers)) {
+    /* XXXX Is this right?  What if network is down? */
+    log_fn(LOG_WARN, "No functional helper nodes found; picking a new set.");
+    clear_helper_nodes();
+    pick_helper_nodes();
+    goto retry;
+  }
+
+  r = smartlist_choose(live_helpers);
+  smartlist_free(live_helpers);
+  return r;
+}
+

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/config.c,v
retrieving revision 1.370
retrieving revision 1.371
diff -u -d -r1.370 -r1.371
--- config.c	22 Jul 2005 14:55:09 -0000	1.370
+++ config.c	22 Jul 2005 17:32:25 -0000	1.371
@@ -307,6 +307,9 @@
     return -1;
   }
 
+  if (options->EntryNodes && strlen(options->EntryNodes))
+    options->UseHelperNodes = 0;
+
   /* Setuid/setgid as appropriate */
   if (options->User || options->Group) {
     if (switch_id(options->User, options->Group) != 0) {

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection.c,v
retrieving revision 1.387
retrieving revision 1.388
diff -u -d -r1.387 -r1.388
--- connection.c	14 Jul 2005 23:08:55 -0000	1.387
+++ connection.c	22 Jul 2005 17:32:25 -0000	1.388
@@ -309,6 +309,7 @@
       if (conn->state != OR_CONN_STATE_OPEN) {
         if (connection_or_nonopen_was_started_here(conn)) {
           rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
+          helper_node_set_status(conn->identity_digest, 0);
           control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
         }
       } else if (conn->hold_open_until_flushed) {

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection_or.c,v
retrieving revision 1.182
retrieving revision 1.183
diff -u -d -r1.182 -r1.183
--- connection_or.c	19 Jul 2005 21:26:24 -0000	1.182
+++ connection_or.c	22 Jul 2005 17:32:25 -0000	1.183
@@ -358,6 +358,7 @@
     case -1:
       if (!options->HttpsProxy)
         router_mark_as_down(conn->identity_digest);
+      helper_node_set_status(conn->identity_digest, 0);
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
       connection_free(conn);
       return NULL;
@@ -527,6 +528,7 @@
         log_fn(severity,
                "Identity key not as expected for router at %s:%d: wanted %s but got %s",
                conn->address, conn->port, conn->nickname+1, d);
+        helper_node_set_status(conn->identity_digest, 0);
         control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
         as_advertised = 0;
       }
@@ -535,6 +537,7 @@
       log_fn(severity,
              "Other side (%s:%d) is '%s', but we tried to connect to '%s'",
              conn->address, conn->port, nickname, conn->nickname);
+      helper_node_set_status(conn->identity_digest, 0);
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
       as_advertised = 0;
     }
@@ -592,6 +595,7 @@
   connection_watch_events(conn, EV_READ);
   circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
   rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
+  helper_node_set_status(conn->identity_digest, 1);
   control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
   return 0;
 }

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/directory.c,v
retrieving revision 1.238
retrieving revision 1.239
diff -u -d -r1.238 -r1.239
--- directory.c	12 Jul 2005 22:56:22 -0000	1.238
+++ directory.c	22 Jul 2005 17:32:25 -0000	1.239
@@ -758,6 +758,7 @@
       log_fn(LOG_INFO,"updated routers.");
     }
     /* do things we've been waiting to do */
+    helper_nodes_set_status_from_directory();
     directory_has_arrived(time(NULL), conn->identity_digest);
   }
 
@@ -780,6 +781,7 @@
     router_get_routerlist(&rl);
     if (rl) {
       routerlist_set_runningrouters(rl,rrs);
+      helper_nodes_set_status_from_directory();
     } else {
       running_routers_free(rrs);
     }

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.627
retrieving revision 1.628
diff -u -d -r1.627 -r1.628
--- or.h	22 Jul 2005 14:55:09 -0000	1.627
+++ or.h	22 Jul 2005 17:32:25 -0000	1.628
@@ -1252,6 +1252,9 @@
 routerinfo_t *build_state_get_exit_router(cpath_build_state_t *state);
 const char *build_state_get_exit_nickname(cpath_build_state_t *state);
 
+void helper_node_set_status(const char *digest, int succeeded);
+void helper_nodes_set_status_from_directory(void);
+
 /********************************* circuitlist.c ***********************/
 
 circuit_t * _circuit_get_global_list(void);



More information about the tor-commits mailing list