[or-cvs] Download network-status at regular intervals. The code is p...

Nick Mathewson nickm at seul.org
Thu Sep 8 06:22:46 UTC 2005


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

Modified Files:
	directory.c main.c or.h routerlist.c 
Log Message:
Download network-status at regular intervals. The code is probably iffy, and the constants need to be renamed.

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/directory.c,v
retrieving revision 1.256
retrieving revision 1.257
diff -u -d -r1.256 -r1.257
--- directory.c	7 Sep 2005 20:03:02 -0000	1.256
+++ directory.c	8 Sep 2005 06:22:43 -0000	1.257
@@ -163,14 +163,25 @@
   trusted_dir_server_t *ds = NULL;
   int fascistfirewall = firewall_is_fascist();
   int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
-                   purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
+                   purpose == DIR_PURPOSE_FETCH_RUNNING_LIST ||
+                   purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
+                   purpose == DIR_PURPOSE_FETCH_SERVERDESC;
   int fetch_fresh_first = advertised_server_mode();
   int priv = purpose_is_private(purpose);
+  int need_v1_support = purpose == DIR_PURPOSE_FETCH_DIR ||
+                        purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
 
   if (directconn) {
-    if (fetch_fresh_first) {
+    if (fetch_fresh_first && purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS &&
+        strlen(resource) == HEX_DIGEST_LEN) {
+      /* Try to ask the actual dirserver its opinion. */
+      char digest[DIGEST_LEN];
+      base16_decode(digest, DIGEST_LEN, resource, HEX_DIGEST_LEN);
+      ds = router_get_trusteddirserver_by_digest(digest);
+    }
+    if (!ds && fetch_fresh_first) {
       /* only ask authdirservers, and don't ask myself */
-      ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
+      ds = router_pick_trusteddirserver(need_v1_support, 1, fascistfirewall,
                                         retry_if_no_servers);
     }
     if (!ds) {
@@ -178,9 +189,17 @@
       r = router_pick_directory_server(1, fascistfirewall, 0,
                                        retry_if_no_servers);
       if (!r) {
-        log_fn(LOG_INFO, "No router found for %s; falling back to dirserver list",
-               purpose == DIR_PURPOSE_FETCH_RUNNING_LIST
-               ? "status list" : "directory");
+        const char *which;
+        if (purpose == DIR_PURPOSE_FETCH_DIR)
+          which = "directory";
+        else if (purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
+          which = "status list";
+        else if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
+          which = "network status";
+        else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
+          which = "server descriptors";
+        log_fn(LOG_INFO,
+               "No router found for %s; falling back to dirserver list",which);
         ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
                                           retry_if_no_servers);
       }
@@ -466,19 +485,21 @@
       httpcommand = "POST";
       url = tor_strdup("/tor/rendezvous/publish");
       break;
+    default:
+      tor_assert(0);
+      return;
   }
   tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
   connection_write_to_buf(request, strlen(request), conn);
   connection_write_to_buf(url, strlen(url), conn);
   tor_free(url);
 
-  tor_snprintf(request, len, " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
+  tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
            payload ? (unsigned long)payload_len : 0,
            hoststring,
            proxyauthstring);
   connection_write_to_buf(request, strlen(request), conn);
 
-
   if (payload) {
     /* then send the payload afterwards too */
     connection_write_to_buf(payload, payload_len, conn);
@@ -858,6 +879,34 @@
     }
   }
 
+  if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+    /* XXXX NM We *must* make certain we get the one(s) we asked for or we
+     * could be partitioned. */
+    log_fn(LOG_INFO,"Received networkstatus objects (size %d)",(int) body_len);
+    if (status_code != 200) {
+      log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s'. Failing.",
+             status_code, reason, conn->address);
+      tor_free(body); tor_free(headers); tor_free(reason);
+      return -1;
+    }
+    while (*body) {
+      char *next = strstr(body, "\nnetwork-status-version");
+      if (next)
+        *next = '\0';
+      if (router_set_networkstatus(body, time(NULL), 0)<0)
+        break;
+      if (next)
+        body = next+1;
+      else
+        break;
+    }
+  }
+
+  if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+    /* XXXX NM implement this. */
+    log_fn(LOG_WARN, "Somehow, we requested some individual server descriptors. Skipping.");
+  }
+
   if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
     switch (status_code) {
       case 200:

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/main.c,v
retrieving revision 1.546
retrieving revision 1.547
diff -u -d -r1.546 -r1.547
--- main.c	7 Sep 2005 16:42:53 -0000	1.546
+++ main.c	8 Sep 2005 06:22:43 -0000	1.547
@@ -731,6 +731,8 @@
         stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT &&
         !we_are_hibernating())
       consider_testing_reachability();
+
+    update_networkstatus_downloads();
   }
 
   /** 3a. Every second, we examine pending circuits and prune the

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.670
retrieving revision 1.671
diff -u -d -r1.670 -r1.671
--- or.h	8 Sep 2005 03:17:50 -0000	1.670
+++ or.h	8 Sep 2005 06:22:43 -0000	1.671
@@ -2027,6 +2027,8 @@
                                                    int requireother,
                                                    int fascistfirewall,
                                                    int retry_if_no_servers);
+trusted_dir_server_t *router_get_trusteddirserver_by_digest(
+     const char *digest);
 int all_trusted_directory_servers_down(void);
 void routerlist_add_family(smartlist_t *sl, routerinfo_t *router);
 void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int warn_if_down);
@@ -2086,6 +2088,8 @@
 void add_trusted_dir_server(const char *addr, uint16_t port,
                             const char *digest, int supports_v1);
 void clear_trusted_dir_servers(void);
+networkstatus_t *networkstatus_get_by_digest(const char *digest);
+void update_networkstatus_downloads(void);
 
 /********************************* routerparse.c ************************/
 

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerlist.c,v
retrieving revision 1.270
retrieving revision 1.271
diff -u -d -r1.270 -r1.271
--- routerlist.c	7 Sep 2005 17:18:52 -0000	1.270
+++ routerlist.c	8 Sep 2005 06:22:44 -0000	1.271
@@ -176,6 +176,21 @@
   return choice;
 }
 
+trusted_dir_server_t *
+router_get_trusteddirserver_by_digest(const char *digest)
+{
+  if (!trusted_dir_servers)
+    return NULL;
+
+  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+     {
+       if (!memcmp(ds->digest, digest, DIGEST_LEN))
+         return ds;
+     });
+
+  return NULL;
+}
+
 /** Try to find a running trusted dirserver. If there are no running
  * trusted dirservers and <b>retry_if_no_servers</b> is non-zero,
  * set them all as running again, and try again.
@@ -1219,7 +1234,10 @@
     if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
       if (!memcmp(old_ns->networkstatus_digest,
                   ns->networkstatus_digest, DIGEST_LEN)) {
+        /* Same one we had before. */
         networkstatus_free(ns);
+        if (old_ns->received_on < arrived_at)
+          old_ns->received_on = arrived_at;
         return 0;
       } else if (old_ns->published_on >= ns->published_on) {
         log_fn(LOG_INFO, "Dropping network-status; we have a newer one for this authority.");
@@ -1257,6 +1275,70 @@
   return 0;
 }
 
+/** DOCDOC */
+void
+update_networkstatus_downloads(void)
+{
+  /* XXX Yes, these constants are supposed to be dumb, so we can choose better
+   * values. */
+#define ABOUT_TWO_DAYS (48*60*60)
+#define ABOUT_HALF_AN_HOUR (30*60)
+  int n_live = 0, needed = 0, n_dirservers, i;
+  int most_recent_idx = -1;
+  trusted_dir_server_t *most_recent = NULL;
+  time_t most_recent_received = 0;
+  time_t now = time(NULL);
+
+  /* This is a little tricky.  We want to download enough network-status
+   * objects so that we have at least half of them under ABOUT_TWO_DAYS
+   * publication time.  We want to download a new *one* if the most recent
+   * one's publication time is under ABOUT_HALF_AN_HOUR.
+   */
+
+  tor_assert(trusted_dir_servers);
+  n_dirservers = smartlist_len(trusted_dir_servers);
+  SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+     {
+       networkstatus_t *ns = networkstatus_get_by_digest(ds->digest);
+       if (ns->published_on > now-ABOUT_TWO_DAYS)
+         ++n_live;
+       if (!most_recent || ns->received_on > most_recent_received) {
+         most_recent_idx = ds_sl_idx; /* magic variable from FOREACH*/
+         most_recent = ds;
+         most_recent_received = ns->received_on;
+       }
+     });
+
+  /* Download enough so we have at least half live, but no more than all the
+   * trusted dirservers we know.
+   */
+  if (n_live < (n_dirservers/2)+1)
+    needed = (n_dirservers/2)+1-n_live;
+  if (needed > n_dirservers)
+    needed = n_dirservers;
+  /* Also, download at least 1 every ABOUT_HALF_AN_HOUR. */
+  if (most_recent_received < now-ABOUT_HALF_AN_HOUR && needed < 1)
+    needed = 1;
+
+  /* If no networkstatus was found, choose a dirserver at random as "most
+   * recent". */
+  if (most_recent_idx<0)
+    most_recent_idx = crypto_pseudo_rand_int(n_dirservers);
+
+  /* XXXX NM This could compress multiple downloads into a single request.
+   * It could also be smarter on failures. */
+  for (i = most_recent_idx+1; needed; ++i) {
+    char resource[HEX_DIGEST_LEN+1];
+    trusted_dir_server_t *ds;
+    if (i > n_dirservers)
+      i = 0;
+    ds = smartlist_get(trusted_dir_servers, i);
+    base16_encode(resource, sizeof(resource), ds->digest, DIGEST_LEN);
+    directory_get_from_dirserver(DIR_PURPOSE_FETCH_NETWORKSTATUS, resource, 1);
+    --needed;
+  }
+}
+
 /** Ensure that our own routerinfo is at the front, and remove duplicates
  * of our routerinfo.
  */
@@ -1709,3 +1791,14 @@
   }
 }
 
+networkstatus_t *
+networkstatus_get_by_digest(const char *digest)
+{
+  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+    {
+      if (!memcmp(ns->identity_digest, digest, DIGEST_LEN))
+        return ns;
+    });
+  return NULL;
+}
+



More information about the tor-commits mailing list