Kaynağa Gözat

r15422@catbus: nickm | 2007-09-27 16:42:35 -0400
Use descriptor annotations to record the source, download t time, and purpose of every descriptor we add to the store. The remaining to-do item is to stop setting do_not_cache on bridges.


svn:r11680

Nick Mathewson 17 yıl önce
ebeveyn
işleme
b5c8a8ae53
10 değiştirilmiş dosya ile 153 ekleme ve 45 silme
  1. 3 0
      ChangeLog
  2. 10 6
      doc/TODO
  3. 5 1
      doc/tor.1.in
  4. 10 4
      src/or/control.c
  5. 32 3
      src/or/directory.c
  6. 23 3
      src/or/dirserv.c
  7. 7 1
      src/or/or.h
  8. 29 0
      src/or/router.c
  9. 19 14
      src/or/routerlist.c
  10. 15 13
      src/or/routerparse.c

+ 3 - 0
ChangeLog

@@ -8,6 +8,9 @@ Changes in version 0.2.0.8-alpha - 2007-??-??
       cached-routers.  Initialize cached-descriptors from cached-routers
       cached-routers.  Initialize cached-descriptors from cached-routers
       if the old format is around.  The new format allows us to store
       if the old format is around.  The new format allows us to store
       annotations along with descriptors.
       annotations along with descriptors.
+    - Use annotations to record the time we received each descriptor.
+    - Use annotations to record the source for each descriptor.
+    - Use annotations to record the purpose of each descriptor.
 
 
   o Minor bugfixes (controller):
   o Minor bugfixes (controller):
     - When sending a status event to the controller telling it that an
     - When sending a status event to the controller telling it that an

+ 10 - 6
doc/TODO

@@ -132,7 +132,7 @@ R     - drop 'authority' queries if they're to our own identity key; accept
       o be more robust to bridges being marked as down and leaving us
       o be more robust to bridges being marked as down and leaving us
         stranded without any known "running" bridges.
         stranded without any known "running" bridges.
 N     . Cache for bridge descriptors
 N     . Cache for bridge descriptors
-        . Annotated router store
+        o Annotated router store
           o Accept annotations before routers
           o Accept annotations before routers
           o Preserve and ignore unexpected annotations
           o Preserve and ignore unexpected annotations
           o Mechanism to add annotations when we first add a descriptor
           o Mechanism to add annotations when we first add a descriptor
@@ -141,11 +141,15 @@ N     . Cache for bridge descriptors
           o Name the router store something different: cached-descriptors?
           o Name the router store something different: cached-descriptors?
             o But load from cached-routers if no cached-descriptors is
             o But load from cached-routers if no cached-descriptors is
               found.
               found.
-            - Document this.
+            o Document this.
-        - Use annotations to denote router purpose
+          o Add a few example annotations to make sure this works: source
-          - Learn purpose from annotations
+            and downloaded/uploaded-at seem like a good start
-          - Set annotations based on purpose
+            - Drop this later as needed.
-          - Preserve routers with unrecognized purpose.
+        o Use annotations to denote router purpose
+          o Learn purpose from annotations
+          o Set annotations based on purpose
+          o Preserve routers with unrecognized purpose.
+R       - Stop setting the do-not-cache flag based on purpose.
     - Bridges operators (rudimentary version)
     - Bridges operators (rudimentary version)
       - Ability to act as dir cache without a dir port.
       - Ability to act as dir cache without a dir port.
       o Bridges publish to bridge authorities
       o Bridges publish to bridge authorities

+ 5 - 1
doc/tor.1.in

@@ -1169,8 +1169,12 @@ The tor process stores keys and other data here.
 The most recently downloaded network status document for each authority.  Each file holds one such document; the filenames are the hexadecimal identity key fingerprints of the directory authorities.
 The most recently downloaded network status document for each authority.  Each file holds one such document; the filenames are the hexadecimal identity key fingerprints of the directory authorities.
 .LP
 .LP
 .TP
 .TP
+.B \fIDataDirectory\fB/cached-descriptors\fR and \fBcached-descriptors.new\fR
+These files hold downloaded router statuses.  Some routers may appear more than once; if so, the most recently published descriptor is used.    Lines beginning with @-signs are annotations that contain more information about a given router.  The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-routers file.
+.LP
+.TP
 .B \fIDataDirectory\fB/cached-routers\fR and \fBcached-routers.new\fR
 .B \fIDataDirectory\fB/cached-routers\fR and \fBcached-routers.new\fR
-These files hold downloaded router statuses.  Some routers may appear more than once; if so, the most recently published descriptor is used.  The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-routers file.
+Obsolete versions of cached-descriptors and cached-descriptors.new.  When Tor can't find the newer files, it looks here instead.
 .LP
 .LP
 .TP
 .TP
 .B \fIDataDirectory\fP/state
 .B \fIDataDirectory\fP/state

+ 10 - 4
src/or/control.c

@@ -1884,12 +1884,18 @@ get_purpose(char **string, int for_circuits, uint8_t *purpose)
   if (!strcmpstart(*string, "purpose="))
   if (!strcmpstart(*string, "purpose="))
     *string += strlen("purpose=");
     *string += strlen("purpose=");
 
 
+  if (!for_circuits) {
+    int r = router_purpose_from_string(*string);
+    if (r == ROUTER_PURPOSE_UNKNOWN)
+      return -1;
+    *purpose = r;
+    return 0;
+  }
+
   if (!strcmp(*string, "general"))
   if (!strcmp(*string, "general"))
-    *purpose = for_circuits ? CIRCUIT_PURPOSE_C_GENERAL :
+    *purpose = CIRCUIT_PURPOSE_C_GENERAL;
-                              ROUTER_PURPOSE_GENERAL;
   else if (!strcmp(*string, "controller"))
   else if (!strcmp(*string, "controller"))
-    *purpose = for_circuits ? CIRCUIT_PURPOSE_CONTROLLER :
+    *purpose = CIRCUIT_PURPOSE_CONTROLLER;
-                              ROUTER_PURPOSE_CONTROLLER;
   else { /* not a recognized purpose */
   else { /* not a recognized purpose */
     return -1;
     return -1;
   }
   }

+ 32 - 3
src/or/directory.c

@@ -1066,6 +1066,31 @@ body_is_plausible(const char *body, size_t len, int purpose)
   }
   }
 }
 }
 
 
+/** DOCDOC */
+static void
+load_downloaded_routers(const char *body, smartlist_t *which,
+                        int descriptor_digests,
+                        int router_purpose,
+                        const char *source)
+{
+  char buf[256];
+  char time_buf[ISO_TIME_LEN+1];
+  int general = router_purpose == ROUTER_PURPOSE_GENERAL;
+  format_iso_time(time_buf, time(NULL));
+
+  if (tor_snprintf(buf, sizeof(buf),
+                   "@downloaded-at %s\n"
+                   "@source %s\n"
+                   "%s%s%s", time_buf, escaped(source),
+                   !general ? "@purpose " : "",
+                   !general ? router_purpose_to_string(router_purpose) : "",
+                   !general ? "\n" : "")<0)
+    return;
+
+  router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
+                                  descriptor_digests, buf);
+}
+
 /** We are a client, and we've finished reading the server's
 /** We are a client, and we've finished reading the server's
  * response. Parse and it and act appropriately.
  * response. Parse and it and act appropriately.
  *
  *
@@ -1460,8 +1485,11 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
         router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which,
         router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which,
                                           descriptor_digests);
                                           descriptor_digests);
       } else {
       } else {
-        router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
+        //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
-                               descriptor_digests, conn->router_purpose);
+        //                       descriptor_digests, conn->router_purpose);
+        load_downloaded_routers(body, which, descriptor_digests,
+                                conn->router_purpose,
+                                conn->_base.address);
         directory_info_has_arrived(now, 0);
         directory_info_has_arrived(now, 0);
       }
       }
     }
     }
@@ -2414,7 +2442,8 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
     const char *msg = NULL;
     const char *msg = NULL;
     uint8_t purpose = authdir_mode_bridge(options) ?
     uint8_t purpose = authdir_mode_bridge(options) ?
                       ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
                       ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
-    int r = dirserv_add_multiple_descriptors(body, purpose, &msg);
+    int r = dirserv_add_multiple_descriptors(body, purpose,
+                                             conn->_base.address, &msg);
     tor_assert(msg);
     tor_assert(msg);
     if (r > 0)
     if (r > 0)
       dirserv_get_directory(); /* rebuild and write to disk */
       dirserv_get_directory(); /* rebuild and write to disk */

+ 23 - 3
src/or/dirserv.c

@@ -524,6 +524,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
  * returns the most severe error that occurred for any one of them. */
  * returns the most severe error that occurred for any one of them. */
 int
 int
 dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
 dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
+                                 const char *source,
                                  const char **msg)
                                  const char **msg)
 {
 {
   int r=100; /* higher than any actual return value. */
   int r=100; /* higher than any actual return value. */
@@ -532,12 +533,28 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
   smartlist_t *list;
   smartlist_t *list;
   const char *s;
   const char *s;
   int n_parsed = 0;
   int n_parsed = 0;
+  time_t now = time(NULL);
+  char annotation_buf[256];
+  char time_buf[ISO_TIME_LEN+1];
+  int general = purpose == ROUTER_PURPOSE_GENERAL;
   tor_assert(msg);
   tor_assert(msg);
 
 
+  format_iso_time(time_buf, now);
+  if (tor_snprintf(annotation_buf, sizeof(annotation_buf),
+                   "@uploaded-at %s\n"
+                   "@source %s\n"
+                   "%s%s%s", time_buf, escaped(source),
+                   !general ? "@purpose " : "",
+                   !general ? router_purpose_to_string(purpose) : "",
+                   !general ? "\n" : "")<0) {
+    *msg = "Couldn't format annotations";
+    return -1;
+  }
+
   s = desc;
   s = desc;
   list = smartlist_create();
   list = smartlist_create();
   if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
   if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
-                                     NULL)) {
+                                     annotation_buf)) {
     SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
     SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
         msg_out = NULL;
         msg_out = NULL;
 
 
@@ -548,8 +565,8 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
          * router_load_single_router()? Lastly, does extrainfo_t want
          * router_load_single_router()? Lastly, does extrainfo_t want
          * a purpose field too, or can we just piggyback off the one
          * a purpose field too, or can we just piggyback off the one
          * in routerinfo_t? */
          * in routerinfo_t? */
-        ri->purpose = purpose;
+        tor_assert(ri->purpose == purpose);
-        if (purpose != ROUTER_PURPOSE_GENERAL)
+        if (purpose != ROUTER_PURPOSE_GENERAL) /*XXXXX020 wrong. */
           ri->cache_info.do_not_cache = 1;
           ri->cache_info.do_not_cache = 1;
 
 
         r_tmp = dirserv_add_descriptor(ri, &msg_out);
         r_tmp = dirserv_add_descriptor(ri, &msg_out);
@@ -603,6 +620,9 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
  *  1 if well-formed and accepted but origin should hear *msg;
  *  1 if well-formed and accepted but origin should hear *msg;
  *  0 if well-formed but redundant with one we already have;
  *  0 if well-formed but redundant with one we already have;
  * -1 if it looks vaguely like a router descriptor but rejected;
  * -1 if it looks vaguely like a router descriptor but rejected;
+ *
+ * This function is only called when fresh descriptors are posted, not when
+ * we re-load the cache.
  */
  */
 int
 int
 dirserv_add_descriptor(routerinfo_t *ri, const char **msg)
 dirserv_add_descriptor(routerinfo_t *ri, const char **msg)

+ 7 - 1
src/or/or.h

@@ -1167,6 +1167,8 @@ typedef struct {
 #define ROUTER_PURPOSE_CONTROLLER 1
 #define ROUTER_PURPOSE_CONTROLLER 1
 /** Tor should use this router only for bridge positions in circuits. */
 /** Tor should use this router only for bridge positions in circuits. */
 #define ROUTER_PURPOSE_BRIDGE 2
 #define ROUTER_PURPOSE_BRIDGE 2
+/** DOCDOC */
+#define ROUTER_PURPOSE_UNKNOWN 255
 
 
   uint8_t purpose; /** What positions in a circuit is this router good for? */
   uint8_t purpose; /** What positions in a circuit is this router good for? */
 
 
@@ -2779,6 +2781,7 @@ int dirserv_load_fingerprint_file(void);
 void dirserv_free_fingerprint_list(void);
 void dirserv_free_fingerprint_list(void);
 const char *dirserv_get_nickname_by_digest(const char *digest);
 const char *dirserv_get_nickname_by_digest(const char *digest);
 int dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
 int dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
+                                     const char *source,
                                      const char **msg);
                                      const char **msg);
 int dirserv_add_descriptor(routerinfo_t *ri, const char **msg);
 int dirserv_add_descriptor(routerinfo_t *ri, const char **msg);
 int getinfo_helper_dirserv_unregistered(control_connection_t *conn,
 int getinfo_helper_dirserv_unregistered(control_connection_t *conn,
@@ -3357,6 +3360,9 @@ void router_reset_warnings(void);
 void router_reset_reachability(void);
 void router_reset_reachability(void);
 void router_free_all(void);
 void router_free_all(void);
 
 
+const char *router_purpose_to_string(uint8_t p);
+uint8_t router_purpose_from_string(const char *s);
+
 #ifdef ROUTER_PRIVATE
 #ifdef ROUTER_PRIVATE
 /* Used only by router.c and test.c */
 /* Used only by router.c and test.c */
 void get_platform_str(char *platform, size_t len);
 void get_platform_str(char *platform, size_t len);
@@ -3480,7 +3486,7 @@ void router_load_routers_from_string(const char *s, const char *eos,
                                      saved_location_t saved_location,
                                      saved_location_t saved_location,
                                      smartlist_t *requested_fingerprints,
                                      smartlist_t *requested_fingerprints,
                                      int descriptor_digests,
                                      int descriptor_digests,
-                                     uint8_t purpose);
+                                     const char *prepend_annotations);
 void router_load_extrainfo_from_string(const char *s, const char *eos,
 void router_load_extrainfo_from_string(const char *s, const char *eos,
                                        saved_location_t saved_location,
                                        saved_location_t saved_location,
                                        smartlist_t *requested_fps,
                                        smartlist_t *requested_fps,

+ 29 - 0
src/or/router.c

@@ -1773,6 +1773,35 @@ router_reset_warnings(void)
   }
   }
 }
 }
 
 
+/** DOCDOC */
+const char *
+router_purpose_to_string(uint8_t p)
+{
+  switch (p)
+    {
+    case ROUTER_PURPOSE_GENERAL: return "general";
+    case ROUTER_PURPOSE_BRIDGE: return "bridge";
+    case ROUTER_PURPOSE_CONTROLLER: return "controller";
+    default:
+      tor_assert(0);
+    }
+  return NULL;
+}
+
+/** DOCDOC */
+uint8_t
+router_purpose_from_string(const char *s)
+{
+  if (!strcmp(s, "general"))
+    return ROUTER_PURPOSE_GENERAL;
+  else if (!strcmp(s, "bridge"))
+    return ROUTER_PURPOSE_BRIDGE;
+  else if (!strcmp(s, "controller"))
+    return ROUTER_PURPOSE_CONTROLLER;
+  else
+    return ROUTER_PURPOSE_UNKNOWN;
+}
+
 /** Release all static resources held in router.c */
 /** Release all static resources held in router.c */
 void
 void
 router_free_all(void)
 router_free_all(void)

+ 19 - 14
src/or/routerlist.c

@@ -675,7 +675,7 @@ router_rebuild_store(int force, desc_store_t *store)
         tor_free(sd->signed_descriptor_body); // sets it to null
         tor_free(sd->signed_descriptor_body); // sets it to null
         sd->saved_offset = offset;
         sd->saved_offset = offset;
       }
       }
-      offset += sd->signed_descriptor_len;
+      offset += sd->signed_descriptor_len + sd->annotations_len;
       signed_descriptor_get_body(sd); /* reconstruct and assert */
       signed_descriptor_get_body(sd); /* reconstruct and assert */
     });
     });
 
 
@@ -743,8 +743,7 @@ router_reload_router_list_impl(desc_store_t *store)
     else
     else
       router_load_routers_from_string(store->mmap->data,
       router_load_routers_from_string(store->mmap->data,
                                       store->mmap->data+store->mmap->size,
                                       store->mmap->data+store->mmap->size,
-                                      SAVED_IN_CACHE, NULL, 0,
+                                      SAVED_IN_CACHE, NULL, 0, NULL);
-                                      ROUTER_PURPOSE_GENERAL);
   }
   }
 
 
   tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"%s.new",
   tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"%s.new",
@@ -762,7 +761,7 @@ router_reload_router_list_impl(desc_store_t *store)
                                         NULL, 0);
                                         NULL, 0);
     else
     else
       router_load_routers_from_string(contents, NULL, SAVED_IN_JOURNAL,
       router_load_routers_from_string(contents, NULL, SAVED_IN_JOURNAL,
-                                      NULL, 0, ROUTER_PURPOSE_GENERAL);
+                                      NULL, 0, NULL);
     store->journal_len = (size_t) st.st_size;
     store->journal_len = (size_t) st.st_size;
     tor_free(contents);
     tor_free(contents);
   }
   }
@@ -2010,11 +2009,13 @@ signed_descriptor_get_body_impl(signed_descriptor_t *desc,
       (with_annotations ? 0 : desc->annotations_len);
       (with_annotations ? 0 : desc->annotations_len);
 
 
   tor_assert(r);
   tor_assert(r);
-  if (memcmp("router ", r, 7) && memcmp("extra-info ", r, 11)) {
+  if (!with_annotations) {
-    log_err(LD_DIR, "descriptor at %p begins with unexpected string %s",
+    if (memcmp("router ", r, 7) && memcmp("extra-info ", r, 11)) {
-            desc, tor_strndup(r, 64));
+      log_err(LD_DIR, "descriptor at %p begins with unexpected string %s",
+              desc, tor_strndup(r, 64));
+    }
+    tor_assert(!memcmp("router ", r, 7) || !memcmp("extra-info ", r, 11));
   }
   }
-  tor_assert(!memcmp("router ", r, 7) || !memcmp("extra-info ", r, 11));
 
 
   return r;
   return r;
 }
 }
@@ -3116,15 +3117,20 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg)
   routerinfo_t *ri;
   routerinfo_t *ri;
   int r;
   int r;
   smartlist_t *lst;
   smartlist_t *lst;
+  char annotation_buf[256];
   tor_assert(msg);
   tor_assert(msg);
   *msg = NULL;
   *msg = NULL;
 
 
-  if (!(ri = router_parse_entry_from_string(s, NULL, 1, 0, NULL))) {
+  tor_snprintf(annotation_buf, sizeof(annotation_buf),
+               "@source controller\n"
+               "@purpose %s\n", router_purpose_to_string(purpose));
+
+  if (!(ri = router_parse_entry_from_string(s, NULL, 1, 0, annotation_buf))) {
     log_warn(LD_DIR, "Error parsing router descriptor; dropping.");
     log_warn(LD_DIR, "Error parsing router descriptor; dropping.");
     *msg = "Couldn't parse router descriptor.";
     *msg = "Couldn't parse router descriptor.";
     return -1;
     return -1;
   }
   }
-  ri->purpose = purpose;
+  tor_assert(ri->purpose == purpose);
   if (ri->purpose != ROUTER_PURPOSE_GENERAL)
   if (ri->purpose != ROUTER_PURPOSE_GENERAL)
     ri->cache_info.do_not_cache = 1;
     ri->cache_info.do_not_cache = 1;
   if (router_is_me(ri)) {
   if (router_is_me(ri)) {
@@ -3171,7 +3177,7 @@ router_load_routers_from_string(const char *s, const char *eos,
                                 saved_location_t saved_location,
                                 saved_location_t saved_location,
                                 smartlist_t *requested_fingerprints,
                                 smartlist_t *requested_fingerprints,
                                 int descriptor_digests,
                                 int descriptor_digests,
-                                uint8_t purpose)
+                                const char *prepend_annotations)
 {
 {
   smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
   smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
   char fp[HEX_DIGEST_LEN+1];
   char fp[HEX_DIGEST_LEN+1];
@@ -3180,7 +3186,7 @@ router_load_routers_from_string(const char *s, const char *eos,
   int allow_annotations = (saved_location != SAVED_NOWHERE);
   int allow_annotations = (saved_location != SAVED_NOWHERE);
 
 
   router_parse_list_from_string(&s, eos, routers, saved_location, 0,
   router_parse_list_from_string(&s, eos, routers, saved_location, 0,
-                                allow_annotations, NULL);
+                                allow_annotations, prepend_annotations);
 
 
   routers_update_status_from_networkstatus(routers, !from_cache);
   routers_update_status_from_networkstatus(routers, !from_cache);
 
 
@@ -3208,8 +3214,7 @@ router_load_routers_from_string(const char *s, const char *eos,
       }
       }
     }
     }
 
 
-    ri->purpose = purpose;
+    if (ri->purpose != ROUTER_PURPOSE_GENERAL) /* XXXX020 wrong. */
-    if (purpose != ROUTER_PURPOSE_GENERAL)
       ri->cache_info.do_not_cache = 1;
       ri->cache_info.do_not_cache = 1;
 
 
     if (router_add_to_routerlist(ri, &msg, from_cache, !from_cache) >= 0) {
     if (router_add_to_routerlist(ri, &msg, from_cache, !from_cache) >= 0) {

+ 15 - 13
src/or/routerparse.c

@@ -1015,6 +1015,7 @@ router_parse_entry_from_string(const char *s, const char *end,
   directory_token_t *tok;
   directory_token_t *tok;
   struct in_addr in;
   struct in_addr in;
   const char *start_of_annotations, *cp;
   const char *start_of_annotations, *cp;
+  size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
 
 
   tor_assert(!allow_annotations || !prepend_annotations);
   tor_assert(!allow_annotations || !prepend_annotations);
 
 
@@ -1068,17 +1069,12 @@ router_parse_entry_from_string(const char *s, const char *end,
     goto err;
     goto err;
   }
   }
 
 
-  tok = smartlist_get(tokens,0);
+  tok = find_first_by_keyword(tokens, K_ROUTER);
-  if (tok->tp != K_ROUTER) {
-    log_warn(LD_DIR,"Entry does not start with \"router\"");
-    goto err;
-  }
   tor_assert(tok->n_args >= 5);
   tor_assert(tok->n_args >= 5);
 
 
   router = tor_malloc_zero(sizeof(routerinfo_t));
   router = tor_malloc_zero(sizeof(routerinfo_t));
   router->routerlist_index = -1;
   router->routerlist_index = -1;
-  router->cache_info.annotations_len = s-start_of_annotations +
+  router->cache_info.annotations_len = s-start_of_annotations + prepend_len;
-    (prepend_annotations ? strlen(prepend_annotations) : 0) ;
   router->cache_info.signed_descriptor_len = end-s;
   router->cache_info.signed_descriptor_len = end-s;
   if (cache_copy) {
   if (cache_copy) {
     size_t len = router->cache_info.signed_descriptor_len +
     size_t len = router->cache_info.signed_descriptor_len +
@@ -1086,11 +1082,12 @@ router_parse_entry_from_string(const char *s, const char *end,
     char *cp =
     char *cp =
       router->cache_info.signed_descriptor_body = tor_malloc(len+1);
       router->cache_info.signed_descriptor_body = tor_malloc(len+1);
     if (prepend_annotations) {
     if (prepend_annotations) {
-      strlcpy(cp, prepend_annotations, len+1);
+      memcpy(cp, prepend_annotations, prepend_len);
-      cp += strlen(prepend_annotations);
+      cp += prepend_len;
     }
     }
-    memcpy(cp, s, end-s);
+    memcpy(cp, start_of_annotations, end-start_of_annotations);
-    cp[len] = '\0';
+    router->cache_info.signed_descriptor_body[len] = '\0';
+    tor_assert(strlen(router->cache_info.signed_descriptor_body) == len);
   }
   }
   memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
   memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
 
 
@@ -1116,8 +1113,6 @@ router_parse_entry_from_string(const char *s, const char *end,
   router->bandwidthrate =
   router->bandwidthrate =
     tor_parse_long(tok->args[0],10,0,INT_MAX,NULL,NULL);
     tor_parse_long(tok->args[0],10,0,INT_MAX,NULL,NULL);
 
 
-  /* Set purpose XXXX020 NM NM*/
-
   if (!router->bandwidthrate) {
   if (!router->bandwidthrate) {
     log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.",
     log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.",
              escaped(tok->args[0]));
              escaped(tok->args[0]));
@@ -1129,6 +1124,13 @@ router_parse_entry_from_string(const char *s, const char *end,
     tor_parse_long(tok->args[2],10,0,INT_MAX,NULL,NULL);
     tor_parse_long(tok->args[2],10,0,INT_MAX,NULL,NULL);
   /* XXXX020 we don't error-check these values? -RD */
   /* XXXX020 we don't error-check these values? -RD */
 
 
+  if ((tok = find_first_by_keyword(tokens, A_PURPOSE))) {
+    tor_assert(tok->n_args);
+    router->purpose = router_purpose_from_string(tok->args[0]);
+  } else {
+    router->purpose = ROUTER_PURPOSE_GENERAL;
+  }
+
   if ((tok = find_first_by_keyword(tokens, K_UPTIME))) {
   if ((tok = find_first_by_keyword(tokens, K_UPTIME))) {
     tor_assert(tok->n_args >= 1);
     tor_assert(tok->n_args >= 1);
     router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL);
     router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL);