[tor-commits] [tor/master] Extract the version-managing code from routerparse.c

nickm at torproject.org nickm at torproject.org
Fri Oct 12 15:39:44 UTC 2018


commit 2f5dc486993b88eb23de7f06043991f08e4d0d73
Author: Nick Mathewson <nickm at torproject.org>
Date:   Sun Sep 30 18:27:23 2018 -0500

    Extract the version-managing code from routerparse.c
    
    Leave the versions.h include in routerparse.h for now; I'll remove
    it later.
---
 src/core/include.am                |   2 +
 src/core/or/versions.c             | 377 +++++++++++++++++++++++++++++++++++++
 src/core/or/versions.h             |  40 ++++
 src/feature/dirparse/routerparse.c | 364 -----------------------------------
 src/feature/dirparse/routerparse.h |  25 +--
 5 files changed, 421 insertions(+), 387 deletions(-)

diff --git a/src/core/include.am b/src/core/include.am
index 45f4cb5c4..c1f63c751 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -46,6 +46,7 @@ LIBTOR_APP_A_SOURCES = 				\
 	src/core/or/scheduler_kist.c		\
 	src/core/or/scheduler_vanilla.c		\
 	src/core/or/status.c			\
+	src/core/or/versions.c			\
 	src/core/proto/proto_cell.c		\
 	src/core/proto/proto_control0.c		\
 	src/core/proto/proto_ext_or.c		\
@@ -241,6 +242,7 @@ noinst_HEADERS +=					\
 	src/core/or/status.h				\
 	src/core/or/tor_version_st.h			\
 	src/core/or/var_cell_st.h			\
+	src/core/or/versions.h				\
 	src/core/proto/proto_cell.h			\
 	src/core/proto/proto_control0.h			\
 	src/core/proto/proto_ext_or.h			\
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
new file mode 100644
index 000000000..2d2486298
--- /dev/null
+++ b/src/core/or/versions.c
@@ -0,0 +1,377 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file versions.c
+ * \brief Code to manipulate, parse, and compare Tor versions.
+ */
+#include "core/or/or.h"
+
+#include "core/or/versions.h"
+#include "lib/crypt_ops/crypto_util.h"
+
+#include "core/or/tor_version_st.h"
+
+/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
+ * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
+ * entries. Else, return VS_OLD if every member of
+ * <b>versionlist</b> is newer than <b>myversion</b>.  Else, return
+ * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
+ * the same series (major.minor.micro) as <b>myversion</b>, but no such member
+ * is newer than <b>myversion.</b>.  Else, return VS_NEW if every member of
+ * <b>versionlist</b> is older than <b>myversion</b>.  Else, return
+ * VS_UNRECOMMENDED.
+ *
+ * (versionlist is a comma-separated list of version strings,
+ * optionally prefixed with "Tor".  Versions that can't be parsed are
+ * ignored.)
+ */
+version_status_t
+tor_version_is_obsolete(const char *myversion, const char *versionlist)
+{
+  tor_version_t mine, other;
+  int found_newer = 0, found_older = 0, found_newer_in_series = 0,
+    found_any_in_series = 0, r, same;
+  version_status_t ret = VS_UNRECOMMENDED;
+  smartlist_t *version_sl;
+
+  log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
+            myversion, versionlist);
+
+  if (tor_version_parse(myversion, &mine)) {
+    log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
+    tor_assert(0);
+  }
+  version_sl = smartlist_new();
+  smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
+
+  if (!strlen(versionlist)) { /* no authorities cared or agreed */
+    ret = VS_EMPTY;
+    goto done;
+  }
+
+  SMARTLIST_FOREACH_BEGIN(version_sl, const char *, cp) {
+    if (!strcmpstart(cp, "Tor "))
+      cp += 4;
+
+    if (tor_version_parse(cp, &other)) {
+      /* Couldn't parse other; it can't be a match. */
+    } else {
+      same = tor_version_same_series(&mine, &other);
+      if (same)
+        found_any_in_series = 1;
+      r = tor_version_compare(&mine, &other);
+      if (r==0) {
+        ret = VS_RECOMMENDED;
+        goto done;
+      } else if (r<0) {
+        found_newer = 1;
+        if (same)
+          found_newer_in_series = 1;
+      } else if (r>0) {
+        found_older = 1;
+      }
+    }
+  } SMARTLIST_FOREACH_END(cp);
+
+  /* We didn't find the listed version. Is it new or old? */
+  if (found_any_in_series && !found_newer_in_series && found_newer) {
+    ret = VS_NEW_IN_SERIES;
+  } else if (found_newer && !found_older) {
+    ret = VS_OLD;
+  } else if (found_older && !found_newer) {
+    ret = VS_NEW;
+  } else {
+    ret = VS_UNRECOMMENDED;
+  }
+
+ done:
+  SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
+  smartlist_free(version_sl);
+  return ret;
+}
+
+/** Extract a Tor version from a <b>platform</b> line from a router
+ * descriptor, and place the result in <b>router_version</b>.
+ *
+ * Return 1 on success, -1 on parsing failure, and 0 if the
+ * platform line does not indicate some version of Tor.
+ *
+ * If <b>strict</b> is non-zero, finding any weird version components
+ * (like negative numbers) counts as a parsing failure.
+ */
+int
+tor_version_parse_platform(const char *platform,
+                           tor_version_t *router_version,
+                           int strict)
+{
+  char tmp[128];
+  char *s, *s2, *start;
+
+  if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; say 0. */
+    return 0;
+
+  start = (char *)eat_whitespace(platform+3);
+  if (!*start) return -1;
+  s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
+  s2 = (char*)eat_whitespace(s);
+  if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
+    s = (char*)find_whitespace(s2);
+
+  if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
+    return -1;
+  strlcpy(tmp, start, s-start+1);
+
+  if (tor_version_parse(tmp, router_version)<0) {
+    log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
+    return -1;
+  }
+
+  if (strict) {
+    if (router_version->major < 0 ||
+        router_version->minor < 0 ||
+        router_version->micro < 0 ||
+        router_version->patchlevel < 0 ||
+        router_version->svn_revision < 0) {
+      return -1;
+    }
+  }
+
+  return 1;
+}
+
+/** Parse the Tor version of the platform string <b>platform</b>,
+ * and compare it to the version in <b>cutoff</b>. Return 1 if
+ * the router is at least as new as the cutoff, else return 0.
+ */
+int
+tor_version_as_new_as(const char *platform, const char *cutoff)
+{
+  tor_version_t cutoff_version, router_version;
+  int r;
+  tor_assert(platform);
+
+  if (tor_version_parse(cutoff, &cutoff_version)<0) {
+    log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
+    return 0;
+  }
+
+  r = tor_version_parse_platform(platform, &router_version, 0);
+  if (r == 0) {
+    /* nonstandard Tor; be safe and say yes */
+    return 1;
+  } else if (r < 0) {
+    /* unparseable version; be safe and say yes. */
+    return 1;
+  }
+
+  /* Here's why we don't need to do any special handling for svn revisions:
+   * - If neither has an svn revision, we're fine.
+   * - If the router doesn't have an svn revision, we can't assume that it
+   *   is "at least" any svn revision, so we need to return 0.
+   * - If the target version doesn't have an svn revision, any svn revision
+   *   (or none at all) is good enough, so return 1.
+   * - If both target and router have an svn revision, we compare them.
+   */
+
+  return tor_version_compare(&router_version, &cutoff_version) >= 0;
+}
+
+/** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
+ * Return 0 on success, -1 on failure. */
+int
+tor_version_parse(const char *s, tor_version_t *out)
+{
+  char *eos=NULL;
+  const char *cp=NULL;
+  int ok = 1;
+  /* Format is:
+   *   "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ]
+   */
+  tor_assert(s);
+  tor_assert(out);
+
+  memset(out, 0, sizeof(tor_version_t));
+  out->status = VER_RELEASE;
+  if (!strcasecmpstart(s, "Tor "))
+    s += 4;
+
+  cp = s;
+
+#define NUMBER(m)                               \
+  do {                                          \
+    if (!cp || *cp < '0' || *cp > '9')          \
+      return -1;                                \
+    out->m = (int)tor_parse_uint64(cp, 10, 0, INT32_MAX, &ok, &eos);    \
+    if (!ok)                                    \
+      return -1;                                \
+    if (!eos || eos == cp)                      \
+      return -1;                                \
+    cp = eos;                                   \
+  } while (0)
+
+#define DOT()                                   \
+  do {                                          \
+    if (*cp != '.')                             \
+      return -1;                                \
+    ++cp;                                       \
+  } while (0)
+
+  NUMBER(major);
+  DOT();
+  NUMBER(minor);
+  if (*cp == 0)
+    return 0;
+  else if (*cp == '-')
+    goto status_tag;
+  DOT();
+  NUMBER(micro);
+
+  /* Get status */
+  if (*cp == 0) {
+    return 0;
+  } else if (*cp == '.') {
+    ++cp;
+  } else if (*cp == '-') {
+    goto status_tag;
+  } else if (0==strncmp(cp, "pre", 3)) {
+    out->status = VER_PRE;
+    cp += 3;
+  } else if (0==strncmp(cp, "rc", 2)) {
+    out->status = VER_RC;
+    cp += 2;
+  } else {
+    return -1;
+  }
+
+  NUMBER(patchlevel);
+
+ status_tag:
+  /* Get status tag. */
+  if (*cp == '-' || *cp == '.')
+    ++cp;
+  eos = (char*) find_whitespace(cp);
+  if (eos-cp >= (int)sizeof(out->status_tag))
+    strlcpy(out->status_tag, cp, sizeof(out->status_tag));
+  else {
+    memcpy(out->status_tag, cp, eos-cp);
+    out->status_tag[eos-cp] = 0;
+  }
+  cp = eat_whitespace(eos);
+
+  if (!strcmpstart(cp, "(r")) {
+    cp += 2;
+    out->svn_revision = (int) strtol(cp,&eos,10);
+  } else if (!strcmpstart(cp, "(git-")) {
+    char *close_paren = strchr(cp, ')');
+    int hexlen;
+    char digest[DIGEST_LEN];
+    if (! close_paren)
+      return -1;
+    cp += 5;
+    if (close_paren-cp > HEX_DIGEST_LEN)
+      return -1;
+    hexlen = (int)(close_paren-cp);
+    memwipe(digest, 0, sizeof(digest));
+    if ( hexlen == 0 || (hexlen % 2) == 1)
+      return -1;
+    if (base16_decode(digest, hexlen/2, cp, hexlen) != hexlen/2)
+      return -1;
+    memcpy(out->git_tag, digest, hexlen/2);
+    out->git_tag_len = hexlen/2;
+  }
+
+  return 0;
+#undef NUMBER
+#undef DOT
+}
+
+/** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
+ * b. */
+int
+tor_version_compare(tor_version_t *a, tor_version_t *b)
+{
+  int i;
+  tor_assert(a);
+  tor_assert(b);
+
+  /* We take this approach to comparison to ensure the same (bogus!) behavior
+   * on all inputs as we would have seen before bug #21278 was fixed. The
+   * only important difference here is that this method doesn't cause
+   * a signed integer underflow.
+   */
+#define CMP(field) do {                               \
+    unsigned aval = (unsigned) a->field;              \
+    unsigned bval = (unsigned) b->field;              \
+    int result = (int) (aval - bval);                 \
+    if (result < 0)                                   \
+      return -1;                                      \
+    else if (result > 0)                              \
+      return 1;                                       \
+  } while (0)
+
+  CMP(major);
+  CMP(minor);
+  CMP(micro);
+  CMP(status);
+  CMP(patchlevel);
+  if ((i = strcmp(a->status_tag, b->status_tag)))
+     return i;
+  CMP(svn_revision);
+  CMP(git_tag_len);
+  if (a->git_tag_len)
+     return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
+  else
+     return 0;
+
+#undef CMP
+}
+
+/** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
+ */
+int
+tor_version_same_series(tor_version_t *a, tor_version_t *b)
+{
+  tor_assert(a);
+  tor_assert(b);
+  return ((a->major == b->major) &&
+          (a->minor == b->minor) &&
+          (a->micro == b->micro));
+}
+
+/** Helper: Given pointers to two strings describing tor versions, return -1
+ * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
+ * Used to sort a list of versions. */
+static int
+compare_tor_version_str_ptr_(const void **_a, const void **_b)
+{
+  const char *a = *_a, *b = *_b;
+  int ca, cb;
+  tor_version_t va, vb;
+  ca = tor_version_parse(a, &va);
+  cb = tor_version_parse(b, &vb);
+  /* If they both parse, compare them. */
+  if (!ca && !cb)
+    return tor_version_compare(&va,&vb);
+  /* If one parses, it comes first. */
+  if (!ca && cb)
+    return -1;
+  if (ca && !cb)
+    return 1;
+  /* If neither parses, compare strings.  Also, the directory server admin
+  ** needs to be smacked upside the head.  But Tor is tolerant and gentle. */
+  return strcmp(a,b);
+}
+
+/** Sort a list of string-representations of versions in ascending order. */
+void
+sort_version_list(smartlist_t *versions, int remove_duplicates)
+{
+  smartlist_sort(versions, compare_tor_version_str_ptr_);
+
+  if (remove_duplicates)
+    smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
+}
diff --git a/src/core/or/versions.h b/src/core/or/versions.h
new file mode 100644
index 000000000..a2353bcae
--- /dev/null
+++ b/src/core/or/versions.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file versions.h
+ * \brief Header file for versions.c.
+ **/
+
+#ifndef TOR_VERSIONS_H
+#define TOR_VERSIONS_H
+
+/** Possible statuses of a version of Tor, given opinions from the directory
+ * servers. */
+typedef enum version_status_t {
+  VS_RECOMMENDED=0, /**< This version is listed as recommended. */
+  VS_OLD=1, /**< This version is older than any recommended version. */
+  VS_NEW=2, /**< This version is newer than any recommended version. */
+  VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
+                       * in its series, but later recommended versions exist.
+                       */
+  VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */
+  VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */
+  VS_UNKNOWN, /**< We have no idea. */
+} version_status_t;
+
+version_status_t tor_version_is_obsolete(const char *myversion,
+                                         const char *versionlist);
+int tor_version_parse_platform(const char *platform,
+                               tor_version_t *version_out,
+                               int strict);
+int tor_version_as_new_as(const char *platform, const char *cutoff);
+int tor_version_parse(const char *s, tor_version_t *out);
+int tor_version_compare(tor_version_t *a, tor_version_t *b);
+int tor_version_same_series(tor_version_t *a, tor_version_t *b);
+void sort_version_list(smartlist_t *lst, int remove_duplicates);
+
+#endif /* !defined(TOR_VERSIONS_H) */
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index 83890cdb9..5ff5fdf23 100644
--- a/src/feature/dirparse/routerparse.c
+++ b/src/feature/dirparse/routerparse.c
@@ -108,9 +108,6 @@
 
 #undef log
 #include <math.h>
-//#ifdef HAVE_SYS_STAT_H
-//#include <sys/stat.h>
-//#endif
 
 /****************************************************************************/
 
@@ -586,85 +583,6 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
   return 0;
 }
 
-/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
- * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
- * entries. Else, return VS_OLD if every member of
- * <b>versionlist</b> is newer than <b>myversion</b>.  Else, return
- * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
- * the same series (major.minor.micro) as <b>myversion</b>, but no such member
- * is newer than <b>myversion.</b>.  Else, return VS_NEW if every member of
- * <b>versionlist</b> is older than <b>myversion</b>.  Else, return
- * VS_UNRECOMMENDED.
- *
- * (versionlist is a comma-separated list of version strings,
- * optionally prefixed with "Tor".  Versions that can't be parsed are
- * ignored.)
- */
-version_status_t
-tor_version_is_obsolete(const char *myversion, const char *versionlist)
-{
-  tor_version_t mine, other;
-  int found_newer = 0, found_older = 0, found_newer_in_series = 0,
-    found_any_in_series = 0, r, same;
-  version_status_t ret = VS_UNRECOMMENDED;
-  smartlist_t *version_sl;
-
-  log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
-            myversion, versionlist);
-
-  if (tor_version_parse(myversion, &mine)) {
-    log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
-    tor_assert(0);
-  }
-  version_sl = smartlist_new();
-  smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
-
-  if (!strlen(versionlist)) { /* no authorities cared or agreed */
-    ret = VS_EMPTY;
-    goto done;
-  }
-
-  SMARTLIST_FOREACH_BEGIN(version_sl, const char *, cp) {
-    if (!strcmpstart(cp, "Tor "))
-      cp += 4;
-
-    if (tor_version_parse(cp, &other)) {
-      /* Couldn't parse other; it can't be a match. */
-    } else {
-      same = tor_version_same_series(&mine, &other);
-      if (same)
-        found_any_in_series = 1;
-      r = tor_version_compare(&mine, &other);
-      if (r==0) {
-        ret = VS_RECOMMENDED;
-        goto done;
-      } else if (r<0) {
-        found_newer = 1;
-        if (same)
-          found_newer_in_series = 1;
-      } else if (r>0) {
-        found_older = 1;
-      }
-    }
-  } SMARTLIST_FOREACH_END(cp);
-
-  /* We didn't find the listed version. Is it new or old? */
-  if (found_any_in_series && !found_newer_in_series && found_newer) {
-    ret = VS_NEW_IN_SERIES;
-  } else if (found_newer && !found_older) {
-    ret = VS_OLD;
-  } else if (found_older && !found_newer) {
-    ret = VS_NEW;
-  } else {
-    ret = VS_UNRECOMMENDED;
-  }
-
- done:
-  SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
-  smartlist_free(version_sl);
-  return ret;
-}
-
 MOCK_IMPL(STATIC int,
 signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
 {
@@ -4276,288 +4194,6 @@ microdescs_parse_from_string(const char *s, const char *eos,
   return result;
 }
 
-/** Extract a Tor version from a <b>platform</b> line from a router
- * descriptor, and place the result in <b>router_version</b>.
- *
- * Return 1 on success, -1 on parsing failure, and 0 if the
- * platform line does not indicate some version of Tor.
- *
- * If <b>strict</b> is non-zero, finding any weird version components
- * (like negative numbers) counts as a parsing failure.
- */
-int
-tor_version_parse_platform(const char *platform,
-                           tor_version_t *router_version,
-                           int strict)
-{
-  char tmp[128];
-  char *s, *s2, *start;
-
-  if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; say 0. */
-    return 0;
-
-  start = (char *)eat_whitespace(platform+3);
-  if (!*start) return -1;
-  s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
-  s2 = (char*)eat_whitespace(s);
-  if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
-    s = (char*)find_whitespace(s2);
-
-  if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
-    return -1;
-  strlcpy(tmp, start, s-start+1);
-
-  if (tor_version_parse(tmp, router_version)<0) {
-    log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
-    return -1;
-  }
-
-  if (strict) {
-    if (router_version->major < 0 ||
-        router_version->minor < 0 ||
-        router_version->micro < 0 ||
-        router_version->patchlevel < 0 ||
-        router_version->svn_revision < 0) {
-      return -1;
-    }
-  }
-
-  return 1;
-}
-
-/** Parse the Tor version of the platform string <b>platform</b>,
- * and compare it to the version in <b>cutoff</b>. Return 1 if
- * the router is at least as new as the cutoff, else return 0.
- */
-int
-tor_version_as_new_as(const char *platform, const char *cutoff)
-{
-  tor_version_t cutoff_version, router_version;
-  int r;
-  tor_assert(platform);
-
-  if (tor_version_parse(cutoff, &cutoff_version)<0) {
-    log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
-    return 0;
-  }
-
-  r = tor_version_parse_platform(platform, &router_version, 0);
-  if (r == 0) {
-    /* nonstandard Tor; be safe and say yes */
-    return 1;
-  } else if (r < 0) {
-    /* unparseable version; be safe and say yes. */
-    return 1;
-  }
-
-  /* Here's why we don't need to do any special handling for svn revisions:
-   * - If neither has an svn revision, we're fine.
-   * - If the router doesn't have an svn revision, we can't assume that it
-   *   is "at least" any svn revision, so we need to return 0.
-   * - If the target version doesn't have an svn revision, any svn revision
-   *   (or none at all) is good enough, so return 1.
-   * - If both target and router have an svn revision, we compare them.
-   */
-
-  return tor_version_compare(&router_version, &cutoff_version) >= 0;
-}
-
-/** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
- * Return 0 on success, -1 on failure. */
-int
-tor_version_parse(const char *s, tor_version_t *out)
-{
-  char *eos=NULL;
-  const char *cp=NULL;
-  int ok = 1;
-  /* Format is:
-   *   "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ]
-   */
-  tor_assert(s);
-  tor_assert(out);
-
-  memset(out, 0, sizeof(tor_version_t));
-  out->status = VER_RELEASE;
-  if (!strcasecmpstart(s, "Tor "))
-    s += 4;
-
-  cp = s;
-
-#define NUMBER(m)                               \
-  do {                                          \
-    if (!cp || *cp < '0' || *cp > '9')          \
-      return -1;                                \
-    out->m = (int)tor_parse_uint64(cp, 10, 0, INT32_MAX, &ok, &eos);    \
-    if (!ok)                                    \
-      return -1;                                \
-    if (!eos || eos == cp)                      \
-      return -1;                                \
-    cp = eos;                                   \
-  } while (0)
-
-#define DOT()                                   \
-  do {                                          \
-    if (*cp != '.')                             \
-      return -1;                                \
-    ++cp;                                       \
-  } while (0)
-
-  NUMBER(major);
-  DOT();
-  NUMBER(minor);
-  if (*cp == 0)
-    return 0;
-  else if (*cp == '-')
-    goto status_tag;
-  DOT();
-  NUMBER(micro);
-
-  /* Get status */
-  if (*cp == 0) {
-    return 0;
-  } else if (*cp == '.') {
-    ++cp;
-  } else if (*cp == '-') {
-    goto status_tag;
-  } else if (0==strncmp(cp, "pre", 3)) {
-    out->status = VER_PRE;
-    cp += 3;
-  } else if (0==strncmp(cp, "rc", 2)) {
-    out->status = VER_RC;
-    cp += 2;
-  } else {
-    return -1;
-  }
-
-  NUMBER(patchlevel);
-
- status_tag:
-  /* Get status tag. */
-  if (*cp == '-' || *cp == '.')
-    ++cp;
-  eos = (char*) find_whitespace(cp);
-  if (eos-cp >= (int)sizeof(out->status_tag))
-    strlcpy(out->status_tag, cp, sizeof(out->status_tag));
-  else {
-    memcpy(out->status_tag, cp, eos-cp);
-    out->status_tag[eos-cp] = 0;
-  }
-  cp = eat_whitespace(eos);
-
-  if (!strcmpstart(cp, "(r")) {
-    cp += 2;
-    out->svn_revision = (int) strtol(cp,&eos,10);
-  } else if (!strcmpstart(cp, "(git-")) {
-    char *close_paren = strchr(cp, ')');
-    int hexlen;
-    char digest[DIGEST_LEN];
-    if (! close_paren)
-      return -1;
-    cp += 5;
-    if (close_paren-cp > HEX_DIGEST_LEN)
-      return -1;
-    hexlen = (int)(close_paren-cp);
-    memwipe(digest, 0, sizeof(digest));
-    if ( hexlen == 0 || (hexlen % 2) == 1)
-      return -1;
-    if (base16_decode(digest, hexlen/2, cp, hexlen) != hexlen/2)
-      return -1;
-    memcpy(out->git_tag, digest, hexlen/2);
-    out->git_tag_len = hexlen/2;
-  }
-
-  return 0;
-#undef NUMBER
-#undef DOT
-}
-
-/** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
- * b. */
-int
-tor_version_compare(tor_version_t *a, tor_version_t *b)
-{
-  int i;
-  tor_assert(a);
-  tor_assert(b);
-
-  /* We take this approach to comparison to ensure the same (bogus!) behavior
-   * on all inputs as we would have seen before bug #21278 was fixed. The
-   * only important difference here is that this method doesn't cause
-   * a signed integer underflow.
-   */
-#define CMP(field) do {                               \
-    unsigned aval = (unsigned) a->field;              \
-    unsigned bval = (unsigned) b->field;              \
-    int result = (int) (aval - bval);                 \
-    if (result < 0)                                   \
-      return -1;                                      \
-    else if (result > 0)                              \
-      return 1;                                       \
-  } while (0)
-
-  CMP(major);
-  CMP(minor);
-  CMP(micro);
-  CMP(status);
-  CMP(patchlevel);
-  if ((i = strcmp(a->status_tag, b->status_tag)))
-     return i;
-  CMP(svn_revision);
-  CMP(git_tag_len);
-  if (a->git_tag_len)
-     return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
-  else
-     return 0;
-
-#undef CMP
-}
-
-/** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
- */
-int
-tor_version_same_series(tor_version_t *a, tor_version_t *b)
-{
-  tor_assert(a);
-  tor_assert(b);
-  return ((a->major == b->major) &&
-          (a->minor == b->minor) &&
-          (a->micro == b->micro));
-}
-
-/** Helper: Given pointers to two strings describing tor versions, return -1
- * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
- * Used to sort a list of versions. */
-static int
-compare_tor_version_str_ptr_(const void **_a, const void **_b)
-{
-  const char *a = *_a, *b = *_b;
-  int ca, cb;
-  tor_version_t va, vb;
-  ca = tor_version_parse(a, &va);
-  cb = tor_version_parse(b, &vb);
-  /* If they both parse, compare them. */
-  if (!ca && !cb)
-    return tor_version_compare(&va,&vb);
-  /* If one parses, it comes first. */
-  if (!ca && cb)
-    return -1;
-  if (ca && !cb)
-    return 1;
-  /* If neither parses, compare strings.  Also, the directory server admin
-  ** needs to be smacked upside the head.  But Tor is tolerant and gentle. */
-  return strcmp(a,b);
-}
-
-/** Sort a list of string-representations of versions in ascending order. */
-void
-sort_version_list(smartlist_t *versions, int remove_duplicates)
-{
-  smartlist_sort(versions, compare_tor_version_str_ptr_);
-
-  if (remove_duplicates)
-    smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
-}
-
 /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
  * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
  * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h
index 51d39c617..6f1af4016 100644
--- a/src/feature/dirparse/routerparse.h
+++ b/src/feature/dirparse/routerparse.h
@@ -12,19 +12,7 @@
 #ifndef TOR_ROUTERPARSE_H
 #define TOR_ROUTERPARSE_H
 
-/** Possible statuses of a version of Tor, given opinions from the directory
- * servers. */
-typedef enum version_status_t {
-  VS_RECOMMENDED=0, /**< This version is listed as recommended. */
-  VS_OLD=1, /**< This version is older than any recommended version. */
-  VS_NEW=2, /**< This version is newer than any recommended version. */
-  VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
-                       * in its series, but later recommended versions exist.
-                       */
-  VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */
-  VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */
-  VS_UNKNOWN, /**< We have no idea. */
-} version_status_t;
+#include "core/or/versions.h"
 
 enum networkstatus_type_t;
 
@@ -65,16 +53,7 @@ extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end,
                              int *can_dl_again_out);
 MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
          (const char *s, int assume_action, int *malformed_list));
-version_status_t tor_version_is_obsolete(const char *myversion,
-                                         const char *versionlist);
-int tor_version_parse_platform(const char *platform,
-                               tor_version_t *version_out,
-                               int strict);
-int tor_version_as_new_as(const char *platform, const char *cutoff);
-int tor_version_parse(const char *s, tor_version_t *out);
-int tor_version_compare(tor_version_t *a, tor_version_t *b);
-int tor_version_same_series(tor_version_t *a, tor_version_t *b);
-void sort_version_list(smartlist_t *lst, int remove_duplicates);
+
 void assert_addr_policy_ok(smartlist_t *t);
 void dump_distinct_digest_count(int severity);
 





More information about the tor-commits mailing list