[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