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

[or-cvs] r17595: {tor} Refactor find_first_by_keyword into one variant that can ret (tor/trunk/src/or)



Author: nickm
Date: 2008-12-11 14:40:58 -0500 (Thu, 11 Dec 2008)
New Revision: 17595

Modified:
   tor/trunk/src/or/routerparse.c
Log:
Refactor find_first_by_keyword into one variant that can return NULL and one that can't.
This makes it easier for us to avoid errors where we we forgot to list a keyword as mandatory, and easier for Coverity to detect cases like this too.

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2008-12-11 19:12:55 UTC (rev 17594)
+++ tor/trunk/src/or/routerparse.c	2008-12-11 19:40:58 UTC (rev 17595)
@@ -449,8 +449,13 @@
                                 char end_char);
 static void token_free(directory_token_t *tok);
 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
-static directory_token_t *find_first_by_keyword(smartlist_t *s,
-                                                directory_keyword keyword);
+static directory_token_t *_find_by_keyword(smartlist_t *s,
+                                           directory_keyword keyword,
+                                           const char *keyword_str);
+#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
+static directory_token_t *find_opt_by_keyword(smartlist_t *s,
+                                              directory_keyword keyword);
+
 #define TS_ANNOTATIONS_OK 1
 #define TS_NOCHECK 2
 #define TS_NO_NEW_ANNOTATIONS 4
@@ -729,8 +734,7 @@
     log_warn(LD_DIR, "Error tokenizing directory"); goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_PUBLISHED);
   tor_assert(tok->n_args == 1);
 
   if (parse_iso_time(tok->args[0], &published_on) < 0) {
@@ -790,13 +794,12 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_PUBLISHED);
   tor_assert(tok->n_args == 1);
   if (parse_iso_time(tok->args[0], &published_on) < 0) {
      goto err;
   }
-  if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
+  if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
     log_warn(LD_DIR, "Missing signature on running-routers");
     goto err;
   }
@@ -1182,7 +1185,7 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_ROUTER);
+  tok = find_by_keyword(tokens, K_ROUTER);
   tor_assert(tok->n_args >= 5);
 
   router = tor_malloc_zero(sizeof(routerinfo_t));
@@ -1238,8 +1241,8 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_BANDWIDTH);
-  tor_assert(tok && tok->n_args >= 3);
+  tok = find_by_keyword(tokens, K_BANDWIDTH);
+  tor_assert(tok->n_args >= 3);
   router->bandwidthrate = (int)
     tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL);
 
@@ -1261,7 +1264,7 @@
     goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, A_PURPOSE))) {
+  if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) {
     tor_assert(tok->n_args != 0);
     router->purpose = router_purpose_from_string(tok->args[0]);
   } else {
@@ -1270,7 +1273,7 @@
   router->cache_info.send_unencrypted =
     (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0;
 
-  if ((tok = find_first_by_keyword(tokens, K_UPTIME))) {
+  if ((tok = find_opt_by_keyword(tokens, K_UPTIME))) {
     tor_assert(tok->n_args >= 1);
     router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL);
     if (!ok) {
@@ -1279,25 +1282,22 @@
     }
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_HIBERNATING))) {
+  if ((tok = find_opt_by_keyword(tokens, K_HIBERNATING))) {
     tor_assert(tok->n_args >= 1);
     router->is_hibernating
       = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
   }
 
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_PUBLISHED);
   tor_assert(tok->n_args == 1);
   if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
     goto err;
 
-  tok = find_first_by_keyword(tokens, K_ONION_KEY);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_ONION_KEY);
   router->onion_pkey = tok->key;
   tok->key = NULL; /* Prevent free */
 
-  tok = find_first_by_keyword(tokens, K_SIGNING_KEY);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_SIGNING_KEY);
   router->identity_pkey = tok->key;
   tok->key = NULL; /* Prevent free */
   if (crypto_pk_get_digest(router->identity_pkey,
@@ -1305,7 +1305,7 @@
     log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_FINGERPRINT))) {
+  if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) {
     /* If there's a fingerprint line, it must match the identity digest. */
     char d[DIGEST_LEN];
     tor_assert(tok->n_args == 1);
@@ -1322,15 +1322,15 @@
     }
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) {
+  if ((tok = find_opt_by_keyword(tokens, K_PLATFORM))) {
     router->platform = tor_strdup(tok->args[0]);
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_CONTACT))) {
+  if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
     router->contact_info = tor_strdup(tok->args[0]);
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_EVENTDNS))) {
+  if ((tok = find_opt_by_keyword(tokens, K_EVENTDNS))) {
     router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0");
   } else if (router->platform) {
     if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha"))
@@ -1349,7 +1349,7 @@
                     });
   policy_expand_private(&router->exit_policy);
 
-  if ((tok = find_first_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
+  if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
     int i;
     router->declared_family = smartlist_create();
     for (i=0;i<tok->n_args;++i) {
@@ -1362,13 +1362,13 @@
     }
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
+  if ((tok = find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
     router->caches_extra_info = 1;
 
-  if ((tok = find_first_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)))
+  if ((tok = find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)))
     router->allow_single_hop_exits = 1;
 
-  if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
+  if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
     tor_assert(tok->n_args >= 1);
     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
       base16_decode(router->cache_info.extra_info_digest,
@@ -1378,12 +1378,11 @@
     }
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) {
+  if ((tok = find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) {
     router->wants_to_be_hs_dir = 1;
   }
 
-  tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
   note_crypto_pk_op(VERIFY_RTR);
 #ifdef COUNT_DISTINCT_DIGESTS
   if (!verified_digests)
@@ -1494,8 +1493,7 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_PUBLISHED);
   if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) {
     log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"",
              escaped(tok->args[0]));
@@ -1508,8 +1506,7 @@
     key = router->identity_pkey;
   }
 
-  tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
   if (strcmp(tok->object_type, "SIGNATURE") ||
       tok->object_size < 128 || tok->object_size > 512) {
     log_warn(LD_DIR, "Bad object type or length on extra-info signature");
@@ -1597,20 +1594,20 @@
   cert = tor_malloc_zero(sizeof(authority_cert_t));
   memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
 
-  tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY);
-  tor_assert(tok && tok->key);
+  tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
+  tor_assert(tok->key);
   cert->signing_key = tok->key;
   tok->key = NULL;
   if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
     goto err;
 
-  tok = find_first_by_keyword(tokens, K_DIR_IDENTITY_KEY);
-  tor_assert(tok && tok->key);
+  tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
+  tor_assert(tok->key);
   cert->identity_key = tok->key;
   tok->key = NULL;
 
-  tok = find_first_by_keyword(tokens, K_FINGERPRINT);
-  tor_assert(tok && tok->n_args);
+  tok = find_by_keyword(tokens, K_FINGERPRINT);
+  tor_assert(tok->n_args > 0);
   if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
                     strlen(tok->args[0]))) {
     log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
@@ -1628,7 +1625,7 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_DIR_ADDRESS);
+  tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
   if (tok) {
     tor_assert(tok->n_args != 0);
     if (parse_addr_port(LOG_WARN, tok->args[0], NULL, &cert->addr,
@@ -1638,13 +1635,11 @@
     }
   }
 
-  tok = find_first_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
   if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
      goto err;
   }
-  tok = find_first_by_keyword(tokens, K_DIR_KEY_EXPIRES);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
   if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
      goto err;
   }
@@ -1763,8 +1758,7 @@
     log_warn(LD_DIR, "Impossibly short router status");
     goto err;
   }
-  tok = find_first_by_keyword(tokens, K_R);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_R);
   tor_assert(tok->n_args >= 8);
   if (vote_rs) {
     rs = &vote_rs->status;
@@ -1810,7 +1804,7 @@
   rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
   rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
 
-  tok = find_first_by_keyword(tokens, K_S);
+  tok = find_opt_by_keyword(tokens, K_S);
   if (tok && vote) {
     int i;
     vote_rs->flags = 0;
@@ -1858,7 +1852,7 @@
       }
     }
   }
-  if ((tok = find_first_by_keyword(tokens, K_V))) {
+  if ((tok = find_opt_by_keyword(tokens, K_V))) {
     tor_assert(tok->n_args == 1);
     rs->version_known = 1;
     if (strcmpstart(tok->args[0], "Tor ")) {
@@ -1881,7 +1875,7 @@
   }
 
   /* handle weighting/bandwidth info */
-  if ((tok = find_first_by_keyword(tokens, K_W))) {
+  if ((tok = find_opt_by_keyword(tokens, K_W))) {
     int i;
     for (i=0; i < tok->n_args; ++i) {
       if (!strcmpstart(tok->args[i], "Bandwidth=")) {
@@ -1898,7 +1892,7 @@
   }
 
   /* parse exit policy summaries */
-  if ((tok = find_first_by_keyword(tokens, K_P))) {
+  if ((tok = find_opt_by_keyword(tokens, K_P))) {
     tor_assert(tok->n_args == 1);
     if (strcmpstart(tok->args[0], "accept ") &&
         strcmpstart(tok->args[0], "reject ")) {
@@ -1985,16 +1979,15 @@
   ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
   memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
 
-  tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
-  tor_assert(tok && tok->n_args >= 1);
+  tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
+  tor_assert(tok->n_args >= 1);
   if (strcmp(tok->args[0], "2")) {
     log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was "
              "%s", escaped(tok->args[0]));
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_DIR_SOURCE);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_DIR_SOURCE);
   tor_assert(tok->n_args >= 3);
   ns->source_address = tor_strdup(tok->args[0]);
   if (tor_inet_aton(tok->args[1], &in) == 0) {
@@ -2010,8 +2003,7 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_FINGERPRINT);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_FINGERPRINT);
   tor_assert(tok->n_args != 0);
   if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
                     strlen(tok->args[0]))) {
@@ -2020,13 +2012,13 @@
     goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_CONTACT))) {
+  if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
     tor_assert(tok->n_args != 0);
     ns->contact = tor_strdup(tok->args[0]);
   }
 
-  tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY);
-  tor_assert(tok && tok->key);
+  tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
+  tor_assert(tok->key);
   ns->signing_key = tok->key;
   tok->key = NULL;
 
@@ -2040,7 +2032,7 @@
     goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) {
+  if ((tok = find_opt_by_keyword(tokens, K_DIR_OPTIONS))) {
     for (i=0; i < tok->n_args; ++i) {
       if (!strcmp(tok->args[i], "Names"))
         ns->binds_names = 1;
@@ -2054,13 +2046,13 @@
   }
 
   if (ns->recommends_versions) {
-    if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) {
+    if (!(tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
       log_warn(LD_DIR, "Missing client-versions on versioning directory");
       goto err;
     }
     ns->client_versions = tor_strdup(tok->args[0]);
 
-    if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) ||
+    if (!(tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS)) ||
         tok->n_args<1) {
       log_warn(LD_DIR, "Missing server-versions on versioning directory");
       goto err;
@@ -2068,8 +2060,7 @@
     ns->server_versions = tor_strdup(tok->args[0]);
   }
 
-  tok = find_first_by_keyword(tokens, K_PUBLISHED);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_PUBLISHED);
   tor_assert(tok->n_args == 1);
   if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
      goto err;
@@ -2174,8 +2165,7 @@
       goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_VOTE_STATUS);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_VOTE_STATUS);
   tor_assert(tok->n_args != 0);
   if (!strcmp(tok->args[0], "vote")) {
     ns->type = NS_TYPE_VOTE;
@@ -2194,12 +2184,12 @@
   }
 
   if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
-    tok = find_first_by_keyword(tokens, K_PUBLISHED);
+    tok = find_by_keyword(tokens, K_PUBLISHED);
     if (parse_iso_time(tok->args[0], &ns->published))
       goto err;
 
     ns->supported_methods = smartlist_create();
-    tok = find_first_by_keyword(tokens, K_CONSENSUS_METHODS);
+    tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
     if (tok) {
       for (i=0; i < tok->n_args; ++i)
         smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
@@ -2207,7 +2197,7 @@
       smartlist_add(ns->supported_methods, tor_strdup("1"));
     }
   } else {
-    tok = find_first_by_keyword(tokens, K_CONSENSUS_METHOD);
+    tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
     if (tok) {
       ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
                                                  &ok, NULL);
@@ -2218,19 +2208,19 @@
     }
   }
 
-  tok = find_first_by_keyword(tokens, K_VALID_AFTER);
+  tok = find_by_keyword(tokens, K_VALID_AFTER);
   if (parse_iso_time(tok->args[0], &ns->valid_after))
     goto err;
 
-  tok = find_first_by_keyword(tokens, K_FRESH_UNTIL);
+  tok = find_by_keyword(tokens, K_FRESH_UNTIL);
   if (parse_iso_time(tok->args[0], &ns->fresh_until))
     goto err;
 
-  tok = find_first_by_keyword(tokens, K_VALID_UNTIL);
+  tok = find_by_keyword(tokens, K_VALID_UNTIL);
   if (parse_iso_time(tok->args[0], &ns->valid_until))
     goto err;
 
-  tok = find_first_by_keyword(tokens, K_VOTING_DELAY);
+  tok = find_by_keyword(tokens, K_VOTING_DELAY);
   tor_assert(tok->n_args >= 2);
   ns->vote_seconds =
     (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
@@ -2257,14 +2247,14 @@
     goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) {
+  if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
     ns->client_versions = tor_strdup(tok->args[0]);
   }
-  if ((tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS))) {
+  if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
     ns->server_versions = tor_strdup(tok->args[0]);
   }
 
-  tok = find_first_by_keyword(tokens, K_KNOWN_FLAGS);
+  tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
   ns->known_flags = smartlist_create();
   inorder = 1;
   for (i = 0; i < tok->n_args; ++i) {
@@ -2357,7 +2347,7 @@
   }
 
   if (ns->type != NS_TYPE_CONSENSUS &&
-      (tok = find_first_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
+      (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
     int bad = 1;
     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
       networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
@@ -2551,8 +2541,7 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_CONSENSUS_DIGEST);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, K_CONSENSUS_DIGEST);
   if (strlen(tok->args[0]) != HEX_DIGEST_LEN) {
     log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
              "networkstatus signatures");
@@ -2565,19 +2554,19 @@
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_VALID_AFTER);
+  tok = find_by_keyword(tokens, K_VALID_AFTER);
   if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
     log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_FRESH_UNTIL);
+  tok = find_by_keyword(tokens, K_FRESH_UNTIL);
   if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
     log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
     goto err;
   }
 
-  tok = find_first_by_keyword(tokens, K_VALID_UNTIL);
+  tok = find_by_keyword(tokens, K_VALID_UNTIL);
   if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
     log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
     goto err;
@@ -3165,12 +3154,28 @@
  * NULL if no such keyword is found.
  */
 static directory_token_t *
-find_first_by_keyword(smartlist_t *s, directory_keyword keyword)
+find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
 {
   SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
   return NULL;
 }
 
+/** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; fail
+ * with an assert if no such keyword is found.
+ */
+static directory_token_t *
+_find_by_keyword(smartlist_t *s, directory_keyword keyword,
+                 const char *keyword_as_string)
+{
+  directory_token_t *tok = find_opt_by_keyword(s, keyword);
+  if (PREDICT_UNLIKELY(!tok)) {
+    log_err(LD_BUG, "Missing %s [%d] in directory object that should have "
+         "been validated. Internal error.", keyword_as_string, (int)keyword);
+    tor_assert(tok);
+  }
+  return tok;
+}
+
 /** Return a newly allocated smartlist of all accept or reject tokens in
  * <b>s</b>.
  */
@@ -3497,8 +3502,7 @@
     goto err;
   }
   /* Parse base32-encoded descriptor ID. */
-  tok = find_first_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
   tor_assert(tok == smartlist_get(tokens, 0));
   tor_assert(tok->n_args == 1);
   if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 ||
@@ -3513,8 +3517,7 @@
     goto err;
   }
   /* Parse descriptor version. */
-  tok = find_first_by_keyword(tokens, R_VERSION);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_VERSION);
   tor_assert(tok->n_args == 1);
   result->version =
     (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
@@ -3528,13 +3531,11 @@
     goto err;
   }
   /* Parse public key. */
-  tok = find_first_by_keyword(tokens, R_PERMANENT_KEY);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_PERMANENT_KEY);
   result->pk = tok->key;
   tok->key = NULL; /* Prevent free */
   /* Parse secret ID part. */
-  tok = find_first_by_keyword(tokens, R_SECRET_ID_PART);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_SECRET_ID_PART);
   tor_assert(tok->n_args == 1);
   if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
       strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
@@ -3548,16 +3549,14 @@
   }
   /* Parse publication time -- up-to-date check is done when storing the
    * descriptor. */
-  tok = find_first_by_keyword(tokens, R_PUBLICATION_TIME);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
   tor_assert(tok->n_args == 1);
   if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
     log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
     goto err;
   }
   /* Parse protocol versions. */
-  tok = find_first_by_keyword(tokens, R_PROTOCOL_VERSIONS);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
   tor_assert(tok->n_args == 1);
   versions = smartlist_create();
   smartlist_split_string(versions, tok->args[0], ",",
@@ -3572,7 +3571,7 @@
   SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
   smartlist_free(versions);
   /* Parse encrypted introduction points. Don't verify. */
-  tok = find_first_by_keyword(tokens, R_INTRODUCTION_POINTS);
+  tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
   if (tok) {
     if (strcmp(tok->object_type, "MESSAGE")) {
       log_warn(LD_DIR, "Bad object type: introduction points should be of "
@@ -3587,8 +3586,7 @@
     *intro_points_encrypted_size_out = 0;
   }
   /* Parse and verify signature. */
-  tok = find_first_by_keyword(tokens, R_SIGNATURE);
-  tor_assert(tok);
+  tok = find_by_keyword(tokens, R_SIGNATURE);
   note_crypto_pk_op(VERIFY_RTR);
   if (check_signature_token(desc_hash, tok, result->pk, 0,
                             "v2 rendezvous service descriptor") < 0)
@@ -3786,8 +3784,7 @@
     intro = tor_malloc_zero(sizeof(rend_intro_point_t));
     info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
     /* Parse identifier. */
-    tok = find_first_by_keyword(tokens, R_IPO_IDENTIFIER);
-    tor_assert(tok);
+    tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
     if (base32_decode(info->identity_digest, DIGEST_LEN,
                       tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
       log_warn(LD_REND, "Identity digest contains illegal characters: %s",
@@ -3800,7 +3797,7 @@
     base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
                   info->identity_digest, DIGEST_LEN);
     /* Parse IP address. */
-    tok = find_first_by_keyword(tokens, R_IPO_IP_ADDRESS);
+    tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
     if (tor_addr_from_str(&info->addr, tok->args[0])<0) {
       log_warn(LD_REND, "Could not parse introduction point address.");
       rend_intro_point_free(intro);
@@ -3813,7 +3810,7 @@
     }
 
     /* Parse onion port. */
-    tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT);
+    tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
     info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
                                            &num_ok,NULL);
     if (!info->port || !num_ok) {
@@ -3823,11 +3820,11 @@
       goto err;
     }
     /* Parse onion key. */
-    tok = find_first_by_keyword(tokens, R_IPO_ONION_KEY);
+    tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
     info->onion_key = tok->key;
     tok->key = NULL; /* Prevent free */
     /* Parse service key. */
-    tok = find_first_by_keyword(tokens, R_IPO_SERVICE_KEY);
+    tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
     intro->intro_key = tok->key;
     tok->key = NULL; /* Prevent free */
     /* Add extend info to list of introduction points. */
@@ -3897,8 +3894,7 @@
       goto err;
     }
     /* Parse client name. */
-    tok = find_first_by_keyword(tokens, C_CLIENT_NAME);
-    tor_assert(tok);
+    tok = find_by_keyword(tokens, C_CLIENT_NAME);
     tor_assert(tok == smartlist_get(tokens, 0));
     tor_assert(tok->n_args == 1);
 
@@ -3920,15 +3916,14 @@
     parsed_entry->client_name = tor_strdup(tok->args[0]);
     strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
     /* Parse client key. */
-    tok = find_first_by_keyword(tokens, C_CLIENT_KEY);
+    tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
     if (tok) {
       parsed_entry->client_key = tok->key;
       tok->key = NULL; /* Prevent free */
     }
 
     /* Parse descriptor cookie. */
-    tok = find_first_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
-    tor_assert(tok);
+    tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
     tor_assert(tok->n_args == 1);
     if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
       log_warn(LD_REND, "Descriptor cookie has illegal length: %s",