diff options
-rw-r--r-- | changes/bug16389 | 12 | ||||
-rw-r--r-- | changes/bug16539 | 4 | ||||
-rw-r--r-- | changes/decouple_dir_all_unreachable | 4 | ||||
-rw-r--r-- | changes/move_formatting_functions | 3 | ||||
-rw-r--r-- | src/common/container.c | 6 | ||||
-rw-r--r-- | src/common/container.h | 6 | ||||
-rw-r--r-- | src/or/dirvote.c | 2 | ||||
-rw-r--r-- | src/or/main.c | 44 | ||||
-rw-r--r-- | src/or/routerlist.c | 2 | ||||
-rw-r--r-- | src/test/test_containers.c | 153 |
10 files changed, 218 insertions, 18 deletions
diff --git a/changes/bug16389 b/changes/bug16389 new file mode 100644 index 0000000000..b7eb35034a --- /dev/null +++ b/changes/bug16389 @@ -0,0 +1,12 @@ + o Hidden Service Enhancement + Client now uses an introduction point failure cache to know when to + fetch or keep a descriptor in their cache. + + When fetching a descriptor, for every introduction points in it, we look + them up in the failure cache to know if we keep the descriptor or not. + For this to work, everytime an introduction points is discarded (ex: + receiving a NACK), we note it down in our introduction cache. If all + introduction points for an onion service are in our failure cache, we + discard the descriptor and fetch a new one. + + See rendcache.c for a detailed explanation of the cache's behavior. diff --git a/changes/bug16539 b/changes/bug16539 new file mode 100644 index 0000000000..8a0b6d251c --- /dev/null +++ b/changes/bug16539 @@ -0,0 +1,4 @@ + o Minor bugfixes (Ed25519): + - Fix a memory leak when reading router descriptors with + expired Ed25519 certificate. Fixes bug 16539; bugfix on 0.2.7.2-alpha. + diff --git a/changes/decouple_dir_all_unreachable b/changes/decouple_dir_all_unreachable new file mode 100644 index 0000000000..1e57b3dfbd --- /dev/null +++ b/changes/decouple_dir_all_unreachable @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Simply the control graph further by deferring the inner body of + directory_all_unreachable() into a callback. Closes ticket + 16762.
\ No newline at end of file diff --git a/changes/move_formatting_functions b/changes/move_formatting_functions new file mode 100644 index 0000000000..4ad5806f23 --- /dev/null +++ b/changes/move_formatting_functions @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Move some format-parsing functions out of crypto.c and + crypto_curve25519.c into crypto_format.c and/or util_format.c. diff --git a/src/common/container.c b/src/common/container.c index 082afb51ee..636dfb6c57 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -742,7 +742,7 @@ smartlist_sort_strings(smartlist_t *sl) } /** Return the most frequent string in the sorted list <b>sl</b> */ -char * +const char * smartlist_get_most_frequent_string(smartlist_t *sl) { return smartlist_get_most_frequent(sl, compare_string_ptrs_); @@ -752,7 +752,7 @@ smartlist_get_most_frequent_string(smartlist_t *sl) * If <b>count_out</b> is provided, set <b>count_out</b> to the * number of times that string appears. */ -char * +const char * smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) { return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); @@ -1020,7 +1020,7 @@ smartlist_sort_digests256(smartlist_t *sl) /** Return the most frequent member of the sorted list of DIGEST256_LEN * digests in <b>sl</b> */ -char * +const uint8_t * smartlist_get_most_frequent_digest256(smartlist_t *sl) { return smartlist_get_most_frequent(sl, compare_digests256_); diff --git a/src/common/container.h b/src/common/container.h index 2a6ba01e62..5abd8b48d9 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -109,9 +109,9 @@ void smartlist_sort_digests(smartlist_t *sl); void smartlist_sort_digests256(smartlist_t *sl); void smartlist_sort_pointers(smartlist_t *sl); -char *smartlist_get_most_frequent_string(smartlist_t *sl); -char *smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out); -char *smartlist_get_most_frequent_digest256(smartlist_t *sl); +const char *smartlist_get_most_frequent_string(smartlist_t *sl); +const char *smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out); +const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); void smartlist_uniq_strings(smartlist_t *sl); void smartlist_uniq_digests(smartlist_t *sl); diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 0f3b77fe28..d8e6ee2229 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -478,7 +478,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, if (microdesc_digest256_out) { smartlist_t *digests = smartlist_new(); - const char *best_microdesc_digest; + const uint8_t *best_microdesc_digest; SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { char d[DIGEST256_LEN]; if (compare_vote_rs(rs, most)) diff --git a/src/or/main.c b/src/or/main.c index c6dcd2ae95..092014f7fa 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -982,19 +982,18 @@ conn_close_if_marked(int i) return 1; } -/** We've just tried every dirserver we know about, and none of - * them were reachable. Assume the network is down. Change state - * so next time an application connection arrives we'll delay it - * and try another directory fetch. Kill off all the circuit_wait - * streams that are waiting now, since they will all timeout anyway. +/** Implementation for directory_all_unreachable. This is done in a callback, + * since otherwise it would complicate Tor's control-flow graph beyond all + * reason. */ -void -directory_all_unreachable(time_t now) +static void +directory_all_unreachable_cb(evutil_socket_t fd, short event, void *arg) { - connection_t *conn; - (void)now; + (void)fd; + (void)event; + (void)arg; - stats_n_seconds_working=0; /* reset it */ + connection_t *conn; while ((conn = connection_get_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_CIRCUIT_WAIT))) { @@ -1010,6 +1009,31 @@ directory_all_unreachable(time_t now) control_event_general_status(LOG_ERR, "DIR_ALL_UNREACHABLE"); } +static struct event *directory_all_unreachable_cb_event = NULL; + +/** We've just tried every dirserver we know about, and none of + * them were reachable. Assume the network is down. Change state + * so next time an application connection arrives we'll delay it + * and try another directory fetch. Kill off all the circuit_wait + * streams that are waiting now, since they will all timeout anyway. + */ +void +directory_all_unreachable(time_t now) +{ + (void)now; + + stats_n_seconds_working=0; /* reset it */ + + if (!directory_all_unreachable_cb_event) { + directory_all_unreachable_cb_event = + tor_event_new(tor_libevent_get_base(), + -1, EV_READ, directory_all_unreachable_cb, NULL); + tor_assert(directory_all_unreachable_cb_event); + } + + event_active(directory_all_unreachable_cb_event, EV_READ, 1); +} + /** This function is called whenever we successfully pull down some new * network statuses or server descriptors. */ void diff --git a/src/or/routerlist.c b/src/or/routerlist.c index dc48862201..aebbd480d2 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -3295,6 +3295,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, /* Make sure that it isn't expired. */ if (router->cert_expiration_time < approx_time()) { + routerinfo_free(router); + *msg = "Some certs on this router are expired."; return ROUTER_CERTS_EXPIRED; } diff --git a/src/test/test_containers.c b/src/test/test_containers.c index 2ae81bf18d..eb98cc80b4 100644 --- a/src/test/test_containers.c +++ b/src/test/test_containers.c @@ -887,7 +887,7 @@ static void test_container_order_functions(void *arg) { int lst[25], n = 0; - unsigned int lst_2[25]; + uint32_t lst_2[25]; // int a=12,b=24,c=25,d=60,e=77; #define median() median_int(lst, n) @@ -933,6 +933,31 @@ test_container_order_functions(void *arg) #undef third_quartile + double dbls[] = { 1.0, 10.0, 100.0, 1e4, 1e5, 1e6 }; + tt_assert(1.0 == median_double(dbls, 1)); + tt_assert(1.0 == median_double(dbls, 2)); + tt_assert(10.0 == median_double(dbls, 3)); + tt_assert(10.0 == median_double(dbls, 4)); + tt_assert(100.0 == median_double(dbls, 5)); + tt_assert(100.0 == median_double(dbls, 6)); + + time_t times[] = { 5, 10, 20, 25, 15 }; + + tt_assert(5 == median_time(times, 1)); + tt_assert(5 == median_time(times, 2)); + tt_assert(10 == median_time(times, 3)); + tt_assert(10 == median_time(times, 4)); + tt_assert(15 == median_time(times, 5)); + + int32_t int32s[] = { -5, -10, -50, 100 }; + tt_int_op(-5, ==, median_int32(int32s, 1)); + tt_int_op(-10, ==, median_int32(int32s, 2)); + tt_int_op(-10, ==, median_int32(int32s, 3)); + tt_int_op(-10, ==, median_int32(int32s, 4)); + + long longs[] = { -30, 30, 100, -100, 7 }; + tt_int_op(7, ==, find_nth_long(longs, 5, 2)); + done: ; } @@ -1078,6 +1103,129 @@ test_container_fp_pair_map(void *arg) tor_free(v105); } +static void +test_container_smartlist_most_frequent(void *arg) +{ + (void) arg; + smartlist_t *sl = smartlist_new(); + + int count = -1; + const char *cp; + + cp = smartlist_get_most_frequent_string_(sl, &count); + tt_int_op(count, ==, 0); + tt_ptr_op(cp, ==, NULL); + + /* String must be sorted before we call get_most_frequent */ + smartlist_split_string(sl, "abc:def:ghi", ":", 0, 0); + + cp = smartlist_get_most_frequent_string_(sl, &count); + tt_int_op(count, ==, 1); + tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */ + + smartlist_split_string(sl, "def:ghi", ":", 0, 0); + smartlist_sort_strings(sl); + + cp = smartlist_get_most_frequent_string_(sl, &count); + tt_int_op(count, ==, 2); + tt_ptr_op(cp, !=, NULL); + tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */ + + smartlist_split_string(sl, "def:abc:qwop", ":", 0, 0); + smartlist_sort_strings(sl); + + cp = smartlist_get_most_frequent_string_(sl, &count); + tt_int_op(count, ==, 3); + tt_ptr_op(cp, !=, NULL); + tt_str_op(cp, ==, "def"); /* No tie */ + + done: + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + smartlist_free(sl); +} + +static void +test_container_smartlist_sort_ptrs(void *arg) +{ + (void)arg; + int array[10]; + int *arrayptrs[11]; + smartlist_t *sl = smartlist_new(); + unsigned i=0, j; + + for (j = 0; j < ARRAY_LENGTH(array); ++j) { + smartlist_add(sl, &array[j]); + arrayptrs[i++] = &array[j]; + if (j == 5) { + smartlist_add(sl, &array[j]); + arrayptrs[i++] = &array[j]; + } + } + + for (i = 0; i < 10; ++i) { + smartlist_shuffle(sl); + smartlist_sort_pointers(sl); + for (j = 0; j < ARRAY_LENGTH(arrayptrs); ++j) { + tt_ptr_op(smartlist_get(sl, j), ==, arrayptrs[j]); + } + } + + done: + smartlist_free(sl); +} + +static void +test_container_smartlist_strings_eq(void *arg) +{ + (void)arg; + smartlist_t *sl1 = smartlist_new(); + smartlist_t *sl2 = smartlist_new(); +#define EQ_SHOULD_SAY(s1,s2,val) \ + do { \ + SMARTLIST_FOREACH(sl1, char *, cp, tor_free(cp)); \ + SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); \ + smartlist_clear(sl1); \ + smartlist_clear(sl2); \ + smartlist_split_string(sl1, (s1), ":", 0, 0); \ + smartlist_split_string(sl2, (s2), ":", 0, 0); \ + tt_int_op((val), OP_EQ, smartlist_strings_eq(sl1, sl2)); \ + } while (0) + + /* Both NULL, so equal */ + tt_int_op(1, ==, smartlist_strings_eq(NULL, NULL)); + + /* One NULL, not equal. */ + tt_int_op(0, ==, smartlist_strings_eq(NULL, sl1)); + tt_int_op(0, ==, smartlist_strings_eq(sl1, NULL)); + + /* Both empty, both equal. */ + EQ_SHOULD_SAY("", "", 1); + + /* One empty, not equal */ + EQ_SHOULD_SAY("", "ab", 0); + EQ_SHOULD_SAY("", "xy:z", 0); + EQ_SHOULD_SAY("abc", "", 0); + EQ_SHOULD_SAY("abc:cd", "", 0); + + /* Different lengths, not equal. */ + EQ_SHOULD_SAY("hello:world", "hello", 0); + EQ_SHOULD_SAY("hello", "hello:friends", 0); + + /* Same lengths, not equal */ + EQ_SHOULD_SAY("Hello:world", "goodbye:world", 0); + EQ_SHOULD_SAY("Hello:world", "Hello:stars", 0); + + /* Actually equal */ + EQ_SHOULD_SAY("ABC", "ABC", 1); + EQ_SHOULD_SAY(" ab : cd : e", " ab : cd : e", 1); + + done: + SMARTLIST_FOREACH(sl1, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); + smartlist_free(sl1); + smartlist_free(sl2); +} + #define CONTAINER_LEGACY(name) \ { #name, test_container_ ## name , 0, NULL, NULL } @@ -1099,6 +1247,9 @@ struct testcase_t container_tests[] = { CONTAINER_LEGACY(order_functions), CONTAINER(di_map, 0), CONTAINER_LEGACY(fp_pair_map), + CONTAINER(smartlist_most_frequent, 0), + CONTAINER(smartlist_sort_ptrs, 0), + CONTAINER(smartlist_strings_eq, 0), END_OF_TESTCASES }; |