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

[or-cvs] More stuff for new directories.



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

Modified Files:
	config.c directory.c dirserv.c main.c or.h router.c 
	routerlist.c routerparse.c 
Log Message:
More stuff for new directories.

- Distinguish v1 authorities (all currently trusted directories) from
  v2 authorities (all trusted directories). 
    - Add configuration option for which dirs are v1 authories.
    - Add configuration option for whether to be a v1 authority.
    - Make trusted dirserver selection functions take options to 
      choose which functionality we need.
    - Remove option when getting directory cache to see whether they 
      support running-routers; they all do now.  Replace it with one
      to see whether caches support v2 stuff.

- Parse, cache, and serve network-status objects properly.

- Serve compressed groups of router descriptors.  The compression logic
  here could be more memory-efficient.

- 


Index: config.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/config.c,v
retrieving revision 1.403
retrieving revision 1.404
diff -u -d -r1.403 -r1.404
--- config.c	2 Sep 2005 20:29:29 -0000	1.403
+++ config.c	7 Sep 2005 16:42:53 -0000	1.404
@@ -102,6 +102,8 @@
   VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
   VAR("AssumeReachable",     BOOL,     AssumeReachable,      "0"),
   VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
+  /* XXXX 011 change this default on 0.1.1.x */
+  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "1"),
   VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
   VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
   VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
@@ -1140,13 +1142,13 @@
 {
   /* moria1 */
   config_line_append(&options->DirServers, "DirServer",
-       "18.244.0.188:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
+     "v1 18.244.0.188:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
   /* moria2 */
   config_line_append(&options->DirServers, "DirServer",
-         "18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
+     "v1 18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
   /* tor26 */
   config_line_append(&options->DirServers, "DirServer",
-     "86.59.5.130:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
+     "v1 86.59.5.130:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
 //  "tor.noreply.org:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
 }
 
@@ -2753,6 +2755,15 @@
   char *addrport, *address=NULL;
   uint16_t port;
   char digest[DIGEST_LEN];
+  int supports_v1 = 1; /*XXXX011 change default when clients support v2. */
+
+  while (TOR_ISSPACE(*line))
+    ++line;
+
+  if (!strcmpstart(line, "v1 ")) {
+    line += 3;
+    supports_v1 = 1;
+  }
 
   items = smartlist_create();
   smartlist_split_string(items, line, NULL,
@@ -2785,7 +2796,7 @@
   if (!validate_only) {
     log_fn(LOG_DEBUG, "Trusted dirserver at %s:%d (%s)", address, (int)port,
            (char*)smartlist_get(items,1));
-    add_trusted_dir_server(address, port, digest);
+    add_trusted_dir_server(address, port, digest, supports_v1);
   }
 
   r = 0;

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/directory.c,v
retrieving revision 1.253
retrieving revision 1.254
diff -u -d -r1.253 -r1.254
--- directory.c	6 Sep 2005 06:14:38 -0000	1.253
+++ directory.c	7 Sep 2005 16:42:53 -0000	1.254
@@ -170,26 +170,25 @@
   if (directconn) {
     if (fetch_fresh_first) {
       /* only ask authdirservers, and don't ask myself */
-      ds = router_pick_trusteddirserver(1, fascistfirewall,
+      ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
                                         retry_if_no_servers);
     }
     if (!ds) {
       /* anybody with a non-zero dirport will do */
-      r = router_pick_directory_server(1, fascistfirewall,
-                                purpose==DIR_PURPOSE_FETCH_RUNNING_LIST,
+      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");
-        ds = router_pick_trusteddirserver(1, fascistfirewall,
+        ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
                                           retry_if_no_servers);
       }
     }
   } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
     /* only ask authdirservers, any of them will do */
     /* Never use fascistfirewall; we're going via Tor. */
-    ds = router_pick_trusteddirserver(0, 0, retry_if_no_servers);
+    ds = router_pick_trusteddirserver(0, 0, 0, retry_if_no_servers);
   }
 
   if (r)
@@ -1062,24 +1061,39 @@
     /* v2 network status fetch. */
     size_t url_len = strlen(url);
     int deflated = !strcmp(url+url_len-2, ".z");
+    smartlist_t *dir_objs = smartlist_create();
     const char *key = url + strlen("/tor/status/");
     if (deflated)
       url[url_len-2] = '\0';
-    dlen = dirserv_get_networkstatus_v2(&cp, key, deflated);
+    if (dirserv_get_networkstatus_v2(dir_objs, key)) {
+      smartlist_free(dir_objs);
+      return 0;
+    }
     tor_free(url);
-    if (!dlen) { /* we failed to create/cache cp */
+    if (!smartlist_len(dir_objs)) { /* we failed to create/cache cp */
       write_http_status_line(conn, 503, "Network status object unavailable");
+      smartlist_free(dir_objs);
       /* try to get a new one now */
       // XXXX NM
       return 0;
     }
+    dlen = 0;
+    SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
+                      dlen += deflated?d->dir_z_len:d->dir_len);
     format_rfc1123_time(date, time(NULL));
     tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n",
                  date,
                  (int)dlen,
                  deflated?"deflate":"identity");
     connection_write_to_buf(tmp, strlen(tmp), conn);
-    connection_write_to_buf(cp, strlen(cp), conn);
+    SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
+       {
+         if (deflated)
+           connection_write_to_buf(d->dir_z, d->dir_z_len, conn);
+         else
+           connection_write_to_buf(d->dir, d->dir_len, conn);
+       });
+    smartlist_free(dir_objs);
     return 0;
   }
 
@@ -1098,15 +1112,42 @@
       format_rfc1123_time(date, time(NULL));
       SMARTLIST_FOREACH(descs, routerinfo_t *, ri,
                         len += ri->signed_descriptor_len);
-      /* XXXX We need to support deflate here. */
-      tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
-                   date,
-                   (int)len);
-      connection_write_to_buf(tmp, strlen(tmp), conn);
-      SMARTLIST_FOREACH(descs, routerinfo_t *, ri,
-                        connection_write_to_buf(ri->signed_descriptor,
-                                                ri->signed_descriptor_len,
-                                                conn));
+      if (deflated) {
+        size_t compressed_len;
+        char *compressed;
+        char *inp = tor_malloc(len+smartlist_len(descs)+1);
+        char *cp = inp;
+        SMARTLIST_FOREACH(descs, routerinfo_t *, ri,
+           {
+             memcpy(cp, ri->signed_descriptor,
+                    ri->signed_descriptor_len);
+             cp += ri->signed_descriptor_len;
+             *cp++ = '\n';
+           });
+        *cp = '\0';
+        /* XXXX This could be way more efficiently handled. */
+        if (tor_gzip_compress(&compressed, &compressed_len,
+                              inp, cp-inp, ZLIB_METHOD)<0){
+          tor_free(cp);
+          smartlist_free(descs);
+          return -1;
+        }
+        tor_free(cp);
+        tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
+                     date,
+                     (int)compressed_len);
+        connection_write_to_buf(tmp, strlen(tmp), conn);
+        connection_write_to_buf(compressed, compressed_len, conn);
+      } else {
+        tor_snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
+                     date,
+                     (int)len);
+        connection_write_to_buf(tmp, strlen(tmp), conn);
+        SMARTLIST_FOREACH(descs, routerinfo_t *, ri,
+                          connection_write_to_buf(ri->signed_descriptor,
+                                                  ri->signed_descriptor_len,
+                                                  conn));
+      }
     }
     smartlist_free(descs);
     return 0;

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/dirserv.c,v
retrieving revision 1.206
retrieving revision 1.207
diff -u -d -r1.206 -r1.207
--- dirserv.c	3 Sep 2005 04:37:30 -0000	1.206
+++ dirserv.c	7 Sep 2005 16:42:53 -0000	1.207
@@ -669,16 +669,6 @@
   return -1;
 }
 
-/** A cached_dir_t represents a cacheable directory object, along with its
- * compressed form. */
-typedef struct cached_dir_t {
-  char *dir; /**< Contents of this object */
-  char *dir_z; /**< Compressed contents of this object. */
-  size_t dir_len; /**< Length of <b>dir</b> */
-  size_t dir_z_len; /**< Length of <b>dir_z</b> */
-  time_t published; /**< When was this object published */
-} cached_dir_t;
-
 /** Most recently generated encoded signed directory. (auth dirservers only.)*/
 static cached_dir_t the_directory = { NULL, NULL, 0, 0, 0 };
 
@@ -768,7 +758,6 @@
                                     time_t published)
 {
   cached_dir_t *d;
-  char fname[512];
   if (!cached_v2_networkstatus)
     cached_v2_networkstatus = strmap_new();
 
@@ -781,14 +770,33 @@
 
   tor_assert(d);
   set_cached_dir(d, tor_strdup(directory), published);
+}
 
-  if (!d->dir)
-    return;
+static cached_dir_t *
+dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
+                            cached_dir_t *auth_src,
+                            time_t dirty, int (*regenerate)(void),
+                            const char *name,
+                            int is_v1_object)
+{
+  int authority = get_options()->AuthoritativeDir &&
+    (!is_v1_object || get_options()->V1AuthoritativeDir);
 
-  tor_snprintf(fname,sizeof(fname), "%s/cached-status/%s",
-               get_options()->DataDirectory, fp);
-  if (write_str_to_file(fname, d->dir, 0)<0) {
-    log_fn(LOG_NOTICE, "Couldn't write cached network status to disk. Ignoring.");
+  if (!authority) {
+    return cache_src;
+  } else {
+    /* We're authoritative. */
+    if (regenerate != NULL) {
+      if (dirty && dirty + DIR_REGEN_SLACK_TIME < time(NULL)) {
+        if (regenerate()) {
+          log_fn(LOG_ERR, "Couldn't generate %s?", name);
+          exit(1);
+        }
+      } else {
+        log_fn(LOG_INFO, "The %s is still clean; reusing.", name);
+      }
+    }
+    return auth_src ? auth_src : cache_src;
   }
 }
 
@@ -798,30 +806,22 @@
  * DIR_REGEN_SLACK_TIME seconds, call <b>regenerate</b>() to make a fresh one.
  * Yields the compressed version of the directory object if <b>compress</b> is
  * set; otherwise return the uncompressed version.  (In either case, sets
- * *<b>out</b> and returns the size of the buffer in *<b>out</b>. */
+ * *<b>out</b> and returns the size of the buffer in *<b>out</b>.
+ *
+ * DOCDOC is_v1_object
+ **/
 static size_t
 dirserv_get_obj(const char **out, int compress,
                 cached_dir_t *cache_src,
                 cached_dir_t *auth_src,
                 time_t dirty, int (*regenerate)(void),
-                const char *name)
+                const char *name,
+                int is_v1_object)
 {
-  cached_dir_t *d;
-  if (!get_options()->AuthoritativeDir || !auth_src) {
-    d = cache_src;
-  } else {
-    if (regenerate != NULL) {
-      if (dirty && dirty + DIR_REGEN_SLACK_TIME < time(NULL)) {
-        if (regenerate()) {
-          log_fn(LOG_ERR, "Couldn't generate %s?", name);
-          exit(1);
-        }
-      } else {
-        log_fn(LOG_INFO, "The %s is still clean; reusing.", name);
-      }
-    }
-    d = auth_src;
-  }
+  cached_dir_t *d = dirserv_pick_cached_dir_obj(
+      cache_src, auth_src,
+      dirty, regenerate, name, is_v1_object);
+
   if (!d)
     return 0;
   *out = compress ? d->dir_z : d->dir;
@@ -843,7 +843,7 @@
                          &cached_directory, &the_directory,
                          the_directory_is_dirty,
                          dirserv_regenerate_directory,
-                         "server directory");
+                         "server directory", 1);
 }
 
 /**
@@ -938,7 +938,7 @@
                          &cached_runningrouters, &the_runningrouters,
                          runningrouters_is_dirty,
                          generate_runningrouters,
-                         "v1 network status list");
+                         "v1 network status list", 1);
 }
 
 /** Return true iff <b>ri</b> is "useful as an exit node." */
@@ -1132,8 +1132,7 @@
   set_cached_dir(&the_v2_networkstatus, status, time(NULL));
   status = NULL; /* So it doesn't get double-freed. */
   the_v2_networkstatus_is_dirty = 0;
-  dirserv_set_cached_networkstatus_v2(the_v2_networkstatus.dir,
-                                      fingerprint, time(NULL));
+  router_set_networkstatus(the_v2_networkstatus.dir, time(NULL), 0);
 
   r = 0;
  done:
@@ -1153,27 +1152,43 @@
  * nothing was found; otherwise set *<b>directory</b> to the matching network
  * status and return its length.
  */
-size_t
-dirserv_get_networkstatus_v2(const char **directory, const char *key,
-                             int compress)
+int
+dirserv_get_networkstatus_v2(smartlist_t *result,
+                             const char *key)
 {
-  *directory = NULL;
+  tor_assert(result);
+
   if (!(strcmp(key,"authority"))) {
     if (get_options()->AuthoritativeDir) {
-      return dirserv_get_obj(directory, compress, NULL,
-                             &the_v2_networkstatus,
-                             the_v2_networkstatus_is_dirty,
-                             generate_v2_networkstatus,
-                             "network status list");
+      cached_dir_t *d =
+        dirserv_pick_cached_dir_obj(NULL,
+                                    &the_v2_networkstatus,
+                                    the_v2_networkstatus_is_dirty,
+                                    generate_v2_networkstatus,
+                                    "network status list", 0);
+      if (d)
+        smartlist_add(result, d);
     }
   } else if (!strcmp(key, "all")) {
-    // XXXX NM
-    return dirserv_get_networkstatus_v2(directory, "authority", compress);
-  } else if (strlen(key)==HEX_DIGEST_LEN) {
-    cached_dir_t *cached = strmap_get(cached_v2_networkstatus, key);
-    if (cached)
-      return dirserv_get_obj(directory, compress, cached, NULL, 0, NULL,
-                             "cached network status");
+    strmap_iter_t *iter = strmap_iter_init(cached_v2_networkstatus);
+    while (!strmap_iter_done(iter)) {
+      const char *fp;
+      void *val;
+      strmap_iter_get(iter, &fp, &val);
+      smartlist_add(result, val);
+    }
+  } else if (!strcmpstart(key, "fp/")) {
+    smartlist_t *hexdigests = smartlist_create();
+    smartlist_split_string(hexdigests, key+3, "+", 0, 0);
+    SMARTLIST_FOREACH(hexdigests, char *, cp,
+        {
+          cached_dir_t *cached;
+          tor_strlower(cp);
+          /* XXXX special-case own key? */
+          cached = strmap_get(cached_v2_networkstatus, cp);
+          if (cached)
+            smartlist_add(result, cached);
+        });
   }
   return 0;
 }

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/main.c,v
retrieving revision 1.545
retrieving revision 1.546
diff -u -d -r1.545 -r1.546
--- main.c	3 Sep 2005 04:37:30 -0000	1.545
+++ main.c	7 Sep 2005 16:42:53 -0000	1.546
@@ -711,7 +711,7 @@
   }
 
   if (time_to_fetch_running_routers < now) {
-    if (!authdir_mode(options)) {
+    if (!authdir_mode(options) || !options->V1AuthoritativeDir) {
       directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
     }
     time_to_fetch_running_routers = now + get_status_fetch_period(options);
@@ -972,6 +972,9 @@
   if (router_reload_router_list()) {
     return -1;
   }
+  if (router_reload_networkstatus()) {
+    return -1;
+  }
 
   if (authdir_mode(get_options())) {
     /* the directory is already here, run startup things */

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.666
retrieving revision 1.667
diff -u -d -r1.666 -r1.667
--- or.h	4 Sep 2005 23:12:27 -0000	1.666
+++ or.h	7 Sep 2005 16:42:53 -0000	1.667
@@ -705,6 +705,17 @@
   struct addr_policy_t *next; /**< Next rule in list. */
 } addr_policy_t;
 
+
+/** A cached_dir_t represents a cacheable directory object, along with its
+ * compressed form. */
+typedef struct cached_dir_t {
+  char *dir; /**< Contents of this object */
+  char *dir_z; /**< Compressed contents of this object. */
+  size_t dir_len; /**< Length of <b>dir</b> */
+  size_t dir_z_len; /**< Length of <b>dir_z</b> */
+  time_t published; /**< When was this object published */
+} cached_dir_t;
+
 /** Information about another onion router in the network. */
 typedef struct {
   char *signed_descriptor; /**< The original signed descriptor for this router*/
@@ -789,6 +800,8 @@
 typedef struct networkstatus_t {
   /** When did we receive the network-status document? */
   time_t received_on;
+  /** What was the digest of the document? */
+  char networkstatus_digest[DIGEST_LEN];
 
   /* These fields come from the actual network-status document.*/
   time_t published_on; /**< Declared publication date. */
@@ -1146,6 +1159,7 @@
   int DirPort; /**< Port to listen on for directory connections. */
   int AssumeReachable; /**< Whether to publish our descriptor regardless. */
   int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
+  int V1AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
   int ClientOnly; /**< Boolean: should we never evolve into a server role? */
   int NoPublish; /**< Boolean: should we never publish a descriptor? */
   int ConnLimit; /**< Requested maximum number of simultaneous connections. */
@@ -1694,8 +1708,7 @@
                                   int is_running_routers);
 void dirserv_set_cached_networkstatus_v2(const char *directory, const char *fp,
                                          time_t published);
-size_t dirserv_get_networkstatus_v2(const char **directory, const char *key,
-                                    int compress);
+int dirserv_get_networkstatus_v2(smartlist_t *result, const char *key);
 void dirserv_get_routerdescs(smartlist_t *descs_out, const char *key);
 void dirserv_orconn_tls_done(const char *address,
                              uint16_t or_port,
@@ -1995,15 +2008,18 @@
   uint16_t dir_port;
   char digest[DIGEST_LEN];
   int is_running;
+  int supports_v1_protocol;
 } trusted_dir_server_t;
 
 int router_reload_router_list(void);
+int router_reload_networkstatus(void);
 void router_get_trusted_dir_servers(smartlist_t **outp);
 routerinfo_t *router_pick_directory_server(int requireother,
                                            int fascistfirewall,
-                                           int for_running_routers,
+                                           int for_v2_directory,
                                            int retry_if_no_servers);
-trusted_dir_server_t *router_pick_trusteddirserver(int requireother,
+trusted_dir_server_t *router_pick_trusteddirserver(int need_v1_support,
+                                                   int requireother,
                                                    int fascistfirewall,
                                                    int retry_if_no_servers);
 int all_trusted_directory_servers_down(void);
@@ -2046,6 +2062,7 @@
 int router_load_single_router(const char *s, const char **msg);
 int router_load_routerlist_from_directory(const char *s,crypto_pk_env_t *pkey,
                                         int dir_is_recent, int dir_is_cached);
+int router_set_networkstatus(const char *s, time_t arrived_at, int is_cached);
 addr_policy_result_t router_compare_addr_to_addr_policy(uint32_t addr,
                               uint16_t port, addr_policy_t *policy);
 
@@ -2061,7 +2078,8 @@
 int router_update_status_from_smartlist(routerinfo_t *r,
                                         time_t list_time,
                                         smartlist_t *running_list);
-void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest);
+void add_trusted_dir_server(const char *addr, uint16_t port,
+                            const char *digest, int supports_v1);
 void clear_trusted_dir_servers(void);
 
 /********************************* routerparse.c ************************/

Index: router.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/router.c,v
retrieving revision 1.201
retrieving revision 1.202
diff -u -d -r1.201 -r1.202
--- router.c	3 Sep 2005 23:10:28 -0000	1.201
+++ router.c	7 Sep 2005 16:42:53 -0000	1.202
@@ -368,7 +368,8 @@
   /* 6b. [authdirserver only] add own key to approved directories. */
   crypto_pk_get_digest(get_identity_key(), digest);
   if (!router_digest_is_trusted_dir(digest)) {
-    add_trusted_dir_server(NULL, (uint16_t)options->DirPort, digest);
+    add_trusted_dir_server(NULL, (uint16_t)options->DirPort, digest,
+                           options->V1AuthoritativeDir);
   }
 #if 0
   /* 7. [authdirserver only] load old directory, if it's there */

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerlist.c,v
retrieving revision 1.268
retrieving revision 1.269
diff -u -d -r1.268 -r1.269
--- routerlist.c	4 Sep 2005 23:12:27 -0000	1.268
+++ routerlist.c	7 Sep 2005 16:42:53 -0000	1.269
@@ -21,9 +21,10 @@
 /* static function prototypes */
 static routerinfo_t *
 router_pick_directory_server_impl(int requireother, int fascistfirewall,
-                                  int for_runningrouters);
+                                  int for_v2_directory);
 static trusted_dir_server_t *
-router_pick_trusteddirserver_impl(int requireother, int fascistfirewall);
+router_pick_trusteddirserver_impl(int need_v1_support,
+                                  int requireother, int fascistfirewall);
 static void mark_all_trusteddirservers_up(void);
 static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
 static int router_nickname_matches(routerinfo_t *router, const char *nickname);
@@ -78,12 +79,13 @@
   return 0;
 }
 
+/** DOCDOC */
 int
 router_reload_networkstatus(void)
 {
   char filename[512];
   struct stat st;
-  smartlist_t *entries;
+  smartlist_t *entries, *bad_names;
   char *s;
   tor_assert(get_options()->DataDirectory);
   if (!networkstatus_list)
@@ -92,17 +94,24 @@
   tor_snprintf(filename,sizeof(filename),"%s/cached-status",
                get_options()->DataDirectory);
   entries = tor_listdir(filename);
+  bad_names = smartlist_create();
   SMARTLIST_FOREACH(entries, const char *, fn, {
+      char buf[DIGEST_LEN];
+      if (strlen(fn) != HEX_DIGEST_LEN ||
+          base16_decode(buf, sizeof(buf), fn, strlen(fn))) {
+        log_fn(LOG_INFO,
+               "Skipping cached-status file with unexpected name \"%s\"",fn);
+        continue;
+      }
       tor_snprintf(filename,sizeof(filename),"%s/cached-status/%s",
                    get_options()->DataDirectory, fn);
       s = read_file_to_str(filename, 0);
       if (s) {
-        networkstatus_t *ns;
         stat(filename, &st);
-        log_fn(LOG_INFO, "Loading cached network status from %s", filename);
-        ns = networkstatus_parse_from_string(s);
-        ns->received_on = st.st_mtime;
-        smartlist_add(networkstatus_list, ns);
+        if (router_set_networkstatus(s, st.st_mtime, 1)<0) {
+          log_fn(LOG_WARN, "Couldn't load networkstatus from \"%s\"",filename);
+        }
+        tor_free(s);
       }
     });
   return 0;
@@ -133,7 +142,7 @@
 routerinfo_t *
 router_pick_directory_server(int requireother,
                              int fascistfirewall,
-                             int for_runningrouters,
+                             int for_v2_directory,
                              int retry_if_no_servers)
 {
   routerinfo_t *choice;
@@ -142,7 +151,7 @@
     return NULL;
 
   choice = router_pick_directory_server_impl(requireother, fascistfirewall,
-                                             for_runningrouters);
+                                             for_v2_directory);
   if (choice || !retry_if_no_servers)
     return choice;
 
@@ -151,7 +160,7 @@
   mark_all_trusteddirservers_up();
   /* try again */
   choice = router_pick_directory_server_impl(requireother, fascistfirewall,
-                                             for_runningrouters);
+                                             for_v2_directory);
   if (choice)
     return choice;
 
@@ -163,7 +172,7 @@
   }
   /* give it one last try */
   choice = router_pick_directory_server_impl(requireother, 0,
-                                             for_runningrouters);
+                                             for_v2_directory);
   return choice;
 }
 
@@ -171,21 +180,26 @@
  * trusted dirservers and <b>retry_if_no_servers</b> is non-zero,
  * set them all as running again, and try again.
  * Other args are as in router_pick_trusteddirserver_impl().
+ *
+ * DOCDOC need_v1_support
  */
 trusted_dir_server_t *
-router_pick_trusteddirserver(int requireother,
+router_pick_trusteddirserver(int need_v1_support,
+                             int requireother,
                              int fascistfirewall,
                              int retry_if_no_servers)
 {
   trusted_dir_server_t *choice;
 
-  choice = router_pick_trusteddirserver_impl(requireother, fascistfirewall);
+  choice = router_pick_trusteddirserver_impl(need_v1_support,
+                                             requireother, fascistfirewall);
   if (choice || !retry_if_no_servers)
     return choice;
 
   log_fn(LOG_INFO,"No trusted dirservers are reachable. Trying them all again.");
   mark_all_trusteddirservers_up();
-  return router_pick_trusteddirserver_impl(requireother, fascistfirewall);
+  return router_pick_trusteddirserver_impl(need_v1_support,
+                                           requireother, fascistfirewall);
 }
 
 /** Pick a random running verified directory server/mirror from our
@@ -193,13 +207,12 @@
  * If <b>fascistfirewall</b> and we're not using a proxy,
  * make sure the port we pick is allowed by options-\>firewallports.
  * If <b>requireother</b>, it cannot be us.
- * If <b>for_runningrouters</b>, make sure we pick a dirserver that
- * can answer queries for running-routers (this option will become obsolete
- * once 0.0.9-rc5 is dead).
+ *
+ * DOCDOC need_v1_support, for_v2_directory
  */
 static routerinfo_t *
 router_pick_directory_server_impl(int requireother, int fascistfirewall,
-                                  int for_runningrouters)
+                                  int for_v2_directory)
 {
   int i;
   routerinfo_t *router;
@@ -223,9 +236,9 @@
       if (!fascist_firewall_allows_address(router->addr, router->dir_port))
         continue;
     }
-    /* before 0.0.9rc5-cvs, only trusted dirservers served status info. */
-    if (for_runningrouters &&
-        !(tor_version_as_new_as(router->platform,"0.0.9rc5-cvs") ||
+    /* before 0.1.1.6-alpha, only trusted dirservers served status info. */
+    if (for_v2_directory &&
+        !(tor_version_as_new_as(router->platform,"0.1.1.6-alpha") ||
           router_digest_is_trusted_dir(router->identity_digest)))
       continue;
     smartlist_add(sl, router);
@@ -242,7 +255,8 @@
  * If <b>requireother</b>, it cannot be us.
  */
 static trusted_dir_server_t *
-router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
+router_pick_trusteddirserver_impl(int need_v1_support,
+                                  int requireother, int fascistfirewall)
 {
   smartlist_t *sl;
   routerinfo_t *me;
@@ -259,6 +273,8 @@
   SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
     {
       if (!d->is_running) continue;
+      if (need_v1_support && !d->supports_v1_protocol)
+        continue;
       if (requireother && me &&
           !memcmp(me->identity_digest, d->digest, DIGEST_LEN))
         continue;
@@ -1166,6 +1182,79 @@
   return 0;
 }
 
+/** DOCDOC returns 0 on no problems, -1 on problems.
+ */
+int
+router_set_networkstatus(const char *s, time_t arrived_at, int is_cached)
+{
+  networkstatus_t *ns;
+  int i, found;
+  time_t now;
+  char fp[HEX_DIGEST_LEN+1];
+
+  ns = networkstatus_parse_from_string(s);
+  if (!ns) {
+    log_fn(LOG_WARN, "Couldn't parse network status.");
+    return -1;
+  }
+  if (!router_digest_is_trusted_dir(ns->identity_digest)) {
+    log_fn(LOG_INFO, "Network status was signed, but not by an authoritative directory we recognize.");
+    return -1;
+  }
+  now = time(NULL);
+  if (arrived_at > now)
+    arrived_at = now;
+
+  ns->received_on = arrived_at;
+
+  /*XXXX Check publishing skew. NM*/
+
+  if (!networkstatus_list)
+    networkstatus_list = smartlist_create();
+
+  found = 0;
+  for (i=0; i < smartlist_len(networkstatus_list); ++i) {
+    networkstatus_t *old_ns = smartlist_get(networkstatus_list, i);
+
+    if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
+      if (!memcmp(old_ns->networkstatus_digest,
+                  ns->networkstatus_digest, DIGEST_LEN)) {
+        networkstatus_free(ns);
+        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.");
+        networkstatus_free(ns);
+        return 0;
+      } else {
+        networkstatus_free(old_ns);
+        smartlist_set(networkstatus_list, i, ns);
+        found = 1;
+        break;
+      }
+    }
+  }
+
+  if (!found)
+    smartlist_add(networkstatus_list, ns);
+
+  base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
+
+  if (!is_cached) {
+    const char *datadir = get_options()->DataDirectory;
+    char fp[HEX_DIGEST_LEN+1];
+    size_t len = strlen(datadir)+64;
+    char *fn = tor_malloc(len+1);
+    tor_snprintf(fn, len, "%s/cached-directory/%s",datadir,fp);
+    if (write_str_to_file(fn, s, 0)<0) {
+      log_fn(LOG_NOTICE, "Couldn't write cached network status to \"%s\"", fn);
+    }
+    tor_free(fn);
+  }
+
+  if (get_options()->DirPort)
+    dirserv_set_cached_networkstatus_v2(s, fp, ns->published_on);
+}
+
 /** Ensure that our own routerinfo is at the front, and remove duplicates
  * of our routerinfo.
  */
@@ -1571,7 +1660,8 @@
  * <b>address</b>:<b>port</b>, with identity key <b>digest</b>.  If
  * <b>address</b> is NULL, add ourself. */
 void
-add_trusted_dir_server(const char *address, uint16_t port, const char *digest)
+add_trusted_dir_server(const char *address, uint16_t port, const char *digest,
+                       int supports_v1)
 {
   trusted_dir_server_t *ent;
   uint32_t a;
@@ -1599,6 +1689,7 @@
   ent->addr = a;
   ent->dir_port = port;
   ent->is_running = 1;
+  ent->supports_v1_protocol = supports_v1;
   memcpy(ent->digest, digest, DIGEST_LEN);
   smartlist_add(trusted_dir_servers, ent);
 }

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerparse.c,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -d -r1.125 -r1.126
--- routerparse.c	4 Sep 2005 23:12:27 -0000	1.125
+++ routerparse.c	7 Sep 2005 16:42:53 -0000	1.126
@@ -1282,6 +1282,7 @@
     goto err;
   }
   ns = tor_malloc_zero(sizeof(networkstatus_t));
+  memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
 
   if (!(tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION))) {
     log_fn(LOG_WARN, "Couldn't find network-status-version keyword");