[or-cvs] Make router/directory parsing nondestructive and more const...

Nick Mathewson nickm at seul.org
Mon Dec 8 23:45:39 UTC 2003


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv8227/src/or

Modified Files:
	dirserv.c or.h router.c routerlist.c test.c 
Log Message:
Make router/directory parsing nondestructive and more const-friendly

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dirserv.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- dirserv.c	5 Dec 2003 09:51:49 -0000	1.18
+++ dirserv.c	8 Dec 2003 23:45:36 -0000	1.19
@@ -202,7 +202,8 @@
   routerinfo_t *ri = NULL;
   int i, r;
   char *start, *end;
-  char *desc_tmp = NULL, *cp;
+  char *desc_tmp = NULL;
+  const char *cp;
   size_t desc_len;
 
   start = strstr(*desc, "router ");
@@ -218,9 +219,7 @@
     end = start+strlen(start);
   }
   desc_len = end-start;
-  cp = desc_tmp = tor_malloc(desc_len+1);
-  strncpy(desc_tmp, start, desc_len);
-  desc_tmp[desc_len]='\0';
+  cp = desc_tmp = tor_strndup(start, desc_len);
 
   /* Check: is the descriptor syntactically valid? */
   ri = router_get_entry_from_string(&cp);

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.199
retrieving revision 1.200
diff -u -d -r1.199 -r1.200
--- or.h	6 Dec 2003 06:01:42 -0000	1.199
+++ or.h	8 Dec 2003 23:45:36 -0000	1.200
@@ -749,11 +749,11 @@
 void routerinfo_free(routerinfo_t *router);
 void router_mark_as_down(char *nickname);
 int router_set_routerlist_from_file(char *routerfile);
-int router_get_dir_hash(char *s, char *digest);
-int router_get_router_hash(char *s, char *digest);
-int router_set_routerlist_from_directory(char *s, crypto_pk_env_t *pkey);
-routerinfo_t *router_get_entry_from_string(char**s);
-int router_add_exit_policy_from_string(routerinfo_t *router, char *s);
+int router_get_dir_hash(const char *s, char *digest);
+int router_get_router_hash(const char *s, char *digest);
+int router_set_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey);
+routerinfo_t *router_get_entry_from_string(const char **s);
+int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
 int router_supports_exit_address(uint32_t addr, uint16_t port,
                                  routerinfo_t *router);
 int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,

Index: router.c
===================================================================
RCS file: /home/or/cvsroot/src/or/router.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- router.c	6 Dec 2003 05:54:04 -0000	1.1
+++ router.c	8 Dec 2003 23:45:36 -0000	1.2
@@ -378,7 +378,8 @@
   int result=0;
   struct exit_policy_t *tmpe;
 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
-  char *s_tmp, *s_dup;
+  char *s_tmp, *s_dup; 
+  const char *cp;
   routerinfo_t *ri_tmp;
 #endif
   
@@ -494,8 +495,8 @@
   s[written+1] = 0;
 
 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
-  s_tmp = s_dup = tor_strdup(s);
-  ri_tmp = router_get_entry_from_string(&s_tmp);
+  cp = s_tmp = s_dup = tor_strdup(s);
+  ri_tmp = router_get_entry_from_string(&cp);
   if (!ri_tmp) {
     log_fn(LOG_ERR, "We just generated a router descriptor we can't parse: <<%s>>", 
            s);

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerlist.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- routerlist.c	6 Dec 2003 06:01:42 -0000	1.2
+++ routerlist.c	8 Dec 2003 23:45:36 -0000	1.3
@@ -21,17 +21,17 @@
 
 /****************************************************************************/
 
-struct directory_token;
-typedef struct directory_token directory_token_t;
+struct directory_token_t;
+typedef struct directory_token_t directory_token_t;
 
 /* static function prototypes */
-static int router_set_routerlist_from_string(char *s);
+static int router_set_routerlist_from_string(const char *s);
 static int
-router_get_list_from_string_impl(char **s, routerlist_t **dest,
+router_get_list_from_string_impl(const char **s, routerlist_t **dest,
                                  int n_good_nicknames,
                                  const char **good_nickname_lst);
 static int
-router_get_routerlist_from_directory_impl(char *s, routerlist_t **dest,
+router_get_routerlist_from_directory_impl(const char *s, routerlist_t **dest,
                                           crypto_pk_env_t *pkey);
 static int router_add_exit_policy(routerinfo_t *router, 
                                   directory_token_t *tok);
@@ -245,30 +245,38 @@
   _SIGNATURE,
   _PUBLIC_KEY,
   _ERR,
-  _EOF
+  _EOF,
+  _NIL
 } directory_keyword;
 
-struct token_table_ent { char *t; int v; };
+typedef enum {
+  NO_ARGS,
+  ARGS,
+  CONCAT_ARGS,
+} arg_syntax;
+ 
+
+struct token_table_ent { char *t; int v; arg_syntax s; };
 
 static struct token_table_ent token_table[] = {
-  { "accept", K_ACCEPT },
-  { "directory-signature", K_DIRECTORY_SIGNATURE },
-  { "reject", K_REJECT },
-  { "router", K_ROUTER },
-  { "recommended-software", K_RECOMMENDED_SOFTWARE },
-  { "signed-directory", K_SIGNED_DIRECTORY },
-  { "signing-key", K_SIGNING_KEY },
-  { "onion-key", K_ONION_KEY },
-  { "link-key", K_LINK_KEY },
-  { "router-signature", K_ROUTER_SIGNATURE },
-  { "published", K_PUBLISHED },
-  { "running-routers", K_RUNNING_ROUTERS },
-  { "platform", K_PLATFORM },
+  { "accept", K_ACCEPT, ARGS },
+  { "directory-signature", K_DIRECTORY_SIGNATURE, NO_ARGS },
+  { "reject", K_REJECT, ARGS },
+  { "router", K_ROUTER, ARGS },
+  { "recommended-software", K_RECOMMENDED_SOFTWARE, ARGS },
+  { "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS },
+  { "signing-key", K_SIGNING_KEY, NO_ARGS },
+  { "onion-key", K_ONION_KEY, NO_ARGS },
+  { "link-key", K_LINK_KEY, NO_ARGS },
+  { "router-signature", K_ROUTER_SIGNATURE, NO_ARGS },
+  { "published", K_PUBLISHED, CONCAT_ARGS },
+  { "running-routers", K_RUNNING_ROUTERS, ARGS },
+  { "platform", K_PLATFORM, ARGS },
   { NULL, -1 }
 };
 
 #define MAX_ARGS 1024
-struct directory_token {
+struct directory_token_t {
   directory_keyword tp;
   union {
     struct {
@@ -287,6 +295,7 @@
 static void
 router_release_token(directory_token_t *tok)
 {
+  int i;
   switch (tok->tp) 
     {
     case _SIGNATURE:
@@ -295,14 +304,21 @@
     case _PUBLIC_KEY:
       crypto_free_pk_env(tok->val.public_key);
       break;
-    default:
+    case _ERR:
+    case _EOF:
+    case _NIL:
       break;
+    default:
+      for (i = 0; i < tok->val.cmd.n_args; ++i) {
+        tor_free(tok->val.cmd.args[i]);
+      }
     }
+  tok->tp = _NIL;
 }
 
 static int
-_router_get_next_token(char **s, directory_token_t *tok) {
-  char *next;
+_router_get_next_token(const char **s, directory_token_t *tok) {
+  const char *next;
   crypto_pk_env_t *pkey = NULL;
   char *signature = NULL;
   int i, done;
@@ -310,6 +326,8 @@
   tok->tp = _ERR;
   tok->val.error = "";
 
+  router_release_token(tok);
+  
   *s = eat_whitespace(*s);
   if (!**s) {
     tok->tp = _EOF;
@@ -368,21 +386,42 @@
     for (i = 0 ; token_table[i].t ; ++i) {
       if (!strncmp(token_table[i].t, *s, next-*s)) {
         tok->tp = token_table[i].v;
-        i = 0;
-        done = (*next == '\n');
-        *s = eat_whitespace_no_nl(next);
-        while (**s != '\n' && i <= MAX_ARGS && !done) {
-          next = find_whitespace(*s);
-          if (*next == '\n')
-            done = 1;
-          *next = 0;
-          tok->val.cmd.args[i++] = *s;
+
+        if (token_table[i].s == ARGS) {
+          i = 0;
+          done = (*next == '\n');
+          *s = eat_whitespace_no_nl(next);
+          while (**s != '\n' && i < MAX_ARGS && !done) {
+            next = find_whitespace(*s);
+            if (*next == '\n')
+              done = 1;
+            tok->val.cmd.args[i++] = tor_strndup(*s,next-*s);
+            *s = eat_whitespace_no_nl(next+1);
+          }
+          tok->val.cmd.n_args = i;
+          if (i >= MAX_ARGS) {
+            /* XXX free args[0..i] */
+            tok->tp = _ERR;
+            tok->val.error = "Too many arguments"; return -1;
+          }
+        } else if (token_table[i].s == CONCAT_ARGS) {
+          *s = eat_whitespace_no_nl(next);
+          next = strchr(*s, '\n');
+          if (!next) {
+            tok->tp = _ERR;
+            tok->val.error = "Unexpected EOF"; return -1;
+          }
+          tok->val.cmd.args[0] = tor_strndup(*s,next-*s);
+          tok->val.cmd.n_args = 1;
           *s = eat_whitespace_no_nl(next+1);
-        };
-        tok->val.cmd.n_args = i;
-        if (i > MAX_ARGS) {
-          tok->tp = _ERR;
-          tok->val.error = "Too many arguments"; return -1;
+        } else {
+          *s = eat_whitespace_no_nl(next);
+          if (**s != '\n') {
+            tok->tp = _ERR;
+            tok->val.error = "Unexpected arguments"; return -1;
+          }
+          tok->val.cmd.n_args = 0;
+          *s = eat_whitespace_no_nl(*s+1);
         }
         return 0;
       }
@@ -444,7 +483,7 @@
 
 /* read routerinfo elements from s, and throw out the ones that
  * don't parse and resolve. */
-static int router_set_routerlist_from_string(char *s)
+static int router_set_routerlist_from_string(const char *s)
 {
   if (router_get_list_from_string_impl(&s, &routerlist, -1, NULL)) {
     log(LOG_WARN, "Error parsing router file");
@@ -457,7 +496,8 @@
   return 0;
 }
 
-static int router_get_hash_impl(char *s, char *digest, const char *start_str,
+static int router_get_hash_impl(const char *s, char *digest, 
+                                const char *start_str,
                                 const char *end_str)
 {
   char *start, *end;
@@ -486,22 +526,22 @@
   return 0;
 }
 
-int router_get_dir_hash(char *s, char *digest)
+int router_get_dir_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
                               "signed-directory","directory-signature");
 }
-int router_get_router_hash(char *s, char *digest)
+int router_get_router_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
                               "router ","router-signature");
 }
 
 /* return 0 if myversion is in start. Else return -1. */
-int compare_recommended_versions(char *myversion, char *start) {
+int compare_recommended_versions(const char *myversion, const char *start) {
   int len_myversion = strlen(myversion);
   char *comma;
-  char *end = start + strlen(start);
+  const char *end = start + strlen(start);
 
   log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, start);
   
@@ -517,7 +557,7 @@
   }
 }
 
-int router_set_routerlist_from_directory(char *s, crypto_pk_env_t *pkey)
+int router_set_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey)
 {
   if (router_get_routerlist_from_directory_impl(s, &routerlist, pkey)) {
     log_fn(LOG_WARN, "Couldn't parse directory.");
@@ -544,18 +584,19 @@
 }
 
 static int
-router_get_routerlist_from_directory_impl(char *s, routerlist_t **dest,
+router_get_routerlist_from_directory_impl(const char *s, routerlist_t **dest,
                                           crypto_pk_env_t *pkey)
 {
   directory_token_t tok;
   char digest[20];
   char signed_digest[128];
   routerlist_t *new_dir = NULL;
-  char *versions;
+  char *versions = NULL;
   struct tm published;
   time_t published_on;
-  const char *good_nickname_lst[1024];
-  int n_good_nicknames;
+  char *good_nickname_lst[1024];
+  int n_good_nicknames = 0;
+  int i;
   
 #define NEXT_TOK()                                                      \
   do {                                                                  \
@@ -570,6 +611,10 @@
       log_fn(LOG_WARN, "Error reading directory: expected %s", name);\
       return -1;                                                        \
     } } while(0)
+#define N_ARGS tok.val.cmd.n_args
+#define ARGS tok.val.cmd.args
+
+  tok.tp = _NIL;
 
   if (router_get_dir_hash(s, digest)) {
     log_fn(LOG_WARN, "Unable to compute digest of directory");
@@ -584,35 +629,34 @@
 
   NEXT_TOK();
   TOK_IS(K_PUBLISHED, "published");
-  if (tok.val.cmd.n_args != 2) {
-    log_fn(LOG_WARN, "Invalid published line");
-    goto err;
-  }
-  tok.val.cmd.args[1][-1] = ' ';
-  if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
+  assert(N_ARGS == 1);
+  if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
     log_fn(LOG_WARN, "Published time was unparseable"); goto err;
   }
   published_on = tor_timegm(&published);  
 
   NEXT_TOK();
   TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
-  if (tok.val.cmd.n_args != 1) {
+  if (N_ARGS != 1) {
     log_fn(LOG_WARN, "Invalid recommended-software line");
     goto err;
   }
-  versions = tor_strdup(tok.val.cmd.args[0]);
-  
+  versions = ARGS[0];
+  tok.val.cmd.n_args = 0; /* Don't let the versions string get freed. */
+
   NEXT_TOK();
   TOK_IS(K_RUNNING_ROUTERS, "running-routers");
-  n_good_nicknames = tok.val.cmd.n_args;
-  memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames*sizeof(char *));
+  n_good_nicknames = N_ARGS;
+  memcpy(good_nickname_lst, ARGS, n_good_nicknames*sizeof(char *));
+  N_ARGS = 0; /* Don't free the strings in good_nickname_lst. */
 
   if (router_get_list_from_string_impl(&s, &new_dir,
-                                       n_good_nicknames, good_nickname_lst)) {
+                                       n_good_nicknames, 
+                                       (const char**)good_nickname_lst)) {
     log_fn(LOG_WARN, "Error reading routers from directory");
     goto err;
   }
-  new_dir->software_versions = versions;
+  new_dir->software_versions = versions; versions = NULL;
   new_dir->published_on = published_on;
 
   NEXT_TOK();
@@ -623,7 +667,6 @@
     if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
         != 20) {
       log_fn(LOG_WARN, "Error reading directory: invalid signature.");
-      free(tok.val.signature);
       goto err;
     }
     log(LOG_DEBUG,"Signed directory hash starts %02x:%02x:%02x:%02x",
@@ -631,11 +674,9 @@
         ((int)signed_digest[2])&0xff,((int)signed_digest[3])&0xff);
     if (memcmp(digest, signed_digest, 20)) {
       log_fn(LOG_WARN, "Error reading directory: signature does not match.");
-      free(tok.val.signature);
       goto err;
     }
   }
-  free(tok.val.signature);
 
   NEXT_TOK();
   TOK_IS(_EOF, "end of directory");
@@ -647,15 +688,25 @@
   return 0;
 
  err:
+  router_release_token(&tok);
   if (new_dir)
     routerlist_free(new_dir);
+  if (versions)
+    tor_free(versions);
+  if (n_good_nicknames) {
+    for (i = 0; i < n_good_nicknames; ++i) {
+      tor_free(good_nickname_lst[i]);
+    }
+  }
   return -1;
 #undef NEXT_TOK
 #undef TOK_IS
+#undef ARGS
+#undef N_ARGS
 }
 
 static int
-router_get_list_from_string_impl(char **s, routerlist_t **dest,
+router_get_list_from_string_impl(const char **s, routerlist_t **dest,
                                  int n_good_nicknames,
                                  const char **good_nickname_lst)
 {
@@ -759,7 +810,7 @@
  * updates s so it points to after the router it just read.
  * mallocs a new router and returns it if all goes well, else returns NULL.
  */
-routerinfo_t *router_get_entry_from_string(char**s) {
+routerinfo_t *router_get_entry_from_string(const char**s) {
   routerinfo_t *router = NULL;
   char signed_digest[128];
   char digest[128];
@@ -775,6 +826,9 @@
     } } while(0)
 
 #define ARGS tok->val.cmd.args
+#define N_ARGS tok->val.cmd.n_args
+
+  _tok.tp = _NIL;
 
   if (router_get_router_hash(*s, digest) < 0) {
     log_fn(LOG_WARN, "Couldn't compute router hash.");
@@ -784,15 +838,14 @@
   NEXT_TOKEN();
 
   if (tok->tp != K_ROUTER) {
-    router_release_token(tok);
     log_fn(LOG_WARN,"Entry does not start with \"router\"");
-    return NULL;
+    goto err;
   }
 
   router = tor_malloc_zero(sizeof(routerinfo_t));
   router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; 
 
-  if (tok->val.cmd.n_args != 6) {
+  if (N_ARGS != 6) {
     log_fn(LOG_WARN,"Wrong # of arguments to \"router\"");
     goto err;
   }
@@ -843,10 +896,7 @@
   if (tok->tp != K_PUBLISHED) {
     log_fn(LOG_WARN, "Missing published time"); goto err;
   }
-  if (tok->val.cmd.n_args != 2) {
-    log_fn(LOG_WARN, "Wrong number of arguments to published"); goto err;
-  }
-  ARGS[1][-1] = ' '; /* Re-insert space. */
+  assert(N_ARGS == 1);
   if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
     log_fn(LOG_WARN, "Published time was unparseable"); goto err;
   }
@@ -912,24 +962,28 @@
   router_release_token(tok); /* free the signature */
   return router;
 
- err:
+err:
   router_release_token(tok); 
   routerinfo_free(router);
   return NULL;
 #undef ARGS
+#undef N_ARGS
 #undef NEXT_TOKEN
 }
 
 int
-router_add_exit_policy_from_string(routerinfo_t *router, char *s)
+router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
 {
   directory_token_t tok;
-  char *tmp, *cp;
+  const char *cp;
+  char *tmp;
   int r;
   int len, idx;
 
+  tok.tp = _NIL;
+
   len = strlen(s);
-  tmp = cp = tor_malloc(len+2);
+  cp = tmp = tor_malloc(len+2);
   for (idx = 0; idx < len; ++idx) {
     tmp[idx] = tolower(s[idx]);
   }

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- test.c	5 Dec 2003 09:51:49 -0000	1.51
+++ test.c	8 Dec 2003 23:45:37 -0000	1.52
@@ -608,7 +608,7 @@
   
   test_assert(router_dump_router_to_string(buf, 2048, &r1, pk2)>0);
   cp = buf;
-  rp1 = router_get_entry_from_string(&cp);
+  rp1 = router_get_entry_from_string((const char**)&cp);
   test_assert(rp1);
   test_streq(rp1->address, r1.address);
   test_eq(rp1->or_port, r1.or_port);



More information about the tor-commits mailing list