diff options
-rw-r--r-- | src/or/or.h | 13 | ||||
-rw-r--r-- | src/or/routerparse.c | 107 | ||||
-rw-r--r-- | src/or/test.c | 31 |
3 files changed, 150 insertions, 1 deletions
diff --git a/src/or/or.h b/src/or/or.h index 61ed9a5a2..a9f120866 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1383,6 +1383,15 @@ void routerlist_update_from_runningrouters(routerlist_t *list, /********************************* routerparse.c ************************/ +typedef struct tor_version_t { + int major; + int minor; + int micro; + enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2 } status; + int patchlevel; + enum { IS_CVS=0, IS_NOT_CVS=1} cvs; +} tor_version_t; + int router_get_router_hash(const char *s, char *digest); int router_get_dir_hash(const char *s, char *digest); int router_get_runningrouters_hash(const char *s, char *digest); @@ -1399,7 +1408,9 @@ int router_add_exit_policy_from_string(routerinfo_t *router, const char *s); struct exit_policy_t *router_parse_exit_policy_from_string(const char *s); int check_software_version_against_directory(const char *directory, int ignoreversion); - +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_compare_to_mine(const char *s); #endif diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 5b8a18a3a..7e4d7e6ed 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1297,6 +1297,113 @@ static int router_get_hash_impl(const char *s, char *digest, return 0; } +int tor_version_parse(const char *s, tor_version_t *out) +{ + char *eos=NULL, *cp=NULL; + /* Format is: + * NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ -cvs ] ] + */ + tor_assert(s && out); + memset(out, 0, sizeof(tor_version_t)); + + /* Get major. */ + out->major = strtol(s,&eos,10); + if (!eos || eos==s || *eos != '.') return -1; + cp = eos+1; + + /* Get minor */ + out->minor = strtol(cp,&eos,10); + if (!eos || eos==cp || *eos != '.') return -1; + cp = eos+1; + + /* Get micro */ + out->micro = strtol(cp,&eos,10); + if (!eos || eos==cp) return -1; + if (!*eos) { + out->status = VER_RELEASE; + out->patchlevel = 0; + out->cvs = IS_NOT_CVS; + return 0; + } + cp = eos; + + /* Get status */ + if (*cp == '.') { + out->status = VER_RELEASE; + ++cp; + } 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; + } + + /* Get patchlevel */ + out->patchlevel = strtol(cp,&eos,10); + if (!eos || eos==cp) return -1; + cp = eos; + + /* Get cvs status. */ + if (!*eos) { + out->cvs = IS_NOT_CVS; + } else if (0==strcmp(cp, "-cvs")) { + out->cvs = IS_CVS; + } else { + return -1; + } + + return 0; +} + +/** 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 && b); + if ((i = a->major - b->major)) + return i; + else if ((i = a->minor - b->minor)) + return i; + else if ((i = a->micro - b->micro)) + return i; + else if ((i = a->status - b->status)) + return i; + else if ((i = a->patchlevel - b->patchlevel)) + return i; + else if ((i = a->cvs - b->cvs)) + return i; + else + return 0; +} + +static tor_version_t *my_tor_version=NULL; + +/** 1 for unequal, newer or can't tell; 0 for equal, -1 for older. */ +int tor_version_compare_to_mine(const char *s) +{ + tor_version_t v; + + if (!my_tor_version) { + my_tor_version = tor_malloc(sizeof(tor_version_t)); + if (tor_version_parse(VERSION, my_tor_version)) { + log_fn(LOG_ERR, "I couldn't parse my own version ("VERSION")"); + exit(1); + } + } + + if (tor_version_parse(s,&v)) { + log_fn(LOG_WARN, "Unparseable tor version %s", s); + return 1; + } + + return tor_version_compare(my_tor_version, &v); +} + + /* Local Variables: mode:c diff --git a/src/or/test.c b/src/or/test.c index 36b5a8ef8..ef1e89c02 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -661,6 +661,7 @@ test_dir_format() routerinfo_t *rp1 = NULL, *rp2 = NULL; struct exit_policy_t ex1, ex2; routerlist_t *dir1 = NULL, *dir2 = NULL; + tor_version_t ver1, ver2; test_assert( (pk1 = crypto_new_pk_env()) ); test_assert( (pk2 = crypto_new_pk_env()) ); @@ -824,6 +825,36 @@ test_dir_format() test_eq(0, is_recommended_version("a", "ab,abd,abde,abc,abcde")); test_eq(0, is_recommended_version("abb", "ab,abd,abde,abc,abcde")); test_eq(0, is_recommended_version("a", "")); + + /* Try out version parsing functionality */ + test_eq(0, tor_version_parse("0.3.4pre2-cvs", &ver1)); + test_eq(0, ver1.major); + test_eq(3, ver1.minor); + test_eq(4, ver1.micro); + test_eq(VER_PRE, ver1.status); + test_eq(2, ver1.patchlevel); + test_eq(IS_CVS, ver1.cvs); + test_eq(0, tor_version_parse("0.3.4rc1", &ver1)); + test_eq(0, ver1.major); + test_eq(3, ver1.minor); + test_eq(4, ver1.micro); + test_eq(VER_RC, ver1.status); + test_eq(1, ver1.patchlevel); + test_eq(IS_NOT_CVS, ver1.cvs); + test_eq(0, tor_version_parse("1.3.4", &ver1)); + test_eq(1, ver1.major); + test_eq(3, ver1.minor); + test_eq(4, ver1.micro); + test_eq(VER_RELEASE, ver1.status); + test_eq(0, ver1.patchlevel); + test_eq(IS_NOT_CVS, ver1.cvs); + test_eq(0, tor_version_parse("1.3.4.999", &ver1)); + test_eq(1, ver1.major); + test_eq(3, ver1.minor); + test_eq(4, ver1.micro); + test_eq(VER_RELEASE, ver1.status); + test_eq(999, ver1.patchlevel); + test_eq(IS_NOT_CVS, ver1.cvs); } void test_rend_fns() |