diff options
Diffstat (limited to 'src/test')
53 files changed, 2195 insertions, 1476 deletions
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake index 605f1a92c3..cfbe281b94 100644 --- a/src/test/Makefile.nmake +++ b/src/test/Makefile.nmake @@ -18,6 +18,7 @@ TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \ test_config.obj test_connection.obj \ test_cell_formats.obj test_relay.obj test_replay.obj \ test_channelpadding.obj \ + test_circuitstats.obj \ test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj tinytest.obj: ..\ext\tinytest.c diff --git a/src/test/bench.c b/src/test/bench.c index b7b123eee2..f30b609900 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -3,11 +3,6 @@ * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -extern const char tor_git_revision[]; -/* Ordinarily defined in tor_main.c; this bit is just here to provide one - * since we're not linking to tor_main.c */ -const char tor_git_revision[] = ""; - /** * \file bench.c * \brief Benchmarks for lower level Tor modules. diff --git a/src/test/fakechans.h b/src/test/fakechans.h index c0de430e3d..ab5d8461b6 100644 --- a/src/test/fakechans.h +++ b/src/test/fakechans.h @@ -20,7 +20,6 @@ void scheduler_release_channel_mock(channel_t *ch); /* Query some counters used by the exposed mocks */ int get_mock_scheduler_has_waiting_cells_count(void); -int get_mock_scheduler_release_channel_count(void); #endif /* !defined(TOR_FAKECHANS_H) */ diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index 1e98eb6c85..1d54e41dbd 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -9,9 +9,6 @@ #include "crypto.h" #include "crypto_ed25519.h" -extern const char tor_git_revision[]; -const char tor_git_revision[] = ""; - static or_options_t *mock_options = NULL; static const or_options_t * mock_get_options(void) diff --git a/src/test/include.am b/src/test/include.am index 610918e9da..a4b9705fdd 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -98,6 +98,7 @@ src_test_test_SOURCES = \ src/test/test_circuitmux.c \ src/test/test_circuitbuild.c \ src/test/test_circuituse.c \ + src/test/test_circuitstats.c \ src/test/test_compat_libevent.c \ src/test/test_config.c \ src/test/test_connection.c \ @@ -125,6 +126,7 @@ src_test_test_SOURCES = \ src/test/test_hs_service.c \ src/test/test_hs_client.c \ src/test/test_hs_intropoint.c \ + src/test/test_hs_control.c \ src/test/test_handles.c \ src/test/test_hs_cache.c \ src/test/test_hs_descriptor.c \ @@ -152,7 +154,6 @@ src_test_test_SOURCES = \ src/test/test_routerkeys.c \ src/test/test_routerlist.c \ src/test/test_routerset.c \ - src/test/test_rust.c \ src/test/test_scheduler.c \ src/test/test_shared_random.c \ src/test/test_socks.c \ diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index 484f13dd05..89d946d506 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #include "orconfig.h" #include <string.h> #include <stdio.h> diff --git a/src/test/test-timers.c b/src/test/test-timers.c index 99715f4333..a0b5b535c2 100644 --- a/src/test/test-timers.c +++ b/src/test/test-timers.c @@ -133,7 +133,7 @@ main(int argc, char **argv) ret = 0; } - timer_free(NULL); + timer_free_(NULL); for (i = 0; i < N_TIMERS; ++i) { timer_free(timers[i]); diff --git a/src/test/test.c b/src/test/test.c index da4f7a0553..f225fd277d 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -345,8 +345,8 @@ test_onion_queues(void *arg) tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); done: - circuit_free(TO_CIRCUIT(circ1)); - circuit_free(TO_CIRCUIT(circ2)); + circuit_free_(TO_CIRCUIT(circ1)); + circuit_free_(TO_CIRCUIT(circ2)); tor_free(create1); tor_free(create2); tor_free(onionskin); @@ -616,7 +616,7 @@ test_rend_fns(void *arg) done: if (descs) { for (i = 0; i < smartlist_len(descs); i++) - rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i)); + rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i)); smartlist_free(descs); } if (parsed) @@ -1178,6 +1178,7 @@ struct testgroup_t testgroups[] = { { "circuitlist/", circuitlist_tests }, { "circuitmux/", circuitmux_tests }, { "circuituse/", circuituse_tests }, + { "circuitstats/", circuitstats_tests }, { "compat/libevent/", compat_libevent_tests }, { "config/", config_tests }, { "connection/", connection_tests }, @@ -1201,6 +1202,7 @@ struct testgroup_t testgroups[] = { { "hs_cell/", hs_cell_tests }, { "hs_common/", hs_common_tests }, { "hs_config/", hs_config_tests }, + { "hs_control/", hs_control_tests }, { "hs_descriptor/", hs_descriptor }, { "hs_ntor/", hs_ntor_tests }, { "hs_service/", hs_service_tests }, @@ -1227,7 +1229,6 @@ struct testgroup_t testgroups[] = { { "routerkeys/", routerkeys_tests }, { "routerlist/", routerlist_tests }, { "routerset/" , routerset_tests }, - { "rust/", rust_tests }, { "scheduler/", scheduler_tests }, { "socks/", socks_tests }, { "shared-random/", sr_tests }, diff --git a/src/test/test.h b/src/test/test.h index 634f3e7b02..93d527ba17 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -188,6 +188,7 @@ extern struct testcase_t circuitbuild_tests[]; extern struct testcase_t circuitlist_tests[]; extern struct testcase_t circuitmux_tests[]; extern struct testcase_t circuituse_tests[]; +extern struct testcase_t circuitstats_tests[]; extern struct testcase_t compat_libevent_tests[]; extern struct testcase_t config_tests[]; extern struct testcase_t connection_tests[]; @@ -210,6 +211,7 @@ extern struct testcase_t hs_cache[]; extern struct testcase_t hs_cell_tests[]; extern struct testcase_t hs_common_tests[]; extern struct testcase_t hs_config_tests[]; +extern struct testcase_t hs_control_tests[]; extern struct testcase_t hs_descriptor[]; extern struct testcase_t hs_ntor_tests[]; extern struct testcase_t hs_service_tests[]; @@ -239,7 +241,6 @@ extern struct testcase_t router_tests[]; extern struct testcase_t routerkeys_tests[]; extern struct testcase_t routerlist_tests[]; extern struct testcase_t routerset_tests[]; -extern struct testcase_t rust_tests[]; extern struct testcase_t scheduler_tests[]; extern struct testcase_t storagedir_tests[]; extern struct testcase_t socks_tests[]; diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c index 7edba988a6..b0d37b2989 100644 --- a/src/test/test_accounting.c +++ b/src/test/test_accounting.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #include "or.h" #include "test.h" #define HIBERNATE_PRIVATE diff --git a/src/test/test_address.c b/src/test/test_address.c index f36ff6998b..9c88d37a41 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -763,7 +763,7 @@ test_address_get_if_addrs_list_internal(void *arg) tt_assert(!smartlist_contains_ipv6_tor_addr(results)); done: - free_interface_address_list(results); + interface_address_list_free(results); return; } @@ -792,7 +792,7 @@ test_address_get_if_addrs_list_no_internal(void *arg) tt_assert(!smartlist_contains_ipv6_tor_addr(results)); done: - free_interface_address_list(results); + interface_address_list_free(results); return; } @@ -834,7 +834,7 @@ test_address_get_if_addrs6_list_internal(void *arg) } done: - free_interface_address6_list(results); + interface_address6_list_free(results); teardown_capture_of_logs(); return; } @@ -878,7 +878,7 @@ test_address_get_if_addrs6_list_no_internal(void *arg) done: teardown_capture_of_logs(); - free_interface_address6_list(results); + interface_address6_list_free(results); return; } @@ -943,8 +943,8 @@ test_address_get_if_addrs_internal_fail(void *arg) done: UNMOCK(get_interface_addresses_raw); UNMOCK(get_interface_address6_via_udp_socket_hack); - free_interface_address6_list(results1); - free_interface_address6_list(results2); + interface_address6_list_free(results1); + interface_address6_list_free(results2); return; } @@ -971,8 +971,8 @@ test_address_get_if_addrs_no_internal_fail(void *arg) done: UNMOCK(get_interface_addresses_raw); UNMOCK(get_interface_address6_via_udp_socket_hack); - free_interface_address6_list(results1); - free_interface_address6_list(results2); + interface_address6_list_free(results1); + interface_address6_list_free(results2); return; } diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index 9f4e19bc5f..057d9fa2dc 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -450,52 +450,54 @@ test_buffer_time_tracking(void *arg) tt_assert(buf); monotime_coarse_set_mock_time_nsec(START_NSEC); - const uint32_t START_MSEC = (uint32_t)monotime_coarse_absolute_msec(); + const uint32_t START_TS = monotime_coarse_get_stamp(); /* Empty buffer means the timestamp is 0. */ - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC)); - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); buf_add(buf, "ABCDEFG", 7); - tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); buf2 = buf_copy(buf); tt_assert(buf2); tt_int_op(1234, OP_EQ, - buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234)); + buf_get_oldest_chunk_timestamp(buf2, START_TS+1234)); /* Now add more bytes; enough to overflow the first chunk. */ monotime_coarse_set_mock_time_nsec(START_NSEC + 123 * (uint64_t)1000000); + const uint32_t TS2 = monotime_coarse_get_stamp(); for (i = 0; i < 600; ++i) buf_add(buf, "ABCDEFG", 7); tt_int_op(4207, OP_EQ, buf_datalen(buf)); /* The oldest bytes are still in the front. */ - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); /* Once those bytes are dropped, the chunk is still on the first * timestamp. */ buf_get_bytes(buf, tmp, 100); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); /* But once we discard the whole first chunk, we get the data in the second * chunk. */ buf_get_bytes(buf, tmp, 4000); tt_int_op(107, OP_EQ, buf_datalen(buf)); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); /* This time we'll be grabbing a chunk from the freelist, and making sure its time gets updated */ monotime_coarse_set_mock_time_nsec(START_NSEC + 5617 * (uint64_t)1000000); + const uint32_t TS3 = monotime_coarse_get_stamp(); for (i = 0; i < 600; ++i) buf_add(buf, "ABCDEFG", 7); tt_int_op(4307, OP_EQ, buf_datalen(buf)); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); buf_get_bytes(buf, tmp, 4000); buf_get_bytes(buf, tmp, 306); - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617)); - tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3)); + tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3+383)); done: buf_free(buf); diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c index 69e89b69b0..df987f82ce 100644 --- a/src/test/test_cell_queue.c +++ b/src/test/test_cell_queue.c @@ -130,8 +130,8 @@ test_circuit_n_cells(void *arg) tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), OP_EQ, 2); done: - circuit_free(TO_CIRCUIT(or_c)); - circuit_free(TO_CIRCUIT(origin_c)); + circuit_free_(TO_CIRCUIT(or_c)); + circuit_free_(TO_CIRCUIT(origin_c)); } struct testcase_t cell_queue_tests[] = { diff --git a/src/test/test_channel.c b/src/test/test_channel.c index 023c2950c9..bdc9d32f78 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -6,8 +6,10 @@ #include "or.h" #include "channel.h" /* For channel_note_destroy_not_pending */ +#define CIRCUITLIST_PRIVATE #include "circuitlist.h" #include "circuitmux.h" +#include "circuitmux_ewma.h" /* For var_cell_free */ #include "connection_or.h" /* For packed_cell stuff */ @@ -15,8 +17,10 @@ #include "relay.h" /* For init/free stuff */ #include "scheduler.h" +#include "networkstatus.h" /* Test suite stuff */ +#include "log_test_helpers.h" #include "test.h" #include "fakechans.h" @@ -26,62 +30,18 @@ static cell_t * test_chan_last_seen_fixed_cell_ptr = NULL; static int test_chan_var_cells_recved = 0; static var_cell_t * test_chan_last_seen_var_cell_ptr = NULL; static int test_cells_written = 0; -static int test_destroy_not_pending_calls = 0; static int test_doesnt_want_writes_count = 0; static int test_dumpstats_calls = 0; static int test_has_waiting_cells_count = 0; -static double test_overhead_estimate = 1.0; static int test_releases_count = 0; -static circuitmux_t *test_target_cmux = NULL; -static unsigned int test_cmux_cells = 0; static channel_t *dump_statistics_mock_target = NULL; static int dump_statistics_mock_matches = 0; - -static void chan_test_channel_dump_statistics_mock( - channel_t *chan, int severity); -static int chan_test_channel_flush_from_first_active_circuit_mock( - channel_t *chan, int max); -static unsigned int chan_test_circuitmux_num_cells_mock(circuitmux_t *cmux); -static void channel_note_destroy_not_pending_mock(channel_t *ch, - circid_t circid); -static void chan_test_cell_handler(channel_t *ch, - cell_t *cell); -static const char * chan_test_describe_transport(channel_t *ch); -static void chan_test_dumpstats(channel_t *ch, int severity); -static void chan_test_var_cell_handler(channel_t *ch, - var_cell_t *var_cell); -static void chan_test_close(channel_t *ch); -static void chan_test_error(channel_t *ch); -static void chan_test_finish_close(channel_t *ch); -static const char * chan_test_get_remote_descr(channel_t *ch, int flags); -static int chan_test_is_canonical(channel_t *ch, int req); -static size_t chan_test_num_bytes_queued(channel_t *ch); -static int chan_test_num_cells_writeable(channel_t *ch); -static int chan_test_write_cell(channel_t *ch, cell_t *cell); -static int chan_test_write_packed_cell(channel_t *ch, - packed_cell_t *packed_cell); -static int chan_test_write_var_cell(channel_t *ch, var_cell_t *var_cell); -static void scheduler_channel_doesnt_want_writes_mock(channel_t *ch); - -static void test_channel_dumpstats(void *arg); -static void test_channel_flush(void *arg); -static void test_channel_flushmux(void *arg); -static void test_channel_incoming(void *arg); -static void test_channel_lifecycle(void *arg); -static void test_channel_multi(void *arg); -static void test_channel_queue_incoming(void *arg); -static void test_channel_queue_size(void *arg); -static void test_channel_write(void *arg); - -static void -channel_note_destroy_not_pending_mock(channel_t *ch, - circid_t circid) -{ - (void)ch; - (void)circid; - - ++test_destroy_not_pending_calls; -} +static int test_close_called = 0; +static int test_chan_should_be_canonical = 0; +static int test_chan_should_match_target = 0; +static int test_chan_canonical_should_be_reliable = 0; +static int test_chan_listener_close_fn_called = 0; +static int test_chan_listener_fn_called = 0; static const char * chan_test_describe_transport(channel_t *ch) @@ -112,71 +72,14 @@ chan_test_channel_dump_statistics_mock(channel_t *chan, int severity) return; } -/** - * If the target cmux is the cmux for chan, make fake cells up to the - * target number of cells and write them to chan. Otherwise, invoke - * the real channel_flush_from_first_active_circuit(). - */ - -static int -chan_test_channel_flush_from_first_active_circuit_mock(channel_t *chan, - int max) -{ - int result = 0, c = 0; - packed_cell_t *cell = NULL; - - tt_ptr_op(chan, OP_NE, NULL); - if (test_target_cmux != NULL && - test_target_cmux == chan->cmux) { - while (c <= max && test_cmux_cells > 0) { - cell = packed_cell_new(); - channel_write_packed_cell(chan, cell); - ++c; - --test_cmux_cells; - } - result = c; - } else { - result = channel_flush_from_first_active_circuit__real(chan, max); - } - - done: - return result; -} - -/** - * If we have a target cmux set and this matches it, lie about how - * many cells we have according to the number indicated; otherwise - * pass to the real circuitmux_num_cells(). - */ - -static unsigned int -chan_test_circuitmux_num_cells_mock(circuitmux_t *cmux) -{ - unsigned int result = 0; - - tt_ptr_op(cmux, OP_NE, NULL); - if (cmux != NULL) { - if (cmux == test_target_cmux) { - result = test_cmux_cells; - } else { - result = circuitmux_num_cells__real(cmux); - } - } - - done: - - return result; -} - /* * Handle an incoming fixed-size cell for unit tests */ static void -chan_test_cell_handler(channel_t *ch, - cell_t *cell) +chan_test_cell_handler(channel_t *chan, cell_t *cell) { - tt_assert(ch); + tt_assert(chan); tt_assert(cell); test_chan_last_seen_fixed_cell_ptr = cell; @@ -226,6 +129,8 @@ chan_test_close(channel_t *ch) { tt_assert(ch); + ++test_close_called; + done: return; } @@ -274,35 +179,6 @@ chan_test_get_remote_descr(channel_t *ch, int flags) return "Fake channel for unit tests; no real endpoint"; } -static double -chan_test_get_overhead_estimate(channel_t *ch) -{ - tt_assert(ch); - - done: - return test_overhead_estimate; -} - -static int -chan_test_is_canonical(channel_t *ch, int req) -{ - tt_ptr_op(ch, OP_NE, NULL); - tt_assert(req == 0 || req == 1); - - done: - /* Fake channels are always canonical */ - return 1; -} - -static size_t -chan_test_num_bytes_queued(channel_t *ch) -{ - tt_assert(ch); - - done: - return 0; -} - static int chan_test_num_cells_writeable(channel_t *ch) { @@ -313,26 +189,6 @@ chan_test_num_cells_writeable(channel_t *ch) } static int -chan_test_write_cell(channel_t *ch, cell_t *cell) -{ - int rv = 0; - - tt_assert(ch); - tt_assert(cell); - - if (test_chan_accept_cells) { - /* Free the cell and bump the counter */ - tor_free(cell); - ++test_cells_written; - rv = 1; - } - /* else return 0, we didn't accept it */ - - done: - return rv; -} - -static int chan_test_write_packed_cell(channel_t *ch, packed_cell_t *packed_cell) { @@ -343,7 +199,6 @@ chan_test_write_packed_cell(channel_t *ch, if (test_chan_accept_cells) { /* Free the cell and bump the counter */ - packed_cell_free(packed_cell); ++test_cells_written; rv = 1; } @@ -419,36 +274,26 @@ new_fake_channel(void) channel_init(chan); chan->close = chan_test_close; - chan->get_overhead_estimate = chan_test_get_overhead_estimate; - chan->get_remote_descr = chan_test_get_remote_descr; - chan->num_bytes_queued = chan_test_num_bytes_queued; chan->num_cells_writeable = chan_test_num_cells_writeable; - chan->write_cell = chan_test_write_cell; + chan->get_remote_descr = chan_test_get_remote_descr; chan->write_packed_cell = chan_test_write_packed_cell; chan->write_var_cell = chan_test_write_var_cell; chan->state = CHANNEL_STATE_OPEN; + chan->cmux = circuitmux_alloc(); + return chan; } void free_fake_channel(channel_t *chan) { - cell_queue_entry_t *cell, *cell_tmp; - if (! chan) return; if (chan->cmux) circuitmux_free(chan->cmux); - TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { - cell_queue_entry_free(cell, 0); - } - TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { - cell_queue_entry_free(cell, 0); - } - tor_free(chan); } @@ -489,16 +334,6 @@ scheduler_channel_doesnt_want_writes_mock(channel_t *ch) } /** - * Counter query for scheduler_release_channel_mock() - */ - -int -get_mock_scheduler_release_channel_count(void) -{ - return test_releases_count; -} - -/** * Mock for scheduler_release_channel() */ @@ -513,6 +348,58 @@ scheduler_release_channel_mock(channel_t *ch) return; } +static int +test_chan_is_canonical(channel_t *chan, int req) +{ + tor_assert(chan); + + if (req && test_chan_canonical_should_be_reliable) { + return 1; + } + + if (test_chan_should_be_canonical) { + return 1; + } + return 0; +} + +static int +test_chan_matches_target(channel_t *chan, const tor_addr_t *target) +{ + (void) chan; + (void) target; + + if (test_chan_should_match_target) { + return 1; + } + return 0; +} + +static void +test_chan_listener_close(channel_listener_t *chan) +{ + (void) chan; + ++test_chan_listener_close_fn_called; + return; +} + +static void +test_chan_listener_fn(channel_listener_t *listener, channel_t *chan) +{ + (void) listener; + (void) chan; + + ++test_chan_listener_fn_called; + return; +} + +static const char * +test_chan_listener_describe_transport(channel_listener_t *chan) +{ + (void) chan; + return "Fake listener channel."; +} + /** * Test for channel_dumpstats() and limited test for * channel_dump_statistics() @@ -523,6 +410,7 @@ test_channel_dumpstats(void *arg) { channel_t *ch = NULL; cell_t *cell = NULL; + packed_cell_t *p_cell = NULL; int old_count; (void)arg; @@ -536,7 +424,6 @@ test_channel_dumpstats(void *arg) /* Set up a new fake channel */ ch = new_fake_channel(); tt_assert(ch); - ch->cmux = circuitmux_alloc(); /* Try to register it */ channel_register(ch); @@ -579,24 +466,21 @@ test_channel_dumpstats(void *arg) /* Now make another channel */ ch = new_fake_channel(); tt_assert(ch); - ch->cmux = circuitmux_alloc(); channel_register(ch); - tt_assert(ch->registered); + tt_int_op(ch->registered, OP_EQ, 1); /* Lie about its age so dumpstats gets coverage for rate calculations */ ch->timestamp_created = time(NULL) - 30; - tt_assert(ch->timestamp_created > 0); - tt_assert(time(NULL) > ch->timestamp_created); + tt_int_op(ch->timestamp_created, OP_GT, 0); + tt_int_op(time(NULL), OP_GT, ch->timestamp_created); /* Put cells through it both ways to make the counters non-zero */ - cell = tor_malloc_zero(sizeof(*cell)); - make_fake_cell(cell); + p_cell = packed_cell_new(); test_chan_accept_cells = 1; old_count = test_cells_written; - channel_write_cell(ch, cell); - cell = NULL; + channel_write_packed_cell(ch, p_cell); tt_int_op(test_cells_written, OP_EQ, old_count + 1); - tt_assert(ch->n_bytes_xmitted > 0); - tt_assert(ch->n_cells_xmitted > 0); + tt_u64_op(ch->n_bytes_xmitted, OP_GT, 0); + tt_u64_op(ch->n_cells_xmitted, OP_GT, 0); /* Receive path */ channel_set_cell_handlers(ch, @@ -605,19 +489,18 @@ test_channel_dumpstats(void *arg) tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler); tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ, chan_test_var_cell_handler); - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); + cell = tor_malloc_zero(sizeof(*cell)); old_count = test_chan_fixed_cells_recved; - channel_queue_cell(ch, cell); - tor_free(cell); + channel_process_cell(ch, cell); tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1); - tt_assert(ch->n_bytes_recved > 0); - tt_assert(ch->n_cells_recved > 0); + tt_u64_op(ch->n_bytes_recved, OP_GT, 0); + tt_u64_op(ch->n_cells_recved, OP_GT, 0); /* Test channel_dump_statistics */ ch->describe_transport = chan_test_describe_transport; ch->dumpstats = chan_test_dumpstats; - ch->is_canonical = chan_test_is_canonical; + test_chan_should_be_canonical = 1; + ch->is_canonical = test_chan_is_canonical; old_count = test_dumpstats_calls; channel_dump_statistics(ch, LOG_DEBUG); tt_int_op(test_dumpstats_calls, OP_EQ, old_count + 1); @@ -631,8 +514,8 @@ test_channel_dumpstats(void *arg) ch = NULL; done: - tor_free(cell); free_fake_channel(ch); + tor_free(cell); UNMOCK(scheduler_channel_doesnt_want_writes); UNMOCK(scheduler_release_channel); @@ -640,215 +523,229 @@ test_channel_dumpstats(void *arg) return; } +/* Test outbound cell. The callstack is: + * channel_flush_some_cells() + * -> channel_flush_from_first_active_circuit() + * -> channel_write_packed_cell() + * -> write_packed_cell() + * -> chan->write_packed_cell() fct ptr. + * + * This test goes from a cell in a circuit up to the channel write handler + * that should put them on the connection outbuf. */ static void -test_channel_flush(void *arg) +test_channel_outbound_cell(void *arg) { - channel_t *ch = NULL; - cell_t *cell = NULL; - packed_cell_t *p_cell = NULL; - var_cell_t *v_cell = NULL; - int init_count; - - (void)arg; + int old_count; + channel_t *chan = NULL; + packed_cell_t *p_cell = NULL, *p_cell2 = NULL; + origin_circuit_t *circ = NULL; + cell_queue_t *queue; - ch = new_fake_channel(); - tt_assert(ch); + (void) arg; - /* Cache the original count */ - init_count = test_cells_written; + /* The channel will be freed so we need to hijack this so the scheduler + * doesn't get confused. */ + MOCK(scheduler_release_channel, scheduler_release_channel_mock); - /* Stop accepting so we can queue some */ - test_chan_accept_cells = 0; + /* Accept cells to lower layer */ + test_chan_accept_cells = 1; - /* Queue a regular cell */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch, cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Queue a var cell */ - v_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(v_cell); - channel_write_var_cell(ch, v_cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Try a packed cell now */ + /* Setup a valid circuit to queue a cell. */ + circ = origin_circuit_new(); + tt_assert(circ); + /* Circuit needs an origin purpose to be considered origin. */ + TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + TO_CIRCUIT(circ)->n_circ_id = 42; + /* This is the outbound test so use the next channel queue. */ + queue = &TO_CIRCUIT(circ)->n_chan_cells; + /* Setup packed cell to queue on the circuit. */ p_cell = packed_cell_new(); tt_assert(p_cell); - channel_write_packed_cell(ch, p_cell); - /* It should be queued, so assert that we didn't write it */ - tt_int_op(test_cells_written, OP_EQ, init_count); - - /* Now allow writes through again */ - test_chan_accept_cells = 1; - - /* ...and flush */ - channel_flush_cells(ch); - - /* All three should have gone through */ - tt_int_op(test_cells_written, OP_EQ, init_count + 3); - - done: - tor_free(ch); - - return; -} - -/** - * Channel flush tests that require cmux mocking - */ - -static void -test_channel_flushmux(void *arg) -{ - channel_t *ch = NULL; - int old_count, q_len_before, q_len_after; - ssize_t result; - - (void)arg; - - /* Install mocks we need for this test */ - MOCK(channel_flush_from_first_active_circuit, - chan_test_channel_flush_from_first_active_circuit_mock); - MOCK(circuitmux_num_cells, - chan_test_circuitmux_num_cells_mock); - - ch = new_fake_channel(); - tt_assert(ch); - ch->cmux = circuitmux_alloc(); - + p_cell2 = packed_cell_new(); + tt_assert(p_cell2); + /* Setup a channel to put the circuit on. */ + chan = new_fake_channel(); + tt_assert(chan); + chan->state = CHANNEL_STATE_OPENING; + channel_change_state_open(chan); + /* Outbound channel. */ + channel_mark_outgoing(chan); + /* Try to register it so we can clean it through the channel cleanup + * process. */ + channel_register(chan); + tt_int_op(chan->registered, OP_EQ, 1); + /* Set EWMA policy so we can pick it when flushing. */ + channel_set_cmux_policy_everywhere(&ewma_policy); + tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy); + + /* Register circuit to the channel circid map which will attach the circuit + * to the channel's cmux as well. */ + circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan); + tt_int_op(channel_num_circuits(chan), OP_EQ, 1); + tt_assert(!TO_CIRCUIT(circ)->next_active_on_n_chan); + tt_assert(!TO_CIRCUIT(circ)->prev_active_on_n_chan); + /* Test the cmux state. */ + tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux); + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + + /* Flush the channel without any cell on it. */ old_count = test_cells_written; - - test_target_cmux = ch->cmux; - test_cmux_cells = 1; - - /* Enable cell acceptance */ - test_chan_accept_cells = 1; - - result = channel_flush_some_cells(ch, 1); - - tt_int_op(result, OP_EQ, 1); + ssize_t flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 0); + tt_int_op(test_cells_written, OP_EQ, old_count); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 0); + tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 0); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0); + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 0); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 0); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, 0); + + /* Queue cell onto the next queue that is the outbound direction. Than + * update its cmux so the circuit can be picked when flushing cells. */ + cell_queue_append(queue, p_cell); + p_cell = NULL; + tt_int_op(queue->n, OP_EQ, 1); + cell_queue_append(queue, p_cell2); + p_cell2 = NULL; + tt_int_op(queue->n, OP_EQ, 2); + + update_circuit_on_cmux(TO_CIRCUIT(circ), CELL_DIRECTION_OUT); + tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 1); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 2); + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + + /* From this point on, we have a queued cell on an active circuit attached + * to the channel's cmux. */ + + /* Flush the first cell. This is going to go down the call stack. */ + old_count = test_cells_written; + flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 1); tt_int_op(test_cells_written, OP_EQ, old_count + 1); - tt_int_op(test_cmux_cells, OP_EQ, 0); - - /* Now try it without accepting to force them into the queue */ - test_chan_accept_cells = 0; - test_cmux_cells = 1; - q_len_before = chan_cell_queue_len(&(ch->outgoing_queue)); - - result = channel_flush_some_cells(ch, 1); - - /* We should not have actually flushed any */ - tt_int_op(result, OP_EQ, 0); + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 1); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 1); + /* Circuit should remain active because there is a second cell queued. */ + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + /* Should still be attached. */ + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 1); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0)); + + /* Flush second cell. This is going to go down the call stack. */ + old_count = test_cells_written; + flushed = channel_flush_some_cells(chan, 1); + tt_i64_op(flushed, OP_EQ, 1); tt_int_op(test_cells_written, OP_EQ, old_count + 1); - /* But we should have gotten to the fake cellgen loop */ - tt_int_op(test_cmux_cells, OP_EQ, 0); - /* ...and we should have a queued cell */ - q_len_after = chan_cell_queue_len(&(ch->outgoing_queue)); - tt_int_op(q_len_after, OP_EQ, q_len_before + 1); - - /* Now accept cells again and drain the queue */ - test_chan_accept_cells = 1; - channel_flush_cells(ch); - tt_int_op(test_cells_written, OP_EQ, old_count + 2); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - test_target_cmux = NULL; - test_cmux_cells = 0; + tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0); + tt_int_op(channel_more_to_flush(chan), OP_EQ, 0); + /* No more cells should make the circuit inactive. */ + tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 0); + /* Should still be attached. */ + tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), + OP_EQ, 1); + tt_u64_op(chan->n_cells_xmitted, OP_EQ, 2); + tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0) * 2); done: - if (ch) - circuitmux_free(ch->cmux); - tor_free(ch); - - UNMOCK(channel_flush_from_first_active_circuit); - UNMOCK(circuitmux_num_cells); - - test_chan_accept_cells = 0; - - return; + if (circ) { + circuit_free_(TO_CIRCUIT(circ)); + } + tor_free(p_cell); + channel_free_all(); + UNMOCK(scheduler_release_channel); } +/* Test inbound cell. The callstack is: + * channel_process_cell() + * -> chan->cell_handler() + * + * This test is about checking if we can process an inbound cell down to the + * channel handler. */ static void -test_channel_incoming(void *arg) +test_channel_inbound_cell(void *arg) { - channel_t *ch = NULL; + channel_t *chan = NULL; cell_t *cell = NULL; - var_cell_t *var_cell = NULL; int old_count; - (void)arg; + (void) arg; - /* Mock these for duration of the test */ - MOCK(scheduler_channel_doesnt_want_writes, - scheduler_channel_doesnt_want_writes_mock); - MOCK(scheduler_release_channel, - scheduler_release_channel_mock); + /* The channel will be freed so we need to hijack this so the scheduler + * doesn't get confused. */ + MOCK(scheduler_release_channel, scheduler_release_channel_mock); /* Accept cells to lower layer */ test_chan_accept_cells = 1; - /* Use default overhead factor */ - test_overhead_estimate = 1.0; - ch = new_fake_channel(); - tt_assert(ch); + chan = new_fake_channel(); + tt_assert(chan); /* Start it off in OPENING */ - ch->state = CHANNEL_STATE_OPENING; - /* We'll need a cmux */ - ch->cmux = circuitmux_alloc(); - - /* Install incoming cell handlers */ - channel_set_cell_handlers(ch, - chan_test_cell_handler, - chan_test_var_cell_handler); - /* Test cell handler getters */ - tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler); - tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ, - chan_test_var_cell_handler); + chan->state = CHANNEL_STATE_OPENING; /* Try to register it */ - channel_register(ch); - tt_assert(ch->registered); + channel_register(chan); + tt_int_op(chan->registered, OP_EQ, 1); /* Open it */ - channel_change_state_open(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN); + channel_change_state_open(chan); + tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_OPEN); + tt_int_op(chan->has_been_open, OP_EQ, 1); - /* Receive a fixed cell */ - cell = tor_malloc_zero(sizeof(cell_t)); + /* Receive a cell now. */ + cell = tor_malloc_zero(sizeof(*cell)); make_fake_cell(cell); old_count = test_chan_fixed_cells_recved; - channel_queue_cell(ch, cell); - tor_free(cell); + channel_process_cell(chan, cell); + tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count); + tt_assert(monotime_coarse_is_zero(&chan->timestamp_xfer)); + tt_u64_op(chan->timestamp_active, OP_EQ, 0); + tt_u64_op(chan->timestamp_recv, OP_EQ, 0); + + /* Setup incoming cell handlers. We don't care about var cell, the channel + * layers is not handling those. */ + channel_set_cell_handlers(chan, chan_test_cell_handler, NULL); + tt_ptr_op(chan->cell_handler, OP_EQ, chan_test_cell_handler); + /* Now process the cell, we should see it. */ + old_count = test_chan_fixed_cells_recved; + channel_process_cell(chan, cell); tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1); - - /* Receive a variable-size cell */ - var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(var_cell); - old_count = test_chan_var_cells_recved; - channel_queue_var_cell(ch, var_cell); - tor_free(cell); - tt_int_op(test_chan_var_cells_recved, OP_EQ, old_count + 1); + /* We should have a series of timestamp set. */ + tt_assert(!monotime_coarse_is_zero(&chan->timestamp_xfer)); + tt_u64_op(chan->timestamp_active, OP_NE, 0); + tt_u64_op(chan->timestamp_recv, OP_NE, 0); + tt_assert(monotime_coarse_is_zero(&chan->next_padding_time)); + tt_u64_op(chan->n_cells_recved, OP_EQ, 1); + tt_u64_op(chan->n_bytes_recved, OP_EQ, get_cell_network_size(0)); /* Close it */ - channel_mark_for_close(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING); - chan_test_finish_close(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED); + old_count = test_close_called; + channel_mark_for_close(chan); + tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSING); + tt_int_op(chan->reason_for_closing, OP_EQ, CHANNEL_CLOSE_REQUESTED); + tt_int_op(test_close_called, OP_EQ, old_count + 1); + + /* This closes the channe so it calls in the scheduler, make sure of it. */ + old_count = test_releases_count; + chan_test_finish_close(chan); + tt_int_op(test_releases_count, OP_EQ, old_count + 1); + tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSED); + + /* The channel will be free, lets make sure it is not accessible. */ + uint64_t chan_id = chan->global_identifier; + tt_ptr_op(channel_find_by_global_id(chan_id), OP_EQ, chan); channel_run_cleanup(); - ch = NULL; + chan = channel_find_by_global_id(chan_id); + tt_assert(chan == NULL); done: - free_fake_channel(ch); tor_free(cell); - tor_free(var_cell); - - UNMOCK(scheduler_channel_doesnt_want_writes); UNMOCK(scheduler_release_channel); - - return; } /** @@ -861,7 +758,7 @@ static void test_channel_lifecycle(void *arg) { channel_t *ch1 = NULL, *ch2 = NULL; - cell_t *cell = NULL; + packed_cell_t *p_cell = NULL; int old_count, init_doesnt_want_writes_count; int init_releases_count; @@ -879,38 +776,29 @@ test_channel_lifecycle(void *arg) /* Accept cells to lower layer */ test_chan_accept_cells = 1; - /* Use default overhead factor */ - test_overhead_estimate = 1.0; ch1 = new_fake_channel(); tt_assert(ch1); /* Start it off in OPENING */ ch1->state = CHANNEL_STATE_OPENING; - /* We'll need a cmux */ - ch1->cmux = circuitmux_alloc(); /* Try to register it */ channel_register(ch1); tt_assert(ch1->registered); /* Try to write a cell through (should queue) */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); + p_cell = packed_cell_new(); old_count = test_cells_written; - channel_write_cell(ch1, cell); + channel_write_packed_cell(ch1, p_cell); tt_int_op(old_count, OP_EQ, test_cells_written); /* Move it to OPEN and flush */ channel_change_state_open(ch1); - /* Queue should drain */ - tt_int_op(old_count + 1, OP_EQ, test_cells_written); - - /* Get another one */ +/* Get another one */ ch2 = new_fake_channel(); tt_assert(ch2); ch2->state = CHANNEL_STATE_OPENING; - ch2->cmux = circuitmux_alloc(); /* Register */ channel_register(ch2); @@ -960,8 +848,6 @@ test_channel_lifecycle(void *arg) UNMOCK(scheduler_channel_doesnt_want_writes); UNMOCK(scheduler_release_channel); - - return; } /** @@ -988,15 +874,11 @@ test_channel_lifecycle_2(void *arg) /* Accept cells to lower layer */ test_chan_accept_cells = 1; - /* Use default overhead factor */ - test_overhead_estimate = 1.0; ch = new_fake_channel(); tt_assert(ch); /* Start it off in OPENING */ ch->state = CHANNEL_STATE_OPENING; - /* The full lifecycle test needs a cmux */ - ch->cmux = circuitmux_alloc(); /* Try to register it */ channel_register(ch); @@ -1016,7 +898,6 @@ test_channel_lifecycle_2(void *arg) ch = new_fake_channel(); tt_assert(ch); ch->state = CHANNEL_STATE_OPENING; - ch->cmux = circuitmux_alloc(); channel_register(ch); tt_assert(ch->registered); @@ -1035,7 +916,6 @@ test_channel_lifecycle_2(void *arg) ch = new_fake_channel(); tt_assert(ch); ch->state = CHANNEL_STATE_OPENING; - ch->cmux = circuitmux_alloc(); channel_register(ch); tt_assert(ch->registered); @@ -1064,7 +944,6 @@ test_channel_lifecycle_2(void *arg) ch = new_fake_channel(); tt_assert(ch); ch->state = CHANNEL_STATE_OPENING; - ch->cmux = circuitmux_alloc(); channel_register(ch); tt_assert(ch->registered); @@ -1090,7 +969,6 @@ test_channel_lifecycle_2(void *arg) ch = new_fake_channel(); tt_assert(ch); ch->state = CHANNEL_STATE_OPENING; - ch->cmux = circuitmux_alloc(); channel_register(ch); tt_assert(ch->registered); @@ -1125,655 +1003,6 @@ test_channel_lifecycle_2(void *arg) } static void -test_channel_multi(void *arg) -{ - channel_t *ch1 = NULL, *ch2 = NULL; - uint64_t global_queue_estimate; - cell_t *cell = NULL; - - (void)arg; - - /* Accept cells to lower layer */ - test_chan_accept_cells = 1; - /* Use default overhead factor */ - test_overhead_estimate = 1.0; - - ch1 = new_fake_channel(); - tt_assert(ch1); - ch2 = new_fake_channel(); - tt_assert(ch2); - - /* Initial queue size update */ - channel_update_xmit_queue_size(ch1); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0); - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Queue some cells, check queue estimates */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch1, cell); - - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch2, cell); - - channel_update_xmit_queue_size(ch1); - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Stop accepting cells at lower layer */ - test_chan_accept_cells = 0; - - /* Queue some cells and check queue estimates */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch1, cell); - - channel_update_xmit_queue_size(ch1); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 512); - - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch2, cell); - - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 512); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 1024); - - /* Allow cells through again */ - test_chan_accept_cells = 1; - - /* Flush chan 2 */ - channel_flush_cells(ch2); - - /* Update and check queue sizes */ - channel_update_xmit_queue_size(ch1); - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 512); - - /* Flush chan 1 */ - channel_flush_cells(ch1); - - /* Update and check queue sizes */ - channel_update_xmit_queue_size(ch1); - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Now block again */ - test_chan_accept_cells = 0; - - /* Queue some cells */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch1, cell); - - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch2, cell); - cell = NULL; - - /* Check the estimates */ - channel_update_xmit_queue_size(ch1); - channel_update_xmit_queue_size(ch2); - tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512); - tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 512); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 1024); - - /* Now close channel 2; it should be subtracted from the global queue */ - MOCK(scheduler_release_channel, scheduler_release_channel_mock); - channel_mark_for_close(ch2); - UNMOCK(scheduler_release_channel); - - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 512); - - /* - * Since the fake channels aren't registered, channel_free_all() can't - * see them properly. - */ - MOCK(scheduler_release_channel, scheduler_release_channel_mock); - channel_mark_for_close(ch1); - UNMOCK(scheduler_release_channel); - - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Now free everything */ - MOCK(scheduler_release_channel, scheduler_release_channel_mock); - channel_free_all(); - UNMOCK(scheduler_release_channel); - - done: - free_fake_channel(ch1); - free_fake_channel(ch2); - - return; -} - -/** - * Check some hopefully-impossible edge cases in the channel queue we - * can only trigger by doing evil things to the queue directly. - */ - -static void -test_channel_queue_impossible(void *arg) -{ - channel_t *ch = NULL; - cell_t *cell = NULL; - packed_cell_t *packed_cell = NULL; - var_cell_t *var_cell = NULL; - int old_count; - cell_queue_entry_t *q = NULL; - uint64_t global_queue_estimate; - uintptr_t cellintptr; - - /* Cache the global queue size (see below) */ - global_queue_estimate = channel_get_global_queue_estimate(); - - (void)arg; - - ch = new_fake_channel(); - tt_assert(ch); - - /* We test queueing here; tell it not to accept cells */ - test_chan_accept_cells = 0; - /* ...and keep it from trying to flush the queue */ - ch->state = CHANNEL_STATE_MAINT; - - /* Cache the cell written count */ - old_count = test_cells_written; - - /* Assert that the queue is initially empty */ - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - /* Get a fresh cell and write it to the channel*/ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - cellintptr = (uintptr_t)(void*)cell; - channel_write_cell(ch, cell); - - /* Now it should be queued */ - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1); - q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue)); - tt_assert(q); - if (q) { - tt_int_op(q->type, OP_EQ, CELL_QUEUE_FIXED); - tt_assert((uintptr_t)q->u.fixed.cell == cellintptr); - } - /* Do perverse things to it */ - tor_free(q->u.fixed.cell); - q->u.fixed.cell = NULL; - - /* - * Now change back to open with channel_change_state() and assert that it - * gets thrown away properly. - */ - test_chan_accept_cells = 1; - channel_change_state_open(ch); - tt_assert(test_cells_written == old_count); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - /* Same thing but for a var_cell */ - - test_chan_accept_cells = 0; - ch->state = CHANNEL_STATE_MAINT; - var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(var_cell); - cellintptr = (uintptr_t)(void*)var_cell; - channel_write_var_cell(ch, var_cell); - - /* Check that it's queued */ - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1); - q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue)); - tt_assert(q); - if (q) { - tt_int_op(q->type, OP_EQ, CELL_QUEUE_VAR); - tt_assert((uintptr_t)q->u.var.var_cell == cellintptr); - } - - /* Remove the cell from the queue entry */ - tor_free(q->u.var.var_cell); - q->u.var.var_cell = NULL; - - /* Let it drain and check that the bad entry is discarded */ - test_chan_accept_cells = 1; - channel_change_state_open(ch); - tt_assert(test_cells_written == old_count); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - /* Same thing with a packed_cell */ - - test_chan_accept_cells = 0; - ch->state = CHANNEL_STATE_MAINT; - packed_cell = packed_cell_new(); - tt_assert(packed_cell); - cellintptr = (uintptr_t)(void*)packed_cell; - channel_write_packed_cell(ch, packed_cell); - - /* Check that it's queued */ - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1); - q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue)); - tt_assert(q); - if (q) { - tt_int_op(q->type, OP_EQ, CELL_QUEUE_PACKED); - tt_assert((uintptr_t)q->u.packed.packed_cell == cellintptr); - } - - /* Remove the cell from the queue entry */ - packed_cell_free(q->u.packed.packed_cell); - q->u.packed.packed_cell = NULL; - - /* Let it drain and check that the bad entry is discarded */ - test_chan_accept_cells = 1; - channel_change_state_open(ch); - tt_assert(test_cells_written == old_count); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - /* Unknown cell type case */ - test_chan_accept_cells = 0; - ch->state = CHANNEL_STATE_MAINT; - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - cellintptr = (uintptr_t)(void*)cell; - channel_write_cell(ch, cell); - - /* Check that it's queued */ - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1); - q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue)); - tt_assert(q); - if (q) { - tt_int_op(q->type, OP_EQ, CELL_QUEUE_FIXED); - tt_assert((uintptr_t)q->u.fixed.cell == cellintptr); - } - /* Clobber it, including the queue entry type */ - tor_free(q->u.fixed.cell); - q->u.fixed.cell = NULL; - q->type = CELL_QUEUE_PACKED + 1; - - /* Let it drain and check that the bad entry is discarded */ - test_chan_accept_cells = 1; - tor_capture_bugs_(1); - channel_change_state_open(ch); - tt_assert(test_cells_written == old_count); - tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0); - - tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); - tor_end_capture_bugs_(); - - done: - free_fake_channel(ch); - - /* - * Doing that meant that we couldn't correctly adjust the queue size - * for the var cell, so manually reset the global queue size estimate - * so the next test doesn't break if we run with --no-fork. - */ - estimated_total_queue_size = global_queue_estimate; - - return; -} - -static void -test_channel_queue_incoming(void *arg) -{ - channel_t *ch = NULL; - cell_t *cell = NULL; - var_cell_t *var_cell = NULL; - int old_fixed_count, old_var_count; - - (void)arg; - - /* Mock these for duration of the test */ - MOCK(scheduler_channel_doesnt_want_writes, - scheduler_channel_doesnt_want_writes_mock); - MOCK(scheduler_release_channel, - scheduler_release_channel_mock); - - /* Accept cells to lower layer */ - test_chan_accept_cells = 1; - /* Use default overhead factor */ - test_overhead_estimate = 1.0; - - ch = new_fake_channel(); - tt_assert(ch); - /* Start it off in OPENING */ - ch->state = CHANNEL_STATE_OPENING; - /* We'll need a cmux */ - ch->cmux = circuitmux_alloc(); - - /* Test cell handler getters */ - tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, NULL); - tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ, NULL); - - /* Try to register it */ - channel_register(ch); - tt_assert(ch->registered); - - /* Open it */ - channel_change_state_open(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN); - - /* Assert that the incoming queue is empty */ - tt_assert(TOR_SIMPLEQ_EMPTY(&(ch->incoming_queue))); - - /* Queue an incoming fixed-length cell */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_queue_cell(ch, cell); - - /* Assert that the incoming queue has one entry */ - tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), OP_EQ, 1); - - /* Queue an incoming var cell */ - var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(var_cell); - channel_queue_var_cell(ch, var_cell); - - /* Assert that the incoming queue has two entries */ - tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), OP_EQ, 2); - - /* - * Install cell handlers; this will drain the queue, so save the old - * cell counters first - */ - old_fixed_count = test_chan_fixed_cells_recved; - old_var_count = test_chan_var_cells_recved; - channel_set_cell_handlers(ch, - chan_test_cell_handler, - chan_test_var_cell_handler); - tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler); - tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ, - chan_test_var_cell_handler); - - /* Assert cells were received */ - tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_fixed_count + 1); - tt_int_op(test_chan_var_cells_recved, OP_EQ, old_var_count + 1); - - /* - * Assert that the pointers are different from the cells we allocated; - * when queueing cells with no incoming cell handlers installed, the - * channel layer should copy them to a new buffer, and free them after - * delivery. These pointers will have already been freed by the time - * we get here, so don't dereference them. - */ - tt_ptr_op(test_chan_last_seen_fixed_cell_ptr, OP_NE, cell); - tt_ptr_op(test_chan_last_seen_var_cell_ptr, OP_NE, var_cell); - - /* Assert queue is now empty */ - tt_assert(TOR_SIMPLEQ_EMPTY(&(ch->incoming_queue))); - - /* Close it; this contains an assertion that the incoming queue is empty */ - channel_mark_for_close(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING); - chan_test_finish_close(ch); - tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED); - channel_run_cleanup(); - ch = NULL; - - done: - free_fake_channel(ch); - tor_free(cell); - tor_free(var_cell); - - UNMOCK(scheduler_channel_doesnt_want_writes); - UNMOCK(scheduler_release_channel); - - return; -} - -static void -test_channel_queue_size(void *arg) -{ - channel_t *ch = NULL; - cell_t *cell = NULL; - int n, old_count; - uint64_t global_queue_estimate; - - (void)arg; - - ch = new_fake_channel(); - tt_assert(ch); - - /* Initial queue size update */ - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Test the call-through to our fake lower layer */ - n = channel_num_cells_writeable(ch); - /* chan_test_num_cells_writeable() always returns 32 */ - tt_int_op(n, OP_EQ, 32); - - /* - * Now we queue some cells and check that channel_num_cells_writeable() - * adjusts properly - */ - - /* tell it not to accept cells */ - test_chan_accept_cells = 0; - /* ...and keep it from trying to flush the queue */ - ch->state = CHANNEL_STATE_MAINT; - - /* Get a fresh cell */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - - old_count = test_cells_written; - channel_write_cell(ch, cell); - /* Assert that it got queued, not written through, correctly */ - tt_int_op(test_cells_written, OP_EQ, old_count); - - /* Now check chan_test_num_cells_writeable() again */ - n = channel_num_cells_writeable(ch); - /* Should return 0 since we're in CHANNEL_STATE_MAINT */ - tt_int_op(n, OP_EQ, 0); - - /* Update queue size estimates */ - channel_update_xmit_queue_size(ch); - /* One cell, times an overhead factor of 1.0 */ - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512); - /* Try a different overhead factor */ - test_overhead_estimate = 0.5; - /* This one should be ignored since it's below 1.0 */ - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512); - /* Now try a larger one */ - test_overhead_estimate = 2.0; - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 1024); - /* Go back to 1.0 */ - test_overhead_estimate = 1.0; - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512); - /* Check the global estimate too */ - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 512); - - /* Go to open */ - old_count = test_cells_written; - channel_change_state_open(ch); - - /* - * It should try to write, but we aren't accepting cells right now, so - * it'll requeue - */ - tt_int_op(test_cells_written, OP_EQ, old_count); - - /* Check the queue size again */ - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 512); - - /* - * Now the cell is in the queue, and we're open, so we should get 31 - * writeable cells. - */ - n = channel_num_cells_writeable(ch); - tt_int_op(n, OP_EQ, 31); - - /* Accept cells again */ - test_chan_accept_cells = 1; - /* ...and re-process the queue */ - old_count = test_cells_written; - channel_flush_cells(ch); - tt_int_op(test_cells_written, OP_EQ, old_count + 1); - - /* Should have 32 writeable now */ - n = channel_num_cells_writeable(ch); - tt_int_op(n, OP_EQ, 32); - - /* Should have queue size estimate of zero */ - channel_update_xmit_queue_size(ch); - tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 0); - global_queue_estimate = channel_get_global_queue_estimate(); - tt_u64_op(global_queue_estimate, OP_EQ, 0); - - /* Okay, now we're done with this one */ - MOCK(scheduler_release_channel, scheduler_release_channel_mock); - channel_mark_for_close(ch); - UNMOCK(scheduler_release_channel); - - done: - free_fake_channel(ch); - - return; -} - -static void -test_channel_write(void *arg) -{ - channel_t *ch = NULL; - cell_t *cell = tor_malloc_zero(sizeof(cell_t)); - packed_cell_t *packed_cell = NULL; - var_cell_t *var_cell = - tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - int old_count; - - (void)arg; - - packed_cell = packed_cell_new(); - tt_assert(packed_cell); - - ch = new_fake_channel(); - tt_assert(ch); - make_fake_cell(cell); - make_fake_var_cell(var_cell); - - /* Tell it to accept cells */ - test_chan_accept_cells = 1; - - old_count = test_cells_written; - channel_write_cell(ch, cell); - cell = NULL; - tt_assert(test_cells_written == old_count + 1); - - channel_write_var_cell(ch, var_cell); - var_cell = NULL; - tt_assert(test_cells_written == old_count + 2); - - channel_write_packed_cell(ch, packed_cell); - packed_cell = NULL; - tt_assert(test_cells_written == old_count + 3); - - /* Now we test queueing; tell it not to accept cells */ - test_chan_accept_cells = 0; - /* ...and keep it from trying to flush the queue */ - ch->state = CHANNEL_STATE_MAINT; - - /* Get a fresh cell */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - - old_count = test_cells_written; - channel_write_cell(ch, cell); - tt_assert(test_cells_written == old_count); - - /* - * Now change back to open with channel_change_state() and assert that it - * gets drained from the queue. - */ - test_chan_accept_cells = 1; - channel_change_state_open(ch); - tt_assert(test_cells_written == old_count + 1); - - /* - * Check the note destroy case - */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - cell->command = CELL_DESTROY; - - /* Set up the mock */ - MOCK(channel_note_destroy_not_pending, - channel_note_destroy_not_pending_mock); - - old_count = test_destroy_not_pending_calls; - channel_write_cell(ch, cell); - tt_assert(test_destroy_not_pending_calls == old_count + 1); - - /* Now send a non-destroy and check we don't call it */ - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch, cell); - tt_assert(test_destroy_not_pending_calls == old_count + 1); - - UNMOCK(channel_note_destroy_not_pending); - - /* - * Now switch it to CLOSING so we can test the discard-cells case - * in the channel_write_*() functions. - */ - MOCK(scheduler_release_channel, scheduler_release_channel_mock); - channel_mark_for_close(ch); - UNMOCK(scheduler_release_channel); - - /* Send cells that will drop in the closing state */ - old_count = test_cells_written; - - cell = tor_malloc_zero(sizeof(cell_t)); - make_fake_cell(cell); - channel_write_cell(ch, cell); - cell = NULL; - tt_assert(test_cells_written == old_count); - - var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE); - make_fake_var_cell(var_cell); - channel_write_var_cell(ch, var_cell); - var_cell = NULL; - tt_assert(test_cells_written == old_count); - - packed_cell = packed_cell_new(); - channel_write_packed_cell(ch, packed_cell); - packed_cell = NULL; - tt_assert(test_cells_written == old_count); - - done: - free_fake_channel(ch); - tor_free(var_cell); - tor_free(cell); - packed_cell_free(packed_cell); - return; -} - -static void test_channel_id_map(void *arg) { (void)arg; @@ -1879,19 +1108,449 @@ test_channel_id_map(void *arg) #undef N_CHAN } +static void +test_channel_state(void *arg) +{ + (void) arg; + + /* Test state validity. */ + tt_int_op(channel_state_is_valid(CHANNEL_STATE_CLOSED), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_CLOSING), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_OPEN), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_OPENING), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_MAINT), OP_EQ, 1); + tt_int_op(channel_state_is_valid(CHANNEL_STATE_LAST), OP_EQ, 0); + tt_int_op(channel_state_is_valid(INT_MAX), OP_EQ, 0); + + /* Test listener state validity. */ + tt_int_op(channel_listener_state_is_valid(CHANNEL_LISTENER_STATE_CLOSED), + OP_EQ, 1); + tt_int_op(channel_listener_state_is_valid(CHANNEL_LISTENER_STATE_LISTENING), + OP_EQ, 1); + tt_int_op(channel_listener_state_is_valid(CHANNEL_LISTENER_STATE_CLOSING), + OP_EQ, 1); + tt_int_op(channel_listener_state_is_valid(CHANNEL_LISTENER_STATE_ERROR), + OP_EQ, 1); + tt_int_op(channel_listener_state_is_valid(CHANNEL_LISTENER_STATE_LAST), + OP_EQ, 0); + tt_int_op(channel_listener_state_is_valid(INT_MAX), OP_EQ, 0); + + /* Test state transition. */ + tt_int_op(channel_state_can_transition(CHANNEL_STATE_CLOSED, + CHANNEL_STATE_OPENING), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_CLOSED, + CHANNEL_STATE_ERROR), OP_EQ, 0); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_CLOSING, + CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_CLOSING, + CHANNEL_STATE_CLOSED), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_CLOSING, + CHANNEL_STATE_OPEN), OP_EQ, 0); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_MAINT, + CHANNEL_STATE_CLOSING), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_MAINT, + CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_MAINT, + CHANNEL_STATE_OPEN), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_MAINT, + CHANNEL_STATE_OPENING), OP_EQ, 0); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPENING, + CHANNEL_STATE_OPEN), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPENING, + CHANNEL_STATE_CLOSING), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPENING, + CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPEN, + CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPEN, + CHANNEL_STATE_CLOSING), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPEN, + CHANNEL_STATE_ERROR), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_OPEN, + CHANNEL_STATE_MAINT), OP_EQ, 1); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_LAST, + CHANNEL_STATE_MAINT), OP_EQ, 0); + tt_int_op(channel_state_can_transition(CHANNEL_STATE_LAST, INT_MAX), + OP_EQ, 0); + + /* Test listener state transition. */ + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_CLOSED, + CHANNEL_LISTENER_STATE_LISTENING), + OP_EQ, 1); + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_CLOSED, + CHANNEL_LISTENER_STATE_ERROR), + OP_EQ, 0); + + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_CLOSING, + CHANNEL_LISTENER_STATE_CLOSED), + OP_EQ, 1); + + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_CLOSING, + CHANNEL_LISTENER_STATE_ERROR), + OP_EQ, 1); + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_ERROR, + CHANNEL_LISTENER_STATE_CLOSING), + OP_EQ, 0); + + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_LISTENING, + CHANNEL_LISTENER_STATE_CLOSING), + OP_EQ, 1); + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_LISTENING, + CHANNEL_LISTENER_STATE_ERROR), + OP_EQ, 1); + tt_int_op(channel_listener_state_can_transition( + CHANNEL_LISTENER_STATE_LAST, + INT_MAX), + OP_EQ, 0); + + /* Test state string. */ + tt_str_op(channel_state_to_string(CHANNEL_STATE_CLOSING), OP_EQ, + "closing"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_ERROR), OP_EQ, + "channel error"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_CLOSED), OP_EQ, + "closed"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_OPEN), OP_EQ, + "open"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_OPENING), OP_EQ, + "opening"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_MAINT), OP_EQ, + "temporarily suspended for maintenance"); + tt_str_op(channel_state_to_string(CHANNEL_STATE_LAST), OP_EQ, + "unknown or invalid channel state"); + tt_str_op(channel_state_to_string(INT_MAX), OP_EQ, + "unknown or invalid channel state"); + + /* Test listener state string. */ + tt_str_op(channel_listener_state_to_string(CHANNEL_LISTENER_STATE_CLOSING), + OP_EQ, "closing"); + tt_str_op(channel_listener_state_to_string(CHANNEL_LISTENER_STATE_ERROR), + OP_EQ, "channel listener error"); + tt_str_op(channel_listener_state_to_string(CHANNEL_LISTENER_STATE_LISTENING), + OP_EQ, "listening"); + tt_str_op(channel_listener_state_to_string(CHANNEL_LISTENER_STATE_LAST), + OP_EQ, "unknown or invalid channel listener state"); + tt_str_op(channel_listener_state_to_string(INT_MAX), + OP_EQ, "unknown or invalid channel listener state"); + + done: + ; +} + +static networkstatus_t *mock_ns = NULL; + +static networkstatus_t * +mock_networkstatus_get_latest_consensus(void) +{ + return mock_ns; +} + +static void +test_channel_duplicates(void *arg) +{ + channel_t *chan = NULL; + routerstatus_t rs; + + (void) arg; + + setup_full_capture_of_logs(LOG_INFO); + /* Try a flat call with channel nor connections. */ + channel_check_for_duplicates(); + expect_log_msg_containing( + "Found 0 connections to 0 relays. Found 0 current canonical " + "connections, in 0 of which we were a non-canonical peer. " + "0 relays had more than 1 connection, 0 had more than 2, and " + "0 had more than 4 connections."); + + mock_ns = tor_malloc_zero(sizeof(*mock_ns)); + mock_ns->routerstatus_list = smartlist_new(); + MOCK(networkstatus_get_latest_consensus, + mock_networkstatus_get_latest_consensus); + + chan = new_fake_channel(); + tt_assert(chan); + chan->is_canonical = test_chan_is_canonical; + memset(chan->identity_digest, 'A', sizeof(chan->identity_digest)); + channel_add_to_digest_map(chan); + tt_ptr_op(channel_find_by_remote_identity(chan->identity_digest, NULL), + OP_EQ, chan); + + /* No relay has been associated with this channel. */ + channel_check_for_duplicates(); + expect_log_msg_containing( + "Found 0 connections to 0 relays. Found 0 current canonical " + "connections, in 0 of which we were a non-canonical peer. " + "0 relays had more than 1 connection, 0 had more than 2, and " + "0 had more than 4 connections."); + + /* Associate relay to this connection in the consensus. */ + memset(&rs, 0, sizeof(rs)); + memset(rs.identity_digest, 'A', sizeof(rs.identity_digest)); + smartlist_add(mock_ns->routerstatus_list, &rs); + + /* Non opened channel. */ + chan->state = CHANNEL_STATE_CLOSING; + channel_check_for_duplicates(); + expect_log_msg_containing( + "Found 0 connections to 0 relays. Found 0 current canonical " + "connections, in 0 of which we were a non-canonical peer. " + "0 relays had more than 1 connection, 0 had more than 2, and " + "0 had more than 4 connections."); + chan->state = CHANNEL_STATE_OPEN; + + channel_check_for_duplicates(); + expect_log_msg_containing( + "Found 1 connections to 1 relays. Found 0 current canonical " + "connections, in 0 of which we were a non-canonical peer. " + "0 relays had more than 1 connection, 0 had more than 2, and " + "0 had more than 4 connections."); + + test_chan_should_be_canonical = 1; + channel_check_for_duplicates(); + expect_log_msg_containing( + "Found 1 connections to 1 relays. Found 1 current canonical " + "connections, in 1 of which we were a non-canonical peer. " + "0 relays had more than 1 connection, 0 had more than 2, and " + "0 had more than 4 connections."); + teardown_capture_of_logs(); + + done: + free_fake_channel(chan); + smartlist_clear(mock_ns->routerstatus_list); + networkstatus_vote_free(mock_ns); + UNMOCK(networkstatus_get_latest_consensus); +} + +static void +test_channel_for_extend(void *arg) +{ + channel_t *chan1 = NULL, *chan2 = NULL; + channel_t *ret_chan = NULL; + char digest[DIGEST_LEN]; + ed25519_public_key_t ed_id; + tor_addr_t addr; + const char *msg; + int launch; + time_t now = time(NULL); + + (void) arg; + + memset(digest, 'A', sizeof(digest)); + memset(&ed_id, 'B', sizeof(ed_id)); + + chan1 = new_fake_channel(); + tt_assert(chan1); + /* Need to be registered to get added to the id map. */ + channel_register(chan1); + tt_int_op(chan1->registered, OP_EQ, 1); + /* We need those for the test. */ + chan1->is_canonical = test_chan_is_canonical; + chan1->matches_target = test_chan_matches_target; + chan1->timestamp_created = now - 9; + + chan2 = new_fake_channel(); + tt_assert(chan2); + /* Need to be registered to get added to the id map. */ + channel_register(chan2); + tt_int_op(chan2->registered, OP_EQ, 1); + /* We need those for the test. */ + chan2->is_canonical = test_chan_is_canonical; + chan2->matches_target = test_chan_matches_target; + /* Make it older than chan1. */ + chan2->timestamp_created = chan1->timestamp_created - 1; + + /* Set channel identities and add it to the channel map. The last one to be + * added is made the first one in the list so the lookup will always return + * that one first. */ + channel_set_identity_digest(chan2, digest, &ed_id); + channel_set_identity_digest(chan1, digest, &ed_id); + tt_ptr_op(channel_find_by_remote_identity(digest, NULL), OP_EQ, chan1); + tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1); + + /* The expected result is chan2 because it is older than chan1. */ + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan2); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + + /* Switch that around from previous test. */ + chan2->timestamp_created = chan1->timestamp_created + 1; + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan1); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + + /* Same creation time, num circuits will be used and they both have 0 so the + * channel 2 should be picked due to how channel_is_better() work. */ + chan2->timestamp_created = chan1->timestamp_created; + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan1); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + + /* For the rest of the tests, we need channel 1 to be the older. */ + chan2->timestamp_created = chan1->timestamp_created + 1; + + /* Condemned the older channel. */ + chan1->state = CHANNEL_STATE_CLOSING; + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan2); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + chan1->state = CHANNEL_STATE_OPEN; + + /* Make the older channel a client one. */ + channel_mark_client(chan1); + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan2); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + channel_clear_client(chan1); + + /* Non matching ed identity with valid digest. */ + ed25519_public_key_t dumb_ed_id; + memset(&dumb_ed_id, 0, sizeof(dumb_ed_id)); + ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg, + &launch); + tt_assert(!ret_chan); + tt_str_op(msg, OP_EQ, "Not connected. Connecting."); + tt_int_op(launch, OP_EQ, 1); + + /* Opening channel, we'll check if the target address matches. */ + test_chan_should_match_target = 1; + chan1->state = CHANNEL_STATE_OPENING; + chan2->state = CHANNEL_STATE_OPENING; + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(!ret_chan); + tt_str_op(msg, OP_EQ, "Connection in progress; waiting."); + tt_int_op(launch, OP_EQ, 0); + chan1->state = CHANNEL_STATE_OPEN; + chan2->state = CHANNEL_STATE_OPEN; + + /* Mark channel 1 as bad for circuits. */ + channel_mark_bad_for_new_circs(chan1); + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(ret_chan); + tt_ptr_op(ret_chan, OP_EQ, chan2); + tt_int_op(launch, OP_EQ, 0); + tt_str_op(msg, OP_EQ, "Connection is fine; using it."); + chan1->is_bad_for_new_circs = 0; + + /* Mark both channels as unusable. */ + channel_mark_bad_for_new_circs(chan1); + channel_mark_bad_for_new_circs(chan2); + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(!ret_chan); + tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. " + " Launching a new one."); + tt_int_op(launch, OP_EQ, 1); + chan1->is_bad_for_new_circs = 0; + chan2->is_bad_for_new_circs = 0; + + /* Non canonical channels. */ + test_chan_should_match_target = 0; + test_chan_canonical_should_be_reliable = 1; + ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); + tt_assert(!ret_chan); + tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. " + " Launching a new one."); + tt_int_op(launch, OP_EQ, 1); + + done: + free_fake_channel(chan1); + free_fake_channel(chan2); +} + +static void +test_channel_listener(void *arg) +{ + int old_count; + time_t now = time(NULL); + channel_listener_t *chan = NULL; + + (void) arg; + + chan = tor_malloc_zero(sizeof(*chan)); + tt_assert(chan); + channel_init_listener(chan); + tt_u64_op(chan->global_identifier, OP_EQ, 1); + tt_int_op(chan->timestamp_created, OP_GE, now); + chan->close = test_chan_listener_close; + + /* Register it. At this point, it is not open so it will be put in the + * finished list. */ + channel_listener_register(chan); + tt_int_op(chan->registered, OP_EQ, 1); + channel_listener_unregister(chan); + + /* Register it as listening now thus active. */ + chan->state = CHANNEL_LISTENER_STATE_LISTENING; + channel_listener_register(chan); + tt_int_op(chan->registered, OP_EQ, 1); + + /* Set the listener function. */ + channel_listener_set_listener_fn(chan, test_chan_listener_fn); + tt_ptr_op(chan->listener, OP_EQ, test_chan_listener_fn); + + /* Put a channel in the listener incoming list and queue it. + * function. By doing this, the listener() handler will be called. */ + channel_t *in_chan = new_fake_channel(); + old_count = test_chan_listener_fn_called; + channel_listener_queue_incoming(chan, in_chan); + free_fake_channel(in_chan); + tt_int_op(test_chan_listener_fn_called, OP_EQ, old_count + 1); + + /* Put listener channel in CLOSING state. */ + old_count = test_chan_listener_close_fn_called; + channel_listener_mark_for_close(chan); + tt_int_op(test_chan_listener_close_fn_called, OP_EQ, old_count + 1); + channel_listener_change_state(chan, CHANNEL_LISTENER_STATE_CLOSED); + + /* Dump stats so we at least hit the code path. */ + chan->describe_transport = test_chan_listener_describe_transport; + /* There is a check for "now > timestamp_created" when dumping the stats so + * make sure we go in. */ + chan->timestamp_created = now - 10; + channel_listener_dump_statistics(chan, LOG_INFO); + + done: + channel_free_all(); +} + struct testcase_t channel_tests[] = { - { "dumpstats", test_channel_dumpstats, TT_FORK, NULL, NULL }, - { "flush", test_channel_flush, TT_FORK, NULL, NULL }, - { "flushmux", test_channel_flushmux, TT_FORK, NULL, NULL }, - { "incoming", test_channel_incoming, TT_FORK, NULL, NULL }, - { "lifecycle", test_channel_lifecycle, TT_FORK, NULL, NULL }, - { "lifecycle_2", test_channel_lifecycle_2, TT_FORK, NULL, NULL }, - { "multi", test_channel_multi, TT_FORK, NULL, NULL }, - { "queue_impossible", test_channel_queue_impossible, TT_FORK, NULL, NULL }, - { "queue_incoming", test_channel_queue_incoming, TT_FORK, NULL, NULL }, - { "queue_size", test_channel_queue_size, TT_FORK, NULL, NULL }, - { "write", test_channel_write, TT_FORK, NULL, NULL }, - { "id_map", test_channel_id_map, TT_FORK, NULL, NULL }, + { "inbound_cell", test_channel_inbound_cell, TT_FORK, + NULL, NULL }, + { "outbound_cell", test_channel_outbound_cell, TT_FORK, + NULL, NULL }, + { "id_map", test_channel_id_map, TT_FORK, + NULL, NULL }, + { "lifecycle", test_channel_lifecycle, TT_FORK, + NULL, NULL }, + { "lifecycle_2", test_channel_lifecycle_2, TT_FORK, + NULL, NULL }, + { "dumpstats", test_channel_dumpstats, TT_FORK, + NULL, NULL }, + { "state", test_channel_state, TT_FORK, + NULL, NULL }, + { "duplicates", test_channel_duplicates, TT_FORK, + NULL, NULL }, + { "get_channel_for_extend", test_channel_for_extend, TT_FORK, + NULL, NULL }, + { "listener", test_channel_listener, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c index d5713688a0..4cc33cbe70 100644 --- a/src/test/test_channelpadding.c +++ b/src/test/test_channelpadding.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #define TOR_CHANNEL_INTERNAL_ #define MAIN_PRIVATE #define NETWORKSTATUS_PRIVATE @@ -276,7 +279,6 @@ test_channelpadding_timers(void *arg) { channelpadding_decision_t decision; channel_t *chans[CHANNELS_TO_TEST]; - int64_t new_time; (void)arg; tor_libevent_postfork(); @@ -286,8 +288,9 @@ test_channelpadding_timers(void *arg) monotime_init(); monotime_enable_test_mocking(); - monotime_set_mock_time_nsec(1); - monotime_coarse_set_mock_time_nsec(1); + uint64_t nsec_mock = 1; + monotime_set_mock_time_nsec(nsec_mock); + monotime_coarse_set_mock_time_nsec(nsec_mock); timers_initialize(); channelpadding_new_consensus_params(NULL); @@ -301,11 +304,14 @@ test_channelpadding_timers(void *arg) tried_to_write_cell = 0; int i = 0; + monotime_coarse_t now; + monotime_coarse_get(&now); + /* This loop fills our timerslot array with timers of increasing time * until they fire */ for (; i < CHANNELPADDING_MAX_TIMERS; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() - + 10 + i*4; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 10 + i*4); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -315,7 +321,8 @@ test_channelpadding_timers(void *arg) /* This loop should add timers to the first position in the timerslot * array, since its timeout is before all other timers. */ for (; i < CHANNELS_TO_TEST/3; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 1; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 1); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -326,8 +333,8 @@ test_channelpadding_timers(void *arg) * pseudorandom pattern. It ensures that the lists can grow with multiple * timers in them. */ for (; i < CHANNELS_TO_TEST/2; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 10 + - i*3 % CHANNELPADDING_MAX_TIMERS; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 10 + i*3 % CHANNELPADDING_MAX_TIMERS); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -337,8 +344,8 @@ test_channelpadding_timers(void *arg) /* This loop should add timers to the last position in the timerslot * array, since its timeout is after all other timers. */ for (; i < CHANNELS_TO_TEST; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 500 + - i % CHANNELPADDING_MAX_TIMERS; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 500 + i % CHANNELPADDING_MAX_TIMERS); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -346,9 +353,9 @@ test_channelpadding_timers(void *arg) } // Wait for the timers and then kill the event loop. - new_time = (monotime_coarse_absolute_msec()+1001)*NSEC_PER_MSEC; - monotime_coarse_set_mock_time_nsec(new_time); - monotime_set_mock_time_nsec(new_time); + nsec_mock += 1001 * NSEC_PER_MSEC; + monotime_coarse_set_mock_time_nsec(nsec_mock); + monotime_set_mock_time_nsec(nsec_mock); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, CHANNELS_TO_TEST); @@ -385,6 +392,7 @@ test_channelpadding_killonehop(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; timers_initialize(); setup_mock_consensus(); @@ -398,9 +406,12 @@ test_channelpadding_killonehop(void *arg) smartlist_clear(current_md_consensus->net_params); channelpadding_new_consensus_params(current_md_consensus); + monotime_coarse_t now; + monotime_coarse_get(&now); + tried_to_write_cell = 0; get_options_mutable()->Tor2webMode = 1; - client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&client_relay3->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(client_relay3->pending_padding_callback); @@ -410,9 +421,10 @@ test_channelpadding_killonehop(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -424,7 +436,7 @@ test_channelpadding_killonehop(void *arg) // Before the client tries to pad, the relay will still pad: tried_to_write_cell = 0; - relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&relay3_client->next_padding_time, &now, 100); get_options_mutable()->ORPort_set = 1; get_options_mutable()->Tor2webMode = 0; decision = channelpadding_decide_to_pad_channel(relay3_client); @@ -432,9 +444,10 @@ test_channelpadding_killonehop(void *arg) tt_assert(relay3_client->pending_padding_callback); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -471,7 +484,8 @@ test_channelpadding_killonehop(void *arg) get_options_mutable()->ORPort_set = 0; get_options_mutable()->HiddenServiceSingleHopMode = 1; get_options_mutable()->HiddenServiceNonAnonymousMode = 1; - client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + + monotime_coarse_add_msec(&client_relay3->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(client_relay3->pending_padding_callback); @@ -481,9 +495,10 @@ test_channelpadding_killonehop(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101 * NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -495,7 +510,7 @@ test_channelpadding_killonehop(void *arg) // Before the client tries to pad, the relay will still pad: tried_to_write_cell = 0; - relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&relay3_client->next_padding_time, &now, 100); get_options_mutable()->ORPort_set = 1; get_options_mutable()->HiddenServiceSingleHopMode = 0; get_options_mutable()->HiddenServiceNonAnonymousMode = 0; @@ -504,9 +519,10 @@ test_channelpadding_killonehop(void *arg) tt_assert(relay3_client->pending_padding_callback); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101 * NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -570,6 +586,9 @@ test_channelpadding_consensus(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; + monotime_coarse_t now; + monotime_coarse_get(&now); timers_initialize(); if (!connection_array) @@ -583,7 +602,7 @@ test_channelpadding_consensus(void *arg) /* Test 1: Padding can be completely disabled via consensus */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -593,9 +612,10 @@ test_channelpadding_consensus(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); @@ -625,7 +645,7 @@ test_channelpadding_consensus(void *arg) tt_i64_op(val, OP_EQ, 0); val = channelpadding_compute_time_until_pad_for_netflow(chan); tt_i64_op(val, OP_EQ, -2); - tt_assert(!chan->next_padding_time_ms); + tt_assert(monotime_coarse_is_zero(&chan->next_padding_time)); smartlist_clear(current_md_consensus->net_params); @@ -638,7 +658,7 @@ test_channelpadding_consensus(void *arg) channelpadding_new_consensus_params(current_md_consensus); tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -650,9 +670,10 @@ test_channelpadding_consensus(void *arg) tt_i64_op(val, OP_LE, 200); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+201)*NSEC_PER_MSEC; + new_time += 201*NSEC_PER_MSEC; monotime_set_mock_time_nsec(new_time); monotime_coarse_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); @@ -941,6 +962,9 @@ test_channelpadding_decide_to_pad_channel(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; + monotime_coarse_t now; + monotime_coarse_get(&now); timers_initialize(); setup_full_capture_of_logs(LOG_WARN); channelpadding_new_consensus_params(NULL); @@ -957,7 +981,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2a: > 1.1s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1200; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 1200); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER); tt_assert(!chan->pending_padding_callback); @@ -965,23 +989,27 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2b: >= 1.0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1000; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 1000); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); tt_int_op(tried_to_write_cell, OP_EQ, 0); + // Set up a timer for the <0 case below. + monotime_coarse_t now_minus_100s; + monotime_coarse_add_msec(&now_minus_100s, &now, 900); // Wait for the timer from case #2b - new_time = (monotime_coarse_absolute_msec() + 1000)*NSEC_PER_MSEC; + new_time += 1000*NSEC_PER_MSEC; monotime_set_mock_time_nsec(new_time); monotime_coarse_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); /* Test case #2c: > 0.1s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -992,16 +1020,17 @@ test_channelpadding_decide_to_pad_channel(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); /* Test case #2e: 0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec(); + monotime_coarse_add_msec(&chan->next_padding_time, &now, 0); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1009,7 +1038,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2f: <0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() - 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now_minus_100s, 0); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1017,7 +1046,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #3: Channel that sends a packet while timeout is scheduled */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1028,9 +1057,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) // We don't expect any timer callbacks here. Make a dummy one to be sure. // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1038,7 +1068,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #4: Channel that closes while a timeout is scheduled */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1048,9 +1078,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) chan->state = CHANNEL_STATE_MAINT; // We don't expect any timer callbacks here. Make a dummy one to be sure. - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1059,16 +1090,17 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #5: Make sure previous test case didn't break everything */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); tt_int_op(tried_to_write_cell, OP_EQ, 0); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1087,7 +1119,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) * It must be last. */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1097,9 +1129,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) free_fake_channeltls((channel_tls_t*)chan); // We don't expect any timer callbacks here. Make a dummy one to be sure. - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time = 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index f622704ec5..d170009a9c 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -141,7 +141,7 @@ test_clist_maps(void *arg) /* Okay, now free ch2 and make sure that the circuit ID is STILL not * usable, because we haven't declared the destroy to be nonpending */ tt_int_op(cdm.ncalls, OP_EQ, 0); - circuit_free(TO_CIRCUIT(or_c2)); + circuit_free_(TO_CIRCUIT(or_c2)); or_c2 = NULL; /* prevent free */ tt_int_op(cdm.ncalls, OP_EQ, 2); memset(&cdm, 0, sizeof(cdm)); @@ -160,9 +160,9 @@ test_clist_maps(void *arg) done: if (or_c1) - circuit_free(TO_CIRCUIT(or_c1)); + circuit_free_(TO_CIRCUIT(or_c1)); if (or_c2) - circuit_free(TO_CIRCUIT(or_c2)); + circuit_free_(TO_CIRCUIT(or_c2)); if (ch1) tor_free(ch1->cmux); if (ch2) @@ -234,11 +234,11 @@ test_rend_token_maps(void *arg) /* Marking a circuit makes it not get returned any more */ circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED); tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); - circuit_free(TO_CIRCUIT(c1)); + circuit_free_(TO_CIRCUIT(c1)); c1 = NULL; /* Freeing a circuit makes it not get returned any more. */ - circuit_free(TO_CIRCUIT(c2)); + circuit_free_(TO_CIRCUIT(c2)); c2 = NULL; tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); @@ -275,15 +275,15 @@ test_rend_token_maps(void *arg) done: if (c1) - circuit_free(TO_CIRCUIT(c1)); + circuit_free_(TO_CIRCUIT(c1)); if (c2) - circuit_free(TO_CIRCUIT(c2)); + circuit_free_(TO_CIRCUIT(c2)); if (c3) - circuit_free(TO_CIRCUIT(c3)); + circuit_free_(TO_CIRCUIT(c3)); if (c4) - circuit_free(TO_CIRCUIT(c4)); + circuit_free_(TO_CIRCUIT(c4)); if (c5) - circuit_free(TO_CIRCUIT(c5)); + circuit_free_(TO_CIRCUIT(c5)); } static void @@ -452,10 +452,10 @@ test_hs_circuitmap_isolation(void *arg) } done: - circuit_free(TO_CIRCUIT(circ1)); - circuit_free(TO_CIRCUIT(circ2)); - circuit_free(TO_CIRCUIT(circ3)); - circuit_free(TO_CIRCUIT(circ4)); + circuit_free_(TO_CIRCUIT(circ1)); + circuit_free_(TO_CIRCUIT(circ2)); + circuit_free_(TO_CIRCUIT(circ3)); + circuit_free_(TO_CIRCUIT(circ4)); } struct testcase_t circuitlist_tests[] = { diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c new file mode 100644 index 0000000000..9d87c325b4 --- /dev/null +++ b/src/test/test_circuitstats.c @@ -0,0 +1,199 @@ +/* Copyright (c) 2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CIRCUITBUILD_PRIVATE +#define CIRCUITSTATS_PRIVATE +#define CIRCUITLIST_PRIVATE +#define CHANNEL_PRIVATE_ + +#include "or.h" +#include "test.h" +#include "test_helpers.h" +#include "log_test_helpers.h" +#include "config.h" +#include "circuitlist.h" +#include "circuitbuild.h" +#include "circuitstats.h" +#include "circuituse.h" +#include "channel.h" + +void test_circuitstats_timeout(void *arg); +void test_circuitstats_hoplen(void *arg); +origin_circuit_t *subtest_fourhop_circuit(struct timeval, int); +origin_circuit_t *add_opened_threehop(void); +origin_circuit_t *build_unopened_fourhop(struct timeval); + +int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); + +static int marked_for_close; +/* Mock function because we are not trying to test the close circuit that does + * an awful lot of checks on the circuit object. */ +static void +mock_circuit_mark_for_close(circuit_t *circ, int reason, int line, + const char *file) +{ + (void) circ; + (void) reason; + (void) line; + (void) file; + marked_for_close = 1; + return; +} + +origin_circuit_t * +add_opened_threehop(void) +{ + origin_circuit_t *or_circ = origin_circuit_new(); + extend_info_t fakehop; + memset(&fakehop, 0, sizeof(fakehop)); + + TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + or_circ->build_state->desired_path_len = DEFAULT_ROUTE_LEN; + + onion_append_hop(&or_circ->cpath, &fakehop); + onion_append_hop(&or_circ->cpath, &fakehop); + onion_append_hop(&or_circ->cpath, &fakehop); + + or_circ->has_opened = 1; + TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; + TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + return or_circ; +} + +origin_circuit_t * +build_unopened_fourhop(struct timeval circ_start_time) +{ + origin_circuit_t *or_circ = origin_circuit_new(); + extend_info_t *fakehop = tor_malloc_zero(sizeof(extend_info_t)); + memset(fakehop, 0, sizeof(extend_info_t)); + + TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + TO_CIRCUIT(or_circ)->timestamp_began = circ_start_time; + TO_CIRCUIT(or_circ)->timestamp_created = circ_start_time; + + or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + or_circ->build_state->desired_path_len = 4; + + onion_append_hop(&or_circ->cpath, fakehop); + onion_append_hop(&or_circ->cpath, fakehop); + onion_append_hop(&or_circ->cpath, fakehop); + onion_append_hop(&or_circ->cpath, fakehop); + + return or_circ; +} + +origin_circuit_t * +subtest_fourhop_circuit(struct timeval circ_start_time, int should_timeout) +{ + origin_circuit_t *or_circ = build_unopened_fourhop(circ_start_time); + + // Now make them open one at a time and call + // circuit_build_times_handle_completed_hop(); + or_circ->cpath->state = CPATH_STATE_OPEN; + circuit_build_times_handle_completed_hop(or_circ); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0); + + or_circ->cpath->next->state = CPATH_STATE_OPEN; + circuit_build_times_handle_completed_hop(or_circ); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0); + + // Third hop: We should count it now. + or_circ->cpath->next->next->state = CPATH_STATE_OPEN; + circuit_build_times_handle_completed_hop(or_circ); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, + !should_timeout); // 1 if counted, 0 otherwise + + // Fourth hop: Don't double count + or_circ->cpath->next->next->next->state = CPATH_STATE_OPEN; + circuit_build_times_handle_completed_hop(or_circ); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, + !should_timeout); + + done: + return or_circ; +} + +void +test_circuitstats_hoplen(void *arg) +{ + /* Plan: + * 0. Test no other opened circs (relaxed timeout) + * 1. Check >3 hop circ building w/o timeout + * 2. Check >3 hop circs w/ timeouts.. + */ + struct timeval circ_start_time; + origin_circuit_t *threehop = NULL; + origin_circuit_t *fourhop = NULL; + (void)arg; + MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close); + + circuit_build_times_init(get_circuit_build_times_mutable()); + + // Let's set a close_ms to 2X the initial timeout, so we can + // test relaxed functionality (which uses the close_ms timeout) + get_circuit_build_times_mutable()->close_ms *= 2; + + tor_gettimeofday(&circ_start_time); + circ_start_time.tv_sec -= 119; // make us hit "relaxed" cutoff + + // Test 1: Build a fourhop circuit that should get marked + // as relaxed and eventually counted by circuit_expire_building + // (but not before) + fourhop = subtest_fourhop_circuit(circ_start_time, 0); + tt_int_op(fourhop->relaxed_timeout, OP_EQ, 0); + tt_int_op(marked_for_close, OP_EQ, 0); + circuit_expire_building(); + tt_int_op(marked_for_close, OP_EQ, 0); + tt_int_op(fourhop->relaxed_timeout, OP_EQ, 1); + TO_CIRCUIT(fourhop)->timestamp_began.tv_sec -= 119; + circuit_expire_building(); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1); + tt_int_op(marked_for_close, OP_EQ, 1); + + circuit_free_(TO_CIRCUIT(fourhop)); + circuit_build_times_reset(get_circuit_build_times_mutable()); + + // Test 2: Add a threehop circuit for non-relaxed timeouts + threehop = add_opened_threehop(); + + /* This circuit should not timeout */ + tor_gettimeofday(&circ_start_time); + circ_start_time.tv_sec -= 59; + fourhop = subtest_fourhop_circuit(circ_start_time, 0); + circuit_expire_building(); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1); + tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_NE, + CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT); + + circuit_free_((circuit_t *)fourhop); + circuit_build_times_reset(get_circuit_build_times_mutable()); + + /* Test 3: This circuit should now time out and get marked as a + * measurement circuit, but still get counted (and counted only once) + */ + circ_start_time.tv_sec -= 2; + fourhop = subtest_fourhop_circuit(circ_start_time, 0); + tt_int_op(TO_CIRCUIT(fourhop)->purpose, OP_EQ, + CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1); + circuit_expire_building(); + tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 1); + + done: + UNMOCK(circuit_mark_for_close_); + circuit_free_(TO_CIRCUIT(threehop)); + circuit_free_(TO_CIRCUIT(fourhop)); + circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); +} + +#define TEST_CIRCUITSTATS(name, flags) \ + { #name, test_##name, (flags), NULL, NULL } + +struct testcase_t circuitstats_tests[] = { + TEST_CIRCUITSTATS(circuitstats_hoplen, TT_FORK), + END_OF_TESTCASES +}; + diff --git a/src/test/test_config.c b/src/test/test_config.c index e7380c1d14..4290d0dc6d 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -4833,7 +4833,7 @@ test_config_include_limit(void *data) torrc_path); tt_int_op(write_str_to_file(torrc_path, torrc_contents, 0), OP_EQ, 0); - tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL), + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL), OP_EQ, -1); done: @@ -4863,7 +4863,7 @@ test_config_include_does_not_exist(void *data) tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s", missing_path); - tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL), + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL), OP_EQ, -1); done: @@ -4895,7 +4895,7 @@ test_config_include_error_in_included_file(void *data) tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s", invalid_path); - tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL), + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL), OP_EQ, -1); done: @@ -4937,8 +4937,8 @@ test_config_include_empty_file_folder(void *data) folder_path, file_path); int include_used; - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used, + NULL), OP_EQ, 0); tt_ptr_op(result, OP_EQ, NULL); tt_int_op(include_used, OP_EQ, 1); @@ -4975,7 +4975,8 @@ test_config_include_no_permission(void *data) folder_path); int include_used; - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, + &include_used, NULL), OP_EQ, -1); tt_ptr_op(result, OP_EQ, NULL); @@ -5031,8 +5032,8 @@ test_config_include_recursion_before_after(void *data) } int include_used; - tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used, + NULL), OP_EQ, 0); tt_ptr_op(result, OP_NE, NULL); tt_int_op(include_used, OP_EQ, 1); @@ -5096,8 +5097,8 @@ test_config_include_recursion_after_only(void *data) } int include_used; - tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used, + NULL), OP_EQ, 0); tt_ptr_op(result, OP_NE, NULL); tt_int_op(include_used, OP_EQ, 1); @@ -5185,8 +5186,8 @@ test_config_include_folder_order(void *data) torrcd); int include_used; - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used, + NULL), OP_EQ, 0); tt_ptr_op(result, OP_NE, NULL); tt_int_op(include_used, OP_EQ, 1); @@ -5239,8 +5240,8 @@ test_config_include_path_syntax(void *data) esc_dir_with_pathsep); int include_used; - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used, + NULL), OP_EQ, 0); tt_ptr_op(result, OP_EQ, NULL); tt_int_op(include_used, OP_EQ, 1); @@ -5294,14 +5295,14 @@ test_config_include_has_include(void *data) char torrc_contents[1000] = "Test 1\n"; int include_used; - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used, + NULL), OP_EQ, 0); tt_int_op(include_used, OP_EQ, 0); config_free_lines(result); tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s\n", dir); - tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used), - OP_EQ, 0); + tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used, + NULL), OP_EQ, 0); tt_int_op(include_used, OP_EQ, 1); done: @@ -5516,6 +5517,85 @@ test_config_check_bridge_distribution_setting_unrecognised(void *arg) return; } +static void +test_config_include_opened_file_list(void *data) +{ + (void)data; + + config_line_t *result = NULL; + smartlist_t *opened_files = smartlist_new(); + char *dir = tor_strdup(get_fname("test_include_opened_file_list")); + tt_ptr_op(dir, OP_NE, NULL); + +#ifdef _WIN32 + tt_int_op(mkdir(dir), OP_EQ, 0); +#else + tt_int_op(mkdir(dir, 0700), OP_EQ, 0); +#endif + + char torrcd[PATH_MAX+1]; + tor_snprintf(torrcd, sizeof(torrcd), "%s"PATH_SEPARATOR"%s", dir, "torrc.d"); + +#ifdef _WIN32 + tt_int_op(mkdir(torrcd), OP_EQ, 0); +#else + tt_int_op(mkdir(torrcd, 0700), OP_EQ, 0); +#endif + + char subfolder[PATH_MAX+1]; + tor_snprintf(subfolder, sizeof(subfolder), "%s"PATH_SEPARATOR"%s", torrcd, + "subfolder"); + +#ifdef _WIN32 + tt_int_op(mkdir(subfolder), OP_EQ, 0); +#else + tt_int_op(mkdir(subfolder, 0700), OP_EQ, 0); +#endif + + char path[PATH_MAX+1]; + tor_snprintf(path, sizeof(path), "%s"PATH_SEPARATOR"%s", subfolder, + "01_file_in_subfolder"); + tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0); + + char empty[PATH_MAX+1]; + tor_snprintf(empty, sizeof(empty), "%s"PATH_SEPARATOR"%s", torrcd, "empty"); + tt_int_op(write_str_to_file(empty, "", 0), OP_EQ, 0); + + char file[PATH_MAX+1]; + tor_snprintf(file, sizeof(file), "%s"PATH_SEPARATOR"%s", torrcd, "file"); + tt_int_op(write_str_to_file(file, "Test 2\n", 0), OP_EQ, 0); + + char dot[PATH_MAX+1]; + tor_snprintf(dot, sizeof(dot), "%s"PATH_SEPARATOR"%s", torrcd, ".dot"); + tt_int_op(write_str_to_file(dot, "Test 3\n", 0), OP_EQ, 0); + + char torrc_contents[1000]; + tor_snprintf(torrc_contents, sizeof(torrc_contents), + "%%include %s\n", + torrcd); + + int include_used; + tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used, + opened_files), OP_EQ, 0); + tt_ptr_op(result, OP_NE, NULL); + tt_int_op(include_used, OP_EQ, 1); + + tt_int_op(smartlist_len(opened_files), OP_EQ, 4); + tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1); + tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1); + // files inside subfolders are not opended, only the subfolder is opened + tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1); + tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1); + // dot files are not opened as we ignore them when we get their name from + // their parent folder + + done: + SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f)); + smartlist_free(opened_files); + config_free_lines(result); + tor_free(dir); +} + #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } @@ -5563,6 +5643,7 @@ struct testcase_t config_tests[] = { CONFIG_TEST(check_bridge_distribution_setting_valid, 0), CONFIG_TEST(check_bridge_distribution_setting_invalid, 0), CONFIG_TEST(check_bridge_distribution_setting_unrecognised, 0), + CONFIG_TEST(include_opened_file_list, 0), END_OF_TESTCASES }; diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c index ddb1bc53c1..ffec3149b0 100644 --- a/src/test/test_conscache.c +++ b/src/test/test_conscache.c @@ -31,8 +31,8 @@ test_conscache_simple_usage(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); @@ -124,8 +124,8 @@ test_conscache_cleanup(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); @@ -267,8 +267,8 @@ test_conscache_filter(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c index 80d3f943ab..a9a4b6a98e 100644 --- a/src/test/test_consdiffmgr.c +++ b/src/test/test_consdiffmgr.c @@ -24,8 +24,8 @@ consdiffmgr_test_setup(const struct testcase_t *arg) { (void)arg; char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer. + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = ddir_fname; // now owns the pointer. check_private_dir(ddir_fname, CPD_CREATE, NULL); consdiff_cfg_t consdiff_cfg = { 300 }; @@ -215,8 +215,8 @@ test_consdiffmgr_init_failure(void *arg) /* As in ...test_setup, but do not create the datadir. The missing directory * will cause a failure. */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer. + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = ddir_fname; // now owns the pointer. consdiff_cfg_t consdiff_cfg = { 7200, 300 }; diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 472fcb8c53..af19f63f6c 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -6,6 +6,7 @@ #include "bridges.h" #include "control.h" #include "entrynodes.h" +#include "hs_common.h" #include "networkstatus.h" #include "rendservice.h" #include "routerlist.h" @@ -13,10 +14,87 @@ #include "test_helpers.h" static void -test_add_onion_helper_keyarg(void *arg) +test_add_onion_helper_keyarg_v3(void *arg) { - crypto_pk_t *pk = NULL; - crypto_pk_t *pk2 = NULL; + int ret, hs_version; + add_onion_secret_key_t pk; + char *key_new_blob = NULL; + char *err_msg = NULL; + const char *key_new_alg = NULL; + + (void) arg; + + memset(&pk, 0, sizeof(pk)); + + /* Test explicit ED25519-V3 key generation. */ + ret = add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg, + &key_new_blob, &pk, &hs_version, + &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE); + tt_assert(pk.v3); + tt_str_op(key_new_alg, OP_EQ, "ED25519-V3"); + tt_assert(key_new_blob); + tt_ptr_op(err_msg, OP_EQ, NULL); + tor_free(pk.v3); pk.v3 = NULL; + tor_free(key_new_blob); + + /* Test discarding the private key. */ + ret = add_onion_helper_keyarg("NEW:ED25519-V3", 1, &key_new_alg, + &key_new_blob, &pk, &hs_version, + &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE); + tt_assert(pk.v3); + tt_ptr_op(key_new_alg, OP_EQ, NULL); + tt_ptr_op(key_new_blob, OP_EQ, NULL); + tt_ptr_op(err_msg, OP_EQ, NULL); + tor_free(pk.v3); pk.v3 = NULL; + tor_free(key_new_blob); + + /* Test passing a key blob. */ + { + /* The base64 key and hex key are the same. Hex key is 64 bytes long. The + * sk has been generated randomly using python3. */ + const char *base64_sk = + "a9bT19PqGC9Y+BmOo1IQvCGjjwxMiaaxEXZ+FKMxpEQW" + "6AmSV5roThUGMRCaqQSCnR2jI1vL2QxHORzI4RxMmw=="; + const char *hex_sk = + "\x6b\xd6\xd3\xd7\xd3\xea\x18\x2f\x58\xf8\x19\x8e\xa3\x52\x10\xbc" + "\x21\xa3\x8f\x0c\x4c\x89\xa6\xb1\x11\x76\x7e\x14\xa3\x31\xa4\x44" + "\x16\xe8\x09\x92\x57\x9a\xe8\x4e\x15\x06\x31\x10\x9a\xa9\x04\x82" + "\x9d\x1d\xa3\x23\x5b\xcb\xd9\x0c\x47\x39\x1c\xc8\xe1\x1c\x4c\x9b"; + char *key_blob = NULL; + + tor_asprintf(&key_blob, "ED25519-V3:%s", base64_sk); + tt_assert(key_blob); + ret = add_onion_helper_keyarg(key_blob, 1, &key_new_alg, + &key_new_blob, &pk, &hs_version, + &err_msg); + tor_free(key_blob); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE); + tt_assert(pk.v3); + tt_mem_op(pk.v3, OP_EQ, hex_sk, 64); + tt_ptr_op(key_new_alg, OP_EQ, NULL); + tt_ptr_op(key_new_blob, OP_EQ, NULL); + tt_ptr_op(err_msg, OP_EQ, NULL); + tor_free(pk.v3); pk.v3 = NULL; + tor_free(key_new_blob); + } + + done: + tor_free(pk.v3); + tor_free(key_new_blob); + tor_free(err_msg); +} + +static void +test_add_onion_helper_keyarg_v2(void *arg) +{ + int ret, hs_version; + add_onion_secret_key_t pk; + crypto_pk_t *pk1 = NULL; const char *key_new_alg = NULL; char *key_new_blob = NULL; char *err_msg = NULL; @@ -25,83 +103,100 @@ test_add_onion_helper_keyarg(void *arg) (void) arg; + memset(&pk, 0, sizeof(pk)); + /* Test explicit RSA1024 key generation. */ - pk = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_assert(pk); + ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(pk.v2); tt_str_op(key_new_alg, OP_EQ, "RSA1024"); tt_assert(key_new_blob); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test "BEST" key generation (Assumes BEST = RSA1024). */ - crypto_pk_free(pk); + crypto_pk_free(pk.v2); pk.v2 = NULL; tor_free(key_new_blob); - pk = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_assert(pk); + ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(pk.v2); tt_str_op(key_new_alg, OP_EQ, "RSA1024"); tt_assert(key_new_blob); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test discarding the private key. */ - crypto_pk_free(pk); + crypto_pk_free(pk.v2); pk.v2 = NULL; tor_free(key_new_blob); - pk = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob, - &err_msg); - tt_assert(pk); + ret = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(pk.v2); tt_ptr_op(key_new_alg, OP_EQ, NULL); tt_ptr_op(key_new_blob, OP_EQ, NULL); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test generating a invalid key type. */ - crypto_pk_free(pk); - pk = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_ptr_op(pk, OP_EQ, NULL); + crypto_pk_free(pk.v2); pk.v2 = NULL; + ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, -1); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(!pk.v2); tt_ptr_op(key_new_alg, OP_EQ, NULL); tt_ptr_op(key_new_blob, OP_EQ, NULL); tt_assert(err_msg); /* Test loading a RSA1024 key. */ tor_free(err_msg); - pk = pk_generate(0); - tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk, &encoded)); + pk1 = pk_generate(0); + tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk1, &encoded)); tor_asprintf(&arg_str, "RSA1024:%s", encoded); - pk2 = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_assert(pk2); + ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(pk.v2); tt_ptr_op(key_new_alg, OP_EQ, NULL); tt_ptr_op(key_new_blob, OP_EQ, NULL); tt_ptr_op(err_msg, OP_EQ, NULL); - tt_int_op(crypto_pk_cmp_keys(pk, pk2), OP_EQ, 0); + tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0); /* Test loading a invalid key type. */ tor_free(arg_str); - crypto_pk_free(pk); pk = NULL; + crypto_pk_free(pk1); pk1 = NULL; + crypto_pk_free(pk.v2); pk.v2 = NULL; tor_asprintf(&arg_str, "RSA512:%s", encoded); - pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_ptr_op(pk, OP_EQ, NULL); + ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, -1); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(!pk.v2); tt_ptr_op(key_new_alg, OP_EQ, NULL); tt_ptr_op(key_new_blob, OP_EQ, NULL); tt_assert(err_msg); /* Test loading a invalid key. */ tor_free(arg_str); - crypto_pk_free(pk); pk = NULL; + crypto_pk_free(pk.v2); pk.v2 = NULL; tor_free(err_msg); encoded[strlen(encoded)/2] = '\0'; tor_asprintf(&arg_str, "RSA1024:%s", encoded); - pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &err_msg); - tt_ptr_op(pk, OP_EQ, NULL); + ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, &err_msg); + tt_int_op(ret, OP_EQ, -1); + tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); + tt_assert(!pk.v2); tt_ptr_op(key_new_alg, OP_EQ, NULL); tt_ptr_op(key_new_blob, OP_EQ, NULL); tt_assert(err_msg); done: - crypto_pk_free(pk); - crypto_pk_free(pk2); + crypto_pk_free(pk1); + crypto_pk_free(pk.v2); tor_free(key_new_blob); tor_free(err_msg); tor_free(encoded); @@ -1370,7 +1465,10 @@ test_download_status_bridge(void *arg) } struct testcase_t controller_tests[] = { - { "add_onion_helper_keyarg", test_add_onion_helper_keyarg, 0, NULL, NULL }, + { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, + NULL, NULL }, + { "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0, + NULL, NULL }, { "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL }, { "rend_service_parse_port_config", test_rend_service_parse_port_config, 0, NULL, NULL }, diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 997b110d62..6092a5a4d0 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -567,7 +567,7 @@ test_dir_routerinfo_parsing(void *arg) static void routerinfo_free_wrapper_(void *arg) { - routerinfo_free(arg); + routerinfo_free_(arg); } static void @@ -664,7 +664,7 @@ test_dir_extrainfo_parsing(void *arg) escaped(NULL); extrainfo_free(ei); routerinfo_free(ri); - digestmap_free((digestmap_t*)map, routerinfo_free_wrapper_); + digestmap_free_((digestmap_t*)map, routerinfo_free_wrapper_); } static void @@ -760,7 +760,7 @@ test_dir_parse_router_list(void *arg) smartlist_free(chunks); routerinfo_free(ri); if (map) { - digestmap_free((digestmap_t*)map, routerinfo_free_wrapper_); + digestmap_free_((digestmap_t*)map, routerinfo_free_wrapper_); router_get_routerlist()->identity_map = (struct digest_ri_map_t*)digestmap_new(); } @@ -4874,9 +4874,11 @@ mock_check_private_dir(const char *dirname, cpd_check_t check, static char * mock_get_datadir_fname(const or_options_t *options, + directory_root_t roottype, const char *sub1, const char *sub2, const char *suffix) { + (void) roottype; char *rv = NULL; /* @@ -5033,7 +5035,7 @@ test_dir_dump_unparseable_descriptors(void *data) mock_options->MaxUnparseableDescSizeToLog = 1536; MOCK(get_options, mock_get_options); MOCK(check_private_dir, mock_check_private_dir); - MOCK(options_get_datadir_fname2_suffix, + MOCK(options_get_dir_fname2_suffix, mock_get_datadir_fname); /* @@ -5551,7 +5553,7 @@ test_dir_dump_unparseable_descriptors(void *data) mock_unlink_reset(); UNMOCK(write_str_to_file); mock_write_str_to_file_reset(); - UNMOCK(options_get_datadir_fname2_suffix); + UNMOCK(options_get_dir_fname2_suffix); UNMOCK(check_private_dir); UNMOCK(get_options); tor_free(mock_options); @@ -6174,6 +6176,106 @@ test_dir_platform_str(void *arg) ; } +static networkstatus_t *mock_networkstatus; + +static networkstatus_t * +mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f) +{ + (void)f; + return mock_networkstatus; +} + +static void +test_dir_networkstatus_consensus_has_ipv6(void *arg) +{ + (void)arg; + + int has_ipv6 = 0; + + /* Init options and networkstatus */ + or_options_t our_options; + mock_options = &our_options; + reset_options(mock_options, &mock_get_options_calls); + MOCK(get_options, mock_get_options); + + networkstatus_t our_networkstatus; + mock_networkstatus = &our_networkstatus; + memset(mock_networkstatus, 0, sizeof(*mock_networkstatus)); + MOCK(networkstatus_get_latest_consensus_by_flavor, + mock_networkstatus_get_latest_consensus_by_flavor); + + /* A live consensus */ + mock_networkstatus->valid_after = time(NULL) - 3600; + mock_networkstatus->valid_until = time(NULL) + 3600; + + /* Test the bounds for A lines in the NS consensus */ + mock_options->UseMicrodescriptors = 0; + + mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES + 1; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES + 20; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES - 1; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(!has_ipv6); + + /* Test the bounds for A lines in the microdesc consensus */ + mock_options->UseMicrodescriptors = 1; + + mock_networkstatus->consensus_method = + MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = + MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 1; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = + MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 20; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + mock_networkstatus->consensus_method = + MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS - 1; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(!has_ipv6); + + /* Test the edge cases */ + mock_options->UseMicrodescriptors = 1; + mock_networkstatus->consensus_method = + MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS; + + /* Reasonably live */ + mock_networkstatus->valid_until = time(NULL) - 60; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + /* Not reasonably live */ + mock_networkstatus->valid_after = time(NULL) - 24*60*60 - 3600; + mock_networkstatus->valid_until = time(NULL) - 24*60*60 - 60; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(!has_ipv6); + + /* NULL consensus */ + mock_networkstatus = NULL; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(!has_ipv6); + + done: + UNMOCK(get_options); + UNMOCK(networkstatus_get_latest_consensus_by_flavor); +} + #define DIR_LEGACY(name) \ { #name, test_dir_ ## name , TT_FORK, NULL, NULL } @@ -6241,6 +6343,7 @@ struct testcase_t dir_tests[] = { DIR(assumed_flags, 0), DIR(networkstatus_compute_bw_weights_v10, 0), DIR(platform_str, 0), + DIR(networkstatus_consensus_has_ipv6, 0), END_OF_TESTCASES }; diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index fe26657ad8..ca64dce5fe 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -88,7 +88,7 @@ test_dir_handle_get_bad_request(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -117,7 +117,7 @@ test_dir_handle_get_v1_command_not_found(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -164,7 +164,7 @@ test_dir_handle_get_v1_command(void *data) done: UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_dirportfrontpage); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); } @@ -190,7 +190,7 @@ test_dir_handle_get_not_found(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -225,7 +225,7 @@ test_dir_handle_get_robots_txt(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); } @@ -254,7 +254,7 @@ test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -282,7 +282,7 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id( done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -315,7 +315,7 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_not_well_formed(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -344,7 +344,7 @@ test_dir_handle_get_rendezvous2_not_found(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); rend_cache_free_all(); } @@ -424,7 +424,7 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_success(void *data) UNMOCK(connection_write_to_buf_impl_); NS_UNMOCK(router_get_my_routerinfo); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); rend_encoded_v2_service_descriptor_free(desc_holder); @@ -457,7 +457,7 @@ test_dir_handle_get_micro_d_not_found(void *data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -469,6 +469,7 @@ init_mock_options(void) memset(mock_options, 0, sizeof(or_options_t)); mock_options->TestingTorNetwork = 1; mock_options->DataDirectory = tor_strdup(get_fname_rnd("datadir_tmp")); + mock_options->CacheDirectory = tor_strdup(mock_options->DataDirectory); check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL); } @@ -541,7 +542,7 @@ test_dir_handle_get_micro_d(void *data) UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); smartlist_free(list); @@ -595,7 +596,7 @@ test_dir_handle_get_micro_d_server_busy(void *data) UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); smartlist_free(list); microdesc_free_all(); @@ -632,7 +633,7 @@ test_dir_handle_get_networkstatus_bridges_not_found_without_auth(void *data) UNMOCK(get_options); UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -672,7 +673,7 @@ test_dir_handle_get_networkstatus_bridges(void *data) UNMOCK(get_options); UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -709,7 +710,7 @@ test_dir_handle_get_networkstatus_bridges_not_found_wrong_auth(void *data) UNMOCK(get_options); UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -737,7 +738,7 @@ test_dir_handle_get_server_descriptors_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); or_options_free(mock_options); mock_options = NULL; - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -798,7 +799,7 @@ test_dir_handle_get_server_descriptors_all(void* data) done: NS_UNMOCK(router_get_my_routerinfo); UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); @@ -902,7 +903,7 @@ test_dir_handle_get_server_descriptors_authority(void* data) UNMOCK(connection_write_to_buf_impl_); tor_free(mock_routerinfo->cache_info.signed_descriptor_body); tor_free(mock_routerinfo); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); crypto_pk_free(identity_pkey); @@ -974,7 +975,7 @@ test_dir_handle_get_server_descriptors_fp(void* data) UNMOCK(connection_write_to_buf_impl_); tor_free(mock_routerinfo->cache_info.signed_descriptor_body); tor_free(mock_routerinfo); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); crypto_pk_free(identity_pkey); @@ -1038,7 +1039,7 @@ test_dir_handle_get_server_descriptors_d(void* data) done: UNMOCK(connection_write_to_buf_impl_); tor_free(mock_routerinfo); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); crypto_pk_free(identity_pkey); @@ -1094,7 +1095,7 @@ test_dir_handle_get_server_descriptors_busy(void* data) UNMOCK(get_options); UNMOCK(connection_write_to_buf_impl_); tor_free(mock_routerinfo); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); crypto_pk_free(identity_pkey); @@ -1125,7 +1126,7 @@ test_dir_handle_get_server_keys_bad_req(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1151,7 +1152,7 @@ test_dir_handle_get_server_keys_all_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1210,7 +1211,7 @@ test_dir_handle_get_server_keys_all(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); @@ -1240,7 +1241,7 @@ test_dir_handle_get_server_keys_authority_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1288,7 +1289,7 @@ test_dir_handle_get_server_keys_authority(void* data) done: UNMOCK(get_my_v3_authority_cert); UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); authority_cert_free(mock_cert); mock_cert = NULL; @@ -1316,7 +1317,7 @@ test_dir_handle_get_server_keys_fp_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1370,7 +1371,7 @@ test_dir_handle_get_server_keys_fp(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); clear_dir_servers(); @@ -1399,7 +1400,7 @@ test_dir_handle_get_server_keys_sk_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1444,7 +1445,7 @@ test_dir_handle_get_server_keys_sk(void* data) done: UNMOCK(get_my_v3_authority_cert); UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); authority_cert_free(mock_cert); mock_cert = NULL; tor_free(header); tor_free(body); @@ -1472,7 +1473,7 @@ test_dir_handle_get_server_keys_fpsk_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1529,7 +1530,7 @@ test_dir_handle_get_server_keys_fpsk(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); @@ -1583,7 +1584,7 @@ test_dir_handle_get_server_keys_busy(void* data) done: UNMOCK(get_options); UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); or_options_free(mock_options); mock_options = NULL; @@ -1649,7 +1650,7 @@ test_dir_handle_get_status_vote_current_consensus_ns_not_enough_sigs(void* d) UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_options); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(stats); smartlist_free(mock_ns_val->voters); @@ -1690,7 +1691,7 @@ test_dir_handle_get_status_vote_current_consensus_ns_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_options); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(stats); or_options_free(mock_options); mock_options = NULL; @@ -1764,7 +1765,7 @@ test_dir_handle_get_status_vote_current_consensus_too_old(void *data) UNMOCK(networkstatus_get_latest_consensus_by_flavor); UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_options); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(mock_ns_val); or_options_free(mock_options); mock_options = NULL; @@ -1825,7 +1826,7 @@ status_vote_current_consensus_ns_test(char **header, char **body, done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); } static void @@ -1948,7 +1949,7 @@ test_dir_handle_get_status_vote_current_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -1971,7 +1972,7 @@ status_vote_current_d_test(char **header, char **body, size_t *body_l) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); } static void @@ -1991,7 +1992,7 @@ status_vote_next_d_test(char **header, char **body, size_t *body_l) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); } static void @@ -2116,7 +2117,7 @@ test_dir_handle_get_status_vote_next_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -2135,7 +2136,7 @@ status_vote_next_consensus_test(char **header, char **body, size_t *body_used) body, body_used, 18, 0); done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); } static void @@ -2175,7 +2176,7 @@ test_dir_handle_get_status_vote_current_authority_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -2199,7 +2200,7 @@ test_dir_handle_get_status_vote_next_authority_not_found(void* data) done: UNMOCK(connection_write_to_buf_impl_); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); } @@ -2281,7 +2282,7 @@ status_vote_next_consensus_signatures_test(char **header, char **body, body, body_used, 22, 0); done: - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); UNMOCK(connection_write_to_buf_impl_); } @@ -2429,7 +2430,7 @@ test_dir_handle_get_status_vote_next_authority(void* data) done: UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_my_v3_authority_cert); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); authority_cert_free(mock_cert); mock_cert = NULL; @@ -2511,7 +2512,7 @@ test_dir_handle_get_status_vote_current_authority(void* data) done: UNMOCK(connection_write_to_buf_impl_); UNMOCK(get_my_v3_authority_cert); - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); tor_free(header); tor_free(body); authority_cert_free(mock_cert); mock_cert = NULL; diff --git a/src/test/test_dns.c b/src/test/test_dns.c index 19dcb02931..1fee01d2c0 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #include "or.h" #include "test.h" @@ -121,7 +124,7 @@ static int n_connection_free = 0; static connection_t *last_freed_conn = NULL; static void -NS(connection_free)(connection_t *conn) +NS(connection_free_)(connection_t *conn) { n_connection_free++; @@ -264,7 +267,7 @@ NS(test_main)(void *arg) */ NS_MOCK(dns_cancel_pending_resolve); - NS_MOCK(connection_free); + NS_MOCK(connection_free_); exitconn->on_circuit = &(on_circuit->base_); exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE; @@ -291,7 +294,7 @@ NS(test_main)(void *arg) NS_UNMOCK(send_resolved_cell); NS_UNMOCK(send_resolved_hostname_cell); NS_UNMOCK(dns_cancel_pending_resolve); - NS_UNMOCK(connection_free); + NS_UNMOCK(connection_free_); tor_free(on_circuit); tor_free(exitconn); tor_free(nextconn); diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c index c29b1a7126..9d8a072c77 100644 --- a/src/test/test_entryconn.c +++ b/src/test/test_entryconn.c @@ -34,7 +34,7 @@ entryconn_rewrite_teardown(const struct testcase_t *tc, void *arg) (void)tc; entry_connection_t *ec = arg; if (ec) - connection_free_(ENTRY_TO_CONN(ec)); + connection_free_minimal(ENTRY_TO_CONN(ec)); addressmap_free_all(); return 1; } @@ -156,8 +156,8 @@ test_entryconn_rewrite_automap_ipv4(void *arg) ec->socks_request->address); done: - connection_free_(ENTRY_TO_CONN(ec2)); - connection_free_(ENTRY_TO_CONN(ec3)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec3)); } /* Automap on resolve, connect to automapped address, resolve again and get @@ -230,9 +230,9 @@ test_entryconn_rewrite_automap_ipv6(void *arg) ec->socks_request->address); done: - connection_free_(ENTRY_TO_CONN(ec)); - connection_free_(ENTRY_TO_CONN(ec2)); - connection_free_(ENTRY_TO_CONN(ec3)); + connection_free_minimal(ENTRY_TO_CONN(ec)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec3)); } #if 0 @@ -283,7 +283,7 @@ test_entryconn_rewrite_automap_reverse(void *arg) tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); done: - connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); } #endif /* 0 */ @@ -333,7 +333,7 @@ test_entryconn_rewrite_cached_dns_ipv4(void *arg) tt_str_op(ec2->socks_request->address, OP_EQ, "240.240.241.241"); done: - connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); } /* Rewrite because of cached DNS entry. */ @@ -385,8 +385,8 @@ test_entryconn_rewrite_cached_dns_ipv6(void *arg) tt_str_op(ec2->socks_request->address, OP_EQ, "[::f00f]"); done: - connection_free_(ENTRY_TO_CONN(ec)); - connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); } /* Fail to connect to unmapped address in virtual range. */ @@ -426,7 +426,7 @@ test_entryconn_rewrite_unmapped_virtual(void *arg) tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); done: - connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); } /* Rewrite because of mapaddress option */ @@ -507,7 +507,7 @@ test_entryconn_rewrite_automap_exit(void *arg) tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_TORPROTOCOL); done: - connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); } /* Rewrite into .exit because of mapaddress */ @@ -618,9 +618,9 @@ test_entryconn_rewrite_mapaddress_automap_onion(void *arg) */ done: - connection_free_(ENTRY_TO_CONN(ec2)); - connection_free_(ENTRY_TO_CONN(ec3)); - connection_free_(ENTRY_TO_CONN(ec4)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec3)); + connection_free_minimal(ENTRY_TO_CONN(ec4)); } static void @@ -678,8 +678,8 @@ test_entryconn_rewrite_mapaddress_automap_onion_common(entry_connection_t *ec, "abcdefghijklmnop.onion")); done: - connection_free_(ENTRY_TO_CONN(ec2)); - connection_free_(ENTRY_TO_CONN(ec3)); + connection_free_minimal(ENTRY_TO_CONN(ec2)); + connection_free_minimal(ENTRY_TO_CONN(ec3)); } /* This time is the same, but we start with a mapping from a non-onion diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 80ebebe3f8..1cff3828c4 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -2372,8 +2372,8 @@ upgrade_circuits_cleanup(const struct testcase_t *testcase, void *ptr) // circuit_guard_state_free(data->guard2_state); // held in circ2 guard_selection_free(data->gs); smartlist_free(data->all_origin_circuits); - circuit_free(TO_CIRCUIT(data->circ1)); - circuit_free(TO_CIRCUIT(data->circ2)); + circuit_free_(TO_CIRCUIT(data->circ1)); + circuit_free_(TO_CIRCUIT(data->circ2)); tor_free(data); return big_fake_network_cleanup(testcase, NULL); } diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index e18deb2700..cadef257f1 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -58,11 +58,11 @@ test_ext_or_id_map(void *arg) done: if (c1) - connection_free_(TO_CONN(c1)); + connection_free_minimal(TO_CONN(c1)); if (c2) - connection_free_(TO_CONN(c2)); + connection_free_minimal(TO_CONN(c2)); if (c3) - connection_free_(TO_CONN(c3)); + connection_free_minimal(TO_CONN(c3)); tor_free(idp); tor_free(idp2); connection_or_clear_ext_or_id_map(); @@ -145,7 +145,7 @@ test_ext_or_write_command(void *arg) done: if (c1) - connection_free_(TO_CONN(c1)); + connection_free_minimal(TO_CONN(c1)); tor_free(cp); tor_free(buf); UNMOCK(connection_write_to_buf_impl_); @@ -591,7 +591,7 @@ test_ext_or_handshake(void *arg) UNMOCK(connection_write_to_buf_impl_); UNMOCK(crypto_rand); if (conn) - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); #undef CONTAINS #undef WRITE } diff --git a/src/test/test_handles.c b/src/test/test_handles.c index 7ddee6e376..eb1e1f1bbe 100644 --- a/src/test/test_handles.c +++ b/src/test/test_handles.c @@ -13,6 +13,8 @@ typedef struct demo_t { } demo_t; HANDLE_DECL(demo, demo_t, static) +#define demo_handle_free(h) \ + FREE_AND_NULL(demo_handle_t, demo_handle_free_, (h)) HANDLE_IMPL(demo, demo_t, static) static demo_t * diff --git a/src/test/test_hs.c b/src/test/test_hs.c index 7737499f50..55c6218dd1 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -258,8 +258,9 @@ test_hs_desc_event(void *arg) sizeof(desc_id_base32)); /* test request event */ - control_event_hs_descriptor_requested(&rend_query.base_, HSDIR_EXIST_ID, - STR_DESC_ID_BASE32); + control_event_hs_descriptor_requested(rend_query.onion_address, + rend_query.auth_type, HSDIR_EXIST_ID, + STR_DESC_ID_BASE32, NULL); expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\ STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n"; tt_assert(received_msg); @@ -268,8 +269,8 @@ test_hs_desc_event(void *arg) /* test received event */ rend_query.auth_type = REND_BASIC_AUTH; - control_event_hs_descriptor_received(rend_query.onion_address, - &rend_query.base_, HSDIR_EXIST_ID); + control_event_hsv2_descriptor_received(rend_query.onion_address, + &rend_query.base_, HSDIR_EXIST_ID); expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\ STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n"; tt_assert(received_msg); @@ -278,7 +279,7 @@ test_hs_desc_event(void *arg) /* test failed event */ rend_query.auth_type = REND_STEALTH_AUTH; - control_event_hs_descriptor_failed(&rend_query.base_, + control_event_hsv2_descriptor_failed(&rend_query.base_, HSDIR_NONE_EXIST_ID, "QUERY_REJECTED"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\ @@ -289,7 +290,7 @@ test_hs_desc_event(void *arg) /* test invalid auth type */ rend_query.auth_type = 999; - control_event_hs_descriptor_failed(&rend_query.base_, + control_event_hsv2_descriptor_failed(&rend_query.base_, HSDIR_EXIST_ID, "QUERY_REJECTED"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\ @@ -301,7 +302,7 @@ test_hs_desc_event(void *arg) /* test no HSDir fingerprint type */ rend_query.auth_type = REND_NO_AUTH; - control_event_hs_descriptor_failed(&rend_query.base_, NULL, + control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, "QUERY_NO_HSDIR"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ "UNKNOWN REASON=QUERY_NO_HSDIR\r\n"; diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index 91b13be862..458ce1a92e 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -259,7 +259,7 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key) done: tor_free(hsdir_query_str); if (conn) - connection_free_(TO_CONN(conn)); + connection_free_minimal(TO_CONN(conn)); return received_desc; } diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index 750920fac0..7ee7210bc9 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -227,10 +227,10 @@ test_e2e_rend_circuit_setup_legacy(void *arg) tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ)); done: - connection_free_(conn); + connection_free_minimal(conn); if (or_circ) tor_free(TO_CIRCUIT(or_circ)->n_chan); - circuit_free(TO_CIRCUIT(or_circ)); + circuit_free_(TO_CIRCUIT(or_circ)); } /* Test: Ensure that setting up v3 rendezvous circuits works correctly. */ @@ -297,10 +297,10 @@ test_e2e_rend_circuit_setup(void *arg) tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ)); done: - connection_free_(conn); + connection_free_minimal(conn); if (or_circ) tor_free(TO_CIRCUIT(or_circ)->n_chan); - circuit_free(TO_CIRCUIT(or_circ)); + circuit_free_(TO_CIRCUIT(or_circ)); } /** Test client logic for picking intro points from a descriptor. Also test how @@ -560,7 +560,7 @@ test_descriptor_fetch(void *arg) smartlist_add(get_connection_array(), TO_CONN(dir_conn)); ret = hs_client_refetch_hsdesc(&service_pk); smartlist_remove(get_connection_array(), TO_CONN(dir_conn)); - connection_free_(TO_CONN(dir_conn)); + connection_free_minimal(TO_CONN(dir_conn)); tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_PENDING); } @@ -579,7 +579,7 @@ test_descriptor_fetch(void *arg) tt_int_op(ec->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED); done: - connection_free_(ENTRY_TO_CONN(ec)); + connection_free_minimal(ENTRY_TO_CONN(ec)); UNMOCK(networkstatus_get_live_consensus); UNMOCK(router_have_minimum_dir_info); hs_free_all(); diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c new file mode 100644 index 0000000000..207a55de6d --- /dev/null +++ b/src/test/test_hs_control.c @@ -0,0 +1,199 @@ +/* Copyright (c) 2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_control.c + * \brief Unit tests for hidden service control port event and command. + **/ + +#define CONTROL_PRIVATE +#define CIRCUITBUILD_PRIVATE +#define RENDCOMMON_PRIVATE +#define RENDSERVICE_PRIVATE +#define HS_SERVICE_PRIVATE + +#include "or.h" +#include "test.h" +#include "control.h" +#include "config.h" +#include "hs_common.h" +#include "hs_control.h" +#include "nodelist.h" +//#include "rendcommon.h" +//#include "rendservice.h" +//#include "routerset.h" +//#include "circuitbuild.h" +#include "test_helpers.h" + +/* mock ID digest and longname for node that's in nodelist */ +#define HSDIR_EXIST_ID \ + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" +#define STR_HSDIR_EXIST_LONGNAME \ + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir" +#define STR_HSDIR_NONE_EXIST_LONGNAME \ + "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + +/* Helper global variable for hidden service descriptor event test. + * It's used as a pointer to dynamically created message buffer in + * send_control_event_string_replacement function, which mocks + * send_control_event_string function. + * + * Always free it after use! */ +static char *received_msg = NULL; + +/** Mock function for send_control_event_string + */ +static void +queue_control_event_string_replacement(uint16_t event, char *msg) +{ + (void) event; + tor_free(received_msg); + received_msg = msg; +} + +/** Mock function for node_describe_longname_by_id, it returns either + * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME + */ +static const char * +node_describe_longname_by_id_replacement(const char *id_digest) +{ + if (!strcmp(id_digest, HSDIR_EXIST_ID)) { + return STR_HSDIR_EXIST_LONGNAME; + } else { + return STR_HSDIR_NONE_EXIST_LONGNAME; + } +} + +/* HSDir fetch index is a series of 'D' */ +#define HSDIR_INDEX_FETCH_HEX \ + "4343434343434343434343434343434343434343434343434343434343434343" +#define HSDIR_INDEX_STORE_HEX \ + "4444444444444444444444444444444444444444444444444444444444444444" + +static const node_t * +mock_node_get_by_id(const char *digest) +{ + static node_t node; + memcpy(node.identity, digest, DIGEST_LEN); + node.hsdir_index = tor_malloc_zero(sizeof(hsdir_index_t)); + memset(node.hsdir_index->fetch, 'C', DIGEST256_LEN); + memset(node.hsdir_index->store_first, 'D', DIGEST256_LEN); + return &node; +} + +static void +test_hs_desc_event(void *arg) +{ + int ret; + char *expected_msg = NULL; + char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1]; + ed25519_keypair_t identity_kp; + ed25519_public_key_t blinded_pk; + char base64_blinded_pk[ED25519_BASE64_LEN + 1]; + routerstatus_t hsdir_rs; + hs_ident_dir_conn_t ident; + + (void) arg; + MOCK(queue_control_event_string, + queue_control_event_string_replacement); + MOCK(node_describe_longname_by_id, + node_describe_longname_by_id_replacement); + MOCK(node_get_by_id, mock_node_get_by_id); + + /* Setup what we need for this test. */ + ed25519_keypair_generate(&identity_kp, 0); + hs_build_address(&identity_kp.pubkey, HS_VERSION_THREE, onion_address); + ret = hs_address_is_valid(onion_address); + tt_int_op(ret, OP_EQ, 1); + memset(&blinded_pk, 'B', sizeof(blinded_pk)); + memset(&hsdir_rs, 0, sizeof(hsdir_rs)); + memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN); + ret = ed25519_public_to_base64(base64_blinded_pk, &blinded_pk); + tt_int_op(ret, OP_EQ, 0); + memcpy(&ident.identity_pk, &identity_kp.pubkey, + sizeof(ed25519_public_key_t)); + memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk)); + + /* HS_DESC REQUESTED ... */ + hs_control_desc_event_requested(&identity_kp.pubkey, base64_blinded_pk, + &hsdir_rs); + tor_asprintf(&expected_msg, "650 HS_DESC REQUESTED %s NO_AUTH " + STR_HSDIR_EXIST_LONGNAME " %s HSDIR_INDEX=" + HSDIR_INDEX_FETCH_HEX "\r\n", + onion_address, base64_blinded_pk); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + /* HS_DESC CREATED... */ + hs_control_desc_event_created(onion_address, &blinded_pk); + tor_asprintf(&expected_msg, "650 HS_DESC CREATED %s UNKNOWN " + "UNKNOWN %s\r\n", + onion_address, base64_blinded_pk); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + /* HS_DESC UPLOAD... */ + uint8_t hsdir_index_store[DIGEST256_LEN]; + memset(hsdir_index_store, 'D', sizeof(hsdir_index_store)); + hs_control_desc_event_upload(onion_address, HSDIR_EXIST_ID, + &blinded_pk, hsdir_index_store); + tor_asprintf(&expected_msg, "650 HS_DESC UPLOAD %s UNKNOWN " + STR_HSDIR_EXIST_LONGNAME " %s " + "HSDIR_INDEX=" HSDIR_INDEX_STORE_HEX "\r\n", + onion_address, base64_blinded_pk); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + /* HS_DESC FAILED... */ + hs_control_desc_event_failed(&ident, HSDIR_EXIST_ID, "BAD_DESC"); + tor_asprintf(&expected_msg, "650 HS_DESC FAILED %s NO_AUTH " + STR_HSDIR_EXIST_LONGNAME " %s " + "REASON=BAD_DESC\r\n", + onion_address, base64_blinded_pk); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + /* HS_DESC RECEIVED... */ + hs_control_desc_event_received(&ident, HSDIR_EXIST_ID); + tor_asprintf(&expected_msg, "650 HS_DESC RECEIVED %s NO_AUTH " + STR_HSDIR_EXIST_LONGNAME " %s\r\n", + onion_address, base64_blinded_pk); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + /* HS_DESC UPLOADED... */ + hs_control_desc_event_uploaded(&ident, HSDIR_EXIST_ID); + tor_asprintf(&expected_msg, "650 HS_DESC UPLOADED %s UNKNOWN " + STR_HSDIR_EXIST_LONGNAME "\r\n", + onion_address); + tt_assert(received_msg); + tt_str_op(received_msg, OP_EQ, expected_msg); + tor_free(received_msg); + tor_free(expected_msg); + + done: + UNMOCK(queue_control_event_string); + UNMOCK(node_describe_longname_by_id); + UNMOCK(node_get_by_id); + tor_free(received_msg); + tor_free(expected_msg); +} + +struct testcase_t hs_control_tests[] = { + { "hs_desc_event", test_hs_desc_event, TT_FORK, + NULL, NULL }, + + END_OF_TESTCASES +}; + diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 0cae2de7e1..6a7962b212 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -194,7 +194,7 @@ test_establish_intro_wrong_purpose(void *arg) tt_int_op(retval, OP_EQ, -1); done: - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */ @@ -228,7 +228,7 @@ test_establish_intro_wrong_keytype(void *arg) tt_int_op(retval, OP_EQ, -1); done: - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */ @@ -263,7 +263,7 @@ test_establish_intro_wrong_keytype2(void *arg) tt_int_op(retval, OP_EQ, -1); done: - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */ @@ -333,7 +333,7 @@ test_establish_intro_wrong_mac(void *arg) done: trn_cell_establish_intro_free(cell); - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Send a legit ESTABLISH_INTRO cell but with a wrong auth key length. Should @@ -378,7 +378,7 @@ test_establish_intro_wrong_auth_key_len(void *arg) done: trn_cell_establish_intro_free(cell); - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should @@ -423,7 +423,7 @@ test_establish_intro_wrong_sig_len(void *arg) done: trn_cell_establish_intro_free(cell); - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should @@ -460,7 +460,7 @@ test_establish_intro_wrong_sig(void *arg) tt_int_op(retval, OP_EQ, -1); done: - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to @@ -629,8 +629,8 @@ test_intro_point_registration(void *arg) done: crypto_pk_free(legacy_auth_key); - circuit_free(TO_CIRCUIT(intro_circ)); - circuit_free(TO_CIRCUIT(legacy_intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(legacy_intro_circ)); trn_cell_establish_intro_free(establish_intro_cell); test_circuitmap_free_all(); @@ -650,7 +650,7 @@ test_introduce1_suitable_circuit(void *arg) circ = or_circuit_new(0, NULL); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); ret = circuit_is_suitable_for_introduce1(circ); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); tt_int_op(ret, OP_EQ, 1); } @@ -659,7 +659,7 @@ test_introduce1_suitable_circuit(void *arg) circ = or_circuit_new(0, NULL); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); ret = circuit_is_suitable_for_introduce1(circ); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); tt_int_op(ret, OP_EQ, 0); } @@ -670,7 +670,7 @@ test_introduce1_suitable_circuit(void *arg) /* Bogus pointer, the check is against NULL on n_chan. */ circ->base_.n_chan = (channel_t *) circ; ret = circuit_is_suitable_for_introduce1(circ); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); tt_int_op(ret, OP_EQ, 0); } @@ -681,7 +681,7 @@ test_introduce1_suitable_circuit(void *arg) circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); circ->already_received_introduce1 = 1; ret = circuit_is_suitable_for_introduce1(circ); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); tt_int_op(ret, OP_EQ, 0); } @@ -800,7 +800,7 @@ test_received_introduce1_handling(void *arg) circ = helper_create_intro_circuit(); ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1); tt_int_op(ret, OP_EQ, -1); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); } /* We have a unit test only for the suitability of a circuit to receive an @@ -813,7 +813,7 @@ test_received_introduce1_handling(void *arg) memset(test, 0, sizeof(test)); ret = handle_introduce1(circ, test, sizeof(test)); tor_free(circ->p_chan); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); tt_int_op(ret, OP_EQ, -1); } @@ -838,8 +838,8 @@ test_received_introduce1_handling(void *arg) memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN); hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key); ret = hs_intro_received_introduce1(circ, request, request_len); - circuit_free(TO_CIRCUIT(circ)); - circuit_free(TO_CIRCUIT(service_circ)); + circuit_free_(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(service_circ)); tt_int_op(ret, OP_EQ, 0); } @@ -867,8 +867,8 @@ test_received_introduce1_handling(void *arg) memcpy(token, legacy_key_id, sizeof(token)); hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token); ret = hs_intro_received_introduce1(circ, request, request_len); - circuit_free(TO_CIRCUIT(circ)); - circuit_free(TO_CIRCUIT(service_circ)); + circuit_free_(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(service_circ)); tt_int_op(ret, OP_EQ, 0); } diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 8407eccfa8..3e3a7d8e0d 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -182,7 +182,7 @@ test_e2e_rend_circuit_setup(void *arg) tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED); done: - circuit_free(TO_CIRCUIT(or_circ)); + circuit_free_(TO_CIRCUIT(or_circ)); } /* Helper: Return a newly allocated and initialized origin circuit with @@ -194,7 +194,7 @@ helper_create_origin_circuit(int purpose, int flags) origin_circuit_t *circ = NULL; circ = origin_circuit_init(purpose, flags); - tt_assert(circ); + tor_assert(circ); circ->cpath = tor_malloc_zero(sizeof(crypt_path_t)); circ->cpath->magic = CRYPT_PATH_MAGIC; circ->cpath->state = CPATH_STATE_OPEN; @@ -206,7 +206,6 @@ helper_create_origin_circuit(int purpose, int flags) /* Create a default HS identifier. */ circ->hs_ident = tor_malloc_zero(sizeof(hs_ident_circuit_t)); - done: return circ; } @@ -219,7 +218,7 @@ helper_create_service(void) { /* Set a service for this circuit. */ hs_service_t *service = hs_service_new(get_options()); - tt_assert(service); + tor_assert(service); service->config.version = HS_VERSION_THREE; ed25519_secret_key_generate(&service->keys.identity_sk, 0); ed25519_public_key_generate(&service->keys.identity_pk, @@ -241,7 +240,7 @@ helper_create_service_ip(void) { hs_desc_link_specifier_t *ls; hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0); - tt_assert(ip); + tor_assert(ip); /* Add a first unused link specifier. */ ls = tor_malloc_zero(sizeof(*ls)); ls->type = LS_IPV4; @@ -252,7 +251,6 @@ helper_create_service_ip(void) memset(ls->u.legacy_id, 'A', sizeof(ls->u.legacy_id)); smartlist_add(ip->base.link_specifiers, ls); - done: return ip; } @@ -655,7 +653,7 @@ test_intro_circuit_opened(void *arg) teardown_capture_of_logs(); done: - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); hs_free_all(); UNMOCK(circuit_mark_for_close_); UNMOCK(relay_send_command_from_edge_); @@ -730,7 +728,7 @@ test_intro_established(void *arg) done: if (circ) - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -772,7 +770,7 @@ test_rdv_circuit_opened(void *arg) tt_int_op(TO_CIRCUIT(circ)->purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED); done: - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); hs_free_all(); UNMOCK(circuit_mark_for_close_); UNMOCK(relay_send_command_from_edge_); @@ -825,7 +823,7 @@ test_closing_intro_circs(void *arg) /* Now pretend we are freeing this intro circuit. We want to see that our * destructor is not gonna kill our intro point structure since that's the * job of the cleanup routine. */ - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); intro_circ = NULL; entry = service_intro_point_find(service, &ip->auth_key_kp.pubkey); tt_assert(entry); @@ -857,7 +855,7 @@ test_closing_intro_circs(void *arg) done: if (intro_circ) { - circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free_(TO_CIRCUIT(intro_circ)); } /* Frees the service object. */ hs_free_all(); @@ -938,7 +936,7 @@ test_introduce2(void *arg) or_state_free(dummy_state); dummy_state = NULL; if (circ) - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -1022,7 +1020,7 @@ test_service_event(void *arg) done: hs_circuitmap_remove_circuit(TO_CIRCUIT(circ)); - circuit_free(TO_CIRCUIT(circ)); + circuit_free_(TO_CIRCUIT(circ)); hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -1576,8 +1574,8 @@ test_rendezvous1_parsing(void *arg) * would need an extra circuit and some more stuff but it's doable. */ done: - circuit_free(TO_CIRCUIT(service_circ)); - circuit_free(TO_CIRCUIT(client_circ)); + circuit_free_(TO_CIRCUIT(service_circ)); + circuit_free_(TO_CIRCUIT(client_circ)); hs_service_free(service); hs_free_all(); UNMOCK(relay_send_command_from_edge_); diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh index 87012cd283..b3d4d8e39a 100755 --- a/src/test/test_keygen.sh +++ b/src/test/test_keygen.sh @@ -40,6 +40,12 @@ fi CASE8=$dflt CASE9=$dflt CASE10=$dflt + CASE11A=$dflt + CASE11B=$dflt + CASE11C=$dflt + CASE11D=$dflt + CASE11E=$dflt + CASE11F=$dflt if [ $# -ge 1 ]; then eval "CASE${1}"=1 @@ -363,6 +369,109 @@ echo "==== Case 10 ok" fi +# Case 11a: -passphrase-fd without --keygen + +if [ "$CASE11A" = 1 ]; then + +ME="${DATA_DIR}/case11a" + +mkdir -p "${ME}/keys" + +${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout" && die "Successfully started with passphrase-fd but no keygen?" || true + +grep "passphrase-fd specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + +echo "==== Case 11A ok" + +fi + +# Case 11b: --no-passphrase without --keygen + +if [ "$CASE11B" = 1 ]; then + +ME="${DATA_DIR}/case11b" + +mkdir -p "${ME}/keys" + +${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout" && die "Successfully started with no-passphrase but no keygen?" || true + +grep "no-passphrase specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + +echo "==== Case 11B ok" + +fi + +# Case 11c: --newpass without --keygen + +if [ "$CASE11C" = 1 ]; then + +ME="${DATA_DIR}/case11C" + +mkdir -p "${ME}/keys" + +${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout" && die "Successfully started with newpass but no keygen?" || true + +grep "newpass specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + +echo "==== Case 11C ok" + +fi + +######## --master-key does not work yet, but this will test the error case +######## when it does. +# +# Case 11d: --master-key without --keygen +# +if [ "$CASE11D" = 1 ]; then +# +# ME="${DATA_DIR}/case11d" +# +# mkdir -p "${ME}/keys" +# +# ${TOR} --DataDirectory "${ME}" --master-key "${ME}/foobar" > "${ME}/stdout" && die "Successfully started with master-key but no keygen?" || true +# +# cat "${ME}/stdout" +# +# grep "master-key without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + + echo "==== Case 11D skipped" + +fi + + +# Case 11E: Silly passphrase-fd + +if [ "$CASE11E" = 1 ]; then + +ME="${DATA_DIR}/case11E" + +mkdir -p "${ME}/keys" + +${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd?" || true + +grep "Invalid --passphrase-fd value" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + +echo "==== Case 11E ok" + +fi + + +# Case 11F: --no-passphrase with --passphrase-fd + +if [ "$CASE11F" = 1 ]; then + +ME="${DATA_DIR}/case11F" + +mkdir -p "${ME}/keys" + +${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd combination?" || true + +grep "no-passphrase specified with --passphrase-fd" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." + +echo "==== Case 11F ok" + +fi + # Check cert-only. diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 422d419078..6840072d76 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -302,8 +302,8 @@ test_link_handshake_certs_ok(void *arg) mock_own_cert = mock_peer_cert = NULL; memset(c1->identity_digest, 0, sizeof(c1->identity_digest)); memset(c2->identity_digest, 0, sizeof(c2->identity_digest)); - connection_free_(TO_CONN(c1)); - connection_free_(TO_CONN(c2)); + connection_free_minimal(TO_CONN(c1)); + connection_free_minimal(TO_CONN(c2)); tor_free(cell1); tor_free(cell2); certs_cell_free(cc1); @@ -343,7 +343,7 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj) tor_free(d->cell); certs_cell_free(d->ccell); connection_or_clear_identity(d->c); - connection_free_(TO_CONN(d->c)); + connection_free_minimal(TO_CONN(d->c)); circuitmux_free(d->chan->base_.cmux); tor_free(d->chan); crypto_pk_free(d->key1); @@ -930,7 +930,7 @@ test_link_handshake_send_authchallenge(void *arg) done: UNMOCK(connection_or_write_var_cell_to_buf); - connection_free_(TO_CONN(c1)); + connection_free_minimal(TO_CONN(c1)); tor_free(cell1); tor_free(cell2); crypto_pk_free(rsa0); @@ -955,7 +955,7 @@ recv_authchallenge_cleanup(const struct testcase_t *test, void *obj) if (d) { tor_free(d->cell); - connection_free_(TO_CONN(d->c)); + connection_free_minimal(TO_CONN(d->c)); circuitmux_free(d->chan->base_.cmux); tor_free(d->chan); tor_free(d); @@ -1158,8 +1158,8 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg) tor_free(d->cell); connection_or_clear_identity(d->c1); connection_or_clear_identity(d->c2); - connection_free_(TO_CONN(d->c1)); - connection_free_(TO_CONN(d->c2)); + connection_free_minimal(TO_CONN(d->c1)); + connection_free_minimal(TO_CONN(d->c2)); circuitmux_free(d->chan2->base_.cmux); tor_free(d->chan2); crypto_pk_free(d->key1); diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 4f0ecd778b..59b28f7580 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -69,12 +69,12 @@ test_md_cache(void *data) time3 = time(NULL) - 15*24*60*60; /* Possibly, turn this into a test setup/cleanup pair */ - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test")); #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif tt_assert(!strcmpstart(test_md3_noannotation, "onion-key")); @@ -152,7 +152,7 @@ test_md_cache(void *data) strlen(test_md3_noannotation)); tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new", - options->DataDirectory); + options->CacheDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_assert(s); tt_mem_op(md1->body, OP_EQ, s + md1->off, md1->bodylen); @@ -180,7 +180,7 @@ test_md_cache(void *data) /* read the cache. */ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", - options->DataDirectory); + options->CacheDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1)); tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2)); @@ -234,7 +234,7 @@ test_md_cache(void *data) done: if (options) - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); microdesc_free_all(); smartlist_free(added); @@ -266,17 +266,17 @@ test_md_cache_broken(void *data) options = get_options_mutable(); tt_assert(options); - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test2")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test2")); #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", - options->DataDirectory); + options->CacheDirectory); write_str_to_file(fn, truncated_md, 1); @@ -285,7 +285,7 @@ test_md_cache_broken(void *data) done: if (options) - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); tor_free(fn); microdesc_free_all(); } @@ -754,8 +754,8 @@ test_md_reject_cache(void *arg) or_options_t *options = get_options_mutable(); char buf[DIGEST256_LEN]; - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test_rej")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test_rej")); mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t)); mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t)); mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t)); @@ -765,9 +765,9 @@ test_md_reject_cache(void *arg) mock_ns_val->flavor = FLAV_MICRODESC; #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif MOCK(router_get_mutable_consensus_status_by_descriptor_digest, @@ -802,7 +802,7 @@ test_md_reject_cache(void *arg) done: UNMOCK(networkstatus_get_latest_consensus_by_flavor); UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest); - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); microdesc_free_all(); smartlist_free(added); SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp)); diff --git a/src/test/test_oom.c b/src/test/test_oom.c index cf28690a28..c172fe60c7 100644 --- a/src/test/test_oom.c +++ b/src/test/test_oom.c @@ -202,7 +202,7 @@ test_oom_streambuf(void *arg) { or_options_t *options = get_options_mutable(); circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL; - uint32_t tvms; + uint32_t tvts; int i; smartlist_t *edgeconns = smartlist_new(); const uint64_t start_ns = 1389641159 * (uint64_t)1000000000; @@ -270,22 +270,28 @@ test_oom_streambuf(void *arg) now_ns -= now_ns % 1000000000; now_ns += 1000000000; monotime_coarse_set_mock_time_nsec(now_ns); - tvms = (uint32_t) monotime_coarse_absolute_msec(); + tvts = monotime_coarse_get_stamp(); - tt_int_op(circuit_max_queued_cell_age(c1, tvms), OP_EQ, 500); - tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490); - tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480); - tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0); +#define ts_is_approx(ts, val) do { \ + uint32_t x_ = (uint32_t) monotime_coarse_stamp_units_to_approx_msec(ts); \ + tt_int_op(x_, OP_GE, val - 5); \ + tt_int_op(x_, OP_LE, val + 5); \ + } while (0) - tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390); - tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380); - tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0); - tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370); + ts_is_approx(circuit_max_queued_cell_age(c1, tvts), 500); + ts_is_approx(circuit_max_queued_cell_age(c2, tvts), 490); + ts_is_approx(circuit_max_queued_cell_age(c3, tvts), 480); + ts_is_approx(circuit_max_queued_cell_age(c4, tvts), 0); - tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500); - tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490); - tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480); - tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370); + ts_is_approx(circuit_max_queued_data_age(c1, tvts), 390); + ts_is_approx(circuit_max_queued_data_age(c2, tvts), 380); + ts_is_approx(circuit_max_queued_data_age(c3, tvts), 0); + ts_is_approx(circuit_max_queued_data_age(c4, tvts), 370); + + ts_is_approx(circuit_max_queued_item_age(c1, tvts), 500); + ts_is_approx(circuit_max_queued_item_age(c2, tvts), 490); + ts_is_approx(circuit_max_queued_item_age(c3, tvts), 480); + ts_is_approx(circuit_max_queued_item_age(c4, tvts), 370); tt_int_op(cell_queues_get_total_allocation(), OP_EQ, packed_cell_mem_cost() * 80); @@ -301,7 +307,7 @@ test_oom_streambuf(void *arg) smartlist_add(edgeconns, ec); } tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2); - tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000); + ts_is_approx(circuit_max_queued_item_age(c4, tvts), 1000); tt_int_op(cell_queues_check_size(), OP_EQ, 0); @@ -335,7 +341,7 @@ test_oom_streambuf(void *arg) circuit_free(c5); SMARTLIST_FOREACH(edgeconns, edge_connection_t *, ec, - connection_free_(TO_CONN(ec))); + connection_free_minimal(TO_CONN(ec))); smartlist_free(edgeconns); UNMOCK(circuit_mark_for_close_); diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 83dca2d431..f8aa8ac40b 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1318,7 +1318,7 @@ mock_get_interface_address6_list(int severity, return clone_list; done: - free_interface_address6_list(clone_list); + interface_address6_list_free(clone_list); return NULL; } @@ -1393,11 +1393,11 @@ test_policies_reject_interface_address(void *arg) done: addr_policy_list_free(policy); - free_interface_address6_list(public_ipv4_addrs); - free_interface_address6_list(public_ipv6_addrs); + interface_address6_list_free(public_ipv4_addrs); + interface_address6_list_free(public_ipv6_addrs); UNMOCK(get_interface_address6_list); - /* we don't use free_interface_address6_list on these lists because their + /* we don't use interface_address6_list_free on these lists because their * address pointers are stack-based */ smartlist_free(mock_ipv4_addrs); smartlist_free(mock_ipv6_addrs); diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 6ce54890d6..6865362115 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -12,6 +12,13 @@ static void test_protover_parse(void *arg) { (void) arg; +#ifdef HAVE_RUST + /** This test is disabled on rust builds, because it only exists to test + * internal C functions. */ + tt_skip(); + done: + ; +#else char *re_encoded = NULL; const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900"; @@ -78,12 +85,18 @@ test_protover_parse(void *arg) SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent)); smartlist_free(elts); tor_free(re_encoded); +#endif } static void test_protover_parse_fail(void *arg) { (void)arg; +#ifdef HAVE_RUST + /** This test is disabled on rust builds, because it only exists to test + * internal C functions. */ + tt_skip(); +#else smartlist_t *elts; /* random junk */ @@ -109,7 +122,7 @@ test_protover_parse_fail(void *arg) /* Broken range */ elts = parse_protocol_list("Link=1,9-8,3"); tt_ptr_op(elts, OP_EQ, NULL); - +#endif done: ; } @@ -182,6 +195,61 @@ test_protover_all_supported(void *arg) tor_free(msg); } +static void +test_protover_list_supports_protocol_returns_true(void *arg) +{ + (void)arg; + + const char *protocols = "Link=1"; + int is_supported = protocol_list_supports_protocol(protocols, PRT_LINK, 1); + tt_int_op(is_supported, OP_EQ, 1); + + done: + ; +} + +static void +test_protover_list_supports_protocol_for_unsupported_returns_false(void *arg) +{ + (void)arg; + + const char *protocols = "Link=1"; + int is_supported = protocol_list_supports_protocol(protocols, PRT_LINK, 10); + tt_int_op(is_supported, OP_EQ, 0); + + done: + ; +} + +static void +test_protover_supports_version(void *arg) +{ + (void)arg; + + tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 3)); + tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 6)); + tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINK, 7)); + tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINKAUTH, 3)); + + tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 2)); + tt_assert(protocol_list_supports_protocol("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 3)); + tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 4)); + tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 4)); + tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 3)); + tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3", + PRT_LINKAUTH, 2)); + + tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3", + PRT_DESC, 2)); + done: + ; +} + #define PV_TEST(name, flags) \ { #name, test_protover_ ##name, (flags), NULL, NULL } @@ -190,6 +258,9 @@ struct testcase_t protover_tests[] = { PV_TEST(parse_fail, 0), PV_TEST(vote, 0), PV_TEST(all_supported, 0), + PV_TEST(list_supports_protocol_for_unsupported_returns_false, 0), + PV_TEST(list_supports_protocol_returns_true, 0), + PV_TEST(supports_version, 0), END_OF_TESTCASES }; diff --git a/src/test/test_relay.c b/src/test/test_relay.c index e3489627a0..73c0ed5586 100644 --- a/src/test/test_relay.c +++ b/src/test/test_relay.c @@ -67,10 +67,6 @@ test_relay_append_cell_to_circuit_queue(void *arg) pchan = new_fake_channel(); tt_assert(pchan); - /* We'll need chans with working cmuxes */ - nchan->cmux = circuitmux_alloc(); - pchan->cmux = circuitmux_alloc(); - /* Make a fake orcirc */ orcirc = new_fake_orcirc(nchan, pchan); tt_assert(orcirc); diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c index 9354dd0480..9f6cfc4a22 100644 --- a/src/test/test_rendcache.c +++ b/src/test/test_rendcache.c @@ -834,7 +834,7 @@ test_rend_cache_failure_entry_free(void *data) (void)data; // Test that it can deal with a NULL argument - rend_cache_failure_entry_free(NULL); + rend_cache_failure_entry_free_(NULL); /* done: */ /* (void)0; */ @@ -963,7 +963,7 @@ test_rend_cache_entry_free(void *data) rend_cache_entry_t *e; // Handles NULL correctly - rend_cache_entry_free(NULL); + rend_cache_entry_free_(NULL); // Handles NULL descriptor correctly e = tor_malloc_zero(sizeof(rend_cache_entry_t)); @@ -1135,7 +1135,7 @@ test_rend_cache_failure_intro_entry_free(void *data) rend_cache_failure_intro_t *entry; // Handles a null argument - rend_cache_failure_intro_entry_free(NULL); + rend_cache_failure_intro_entry_free_(NULL); // Handles a non-null argument entry = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); @@ -1148,7 +1148,7 @@ test_rend_cache_failure_purge(void *data) (void)data; // Handles a null failure cache - strmap_free(rend_cache_failure, rend_cache_failure_entry_free_); + strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void); rend_cache_failure = NULL; rend_cache_failure_purge(); diff --git a/src/test/test_replay.c b/src/test/test_replay.c index c379cafa7c..d8dcc7370c 100644 --- a/src/test/test_replay.c +++ b/src/test/test_replay.c @@ -74,7 +74,7 @@ static void test_replaycache_free_null(void *arg) { (void)arg; - replaycache_free(NULL); + replaycache_free_(NULL); /* Assert that we're here without horrible death */ tt_assert(1); diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index d8b72651a0..e4abcdb92d 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -421,6 +421,7 @@ test_routerkeys_ed_keys_init_all(void *arg) { (void)arg; char *dir = tor_strdup(get_fname("test_ed_keys_init_all")); + char *keydir = tor_strdup(get_fname("test_ed_keys_init_all/KEYS")); or_options_t *options = tor_malloc_zero(sizeof(or_options_t)); time_t now = time(NULL); ed25519_public_key_t id; @@ -445,13 +446,14 @@ test_routerkeys_ed_keys_init_all(void *arg) #ifdef _WIN32 mkdir(dir); - mkdir(get_fname("test_ed_keys_init_all/keys")); + mkdir(keydir); #else mkdir(dir, 0700); - mkdir(get_fname("test_ed_keys_init_all/keys"), 0700); + mkdir(keydir, 0700); #endif /* defined(_WIN32) */ options->DataDirectory = dir; + options->KeyDirectory = keydir; tt_int_op(1, OP_EQ, load_ed_keys(options, now)); tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0)); @@ -521,7 +523,7 @@ test_routerkeys_ed_keys_init_all(void *arg) /* Demonstrate that we can start up with no secret identity key */ routerkeys_free_all(); - unlink(get_fname("test_ed_keys_init_all/keys/" + unlink(get_fname("test_ed_keys_init_all/KEYS/" "ed25519_master_id_secret_key")); tt_int_op(1, OP_EQ, load_ed_keys(options, now)); tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0)); @@ -542,6 +544,7 @@ test_routerkeys_ed_keys_init_all(void *arg) done: tor_free(dir); + tor_free(keydir); tor_free(options); tor_cert_free(link_cert); routerkeys_free_all(); diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 3b0e943ce5..c19d66ef9d 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -5,7 +5,11 @@ #include <math.h> #include <time.h> +#define CONNECTION_PRIVATE +#define DIRECTORY_PRIVATE #define DIRVOTE_PRIVATE +#define ENTRYNODES_PRIVATE +#define HIBERNATE_PRIVATE #define NETWORKSTATUS_PRIVATE #define ROUTERLIST_PRIVATE #define TOR_UNIT_TESTING @@ -13,19 +17,24 @@ #include "config.h" #include "connection.h" #include "container.h" +#include "control.h" #include "directory.h" #include "dirvote.h" #include "entrynodes.h" +#include "hibernate.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "router.h" #include "routerlist.h" +#include "routerset.h" #include "routerparse.h" #include "shared_random.h" +#include "statefile.h" #include "test.h" #include "test_dir_common.h" +#include "log_test_helpers.h" void construct_consensus(char **consensus_text_md); @@ -411,6 +420,111 @@ test_router_pick_directory_server_impl(void *arg) networkstatus_vote_free(con_md); } +static or_state_t *dummy_state = NULL; +static or_state_t * +get_or_state_replacement(void) +{ + return dummy_state; +} + +static void +mock_directory_initiate_request(directory_request_t *req) +{ + (void)req; + return; +} + +static circuit_guard_state_t * +mock_circuit_guard_state_new(entry_guard_t *guard, unsigned state, + entry_guard_restriction_t *rst) +{ + (void) guard; + (void) state; + (void) rst; + return NULL; +} + +/** Test that we will use our directory guards to fetch mds even if we don't + * have any dirinfo (tests bug #23862). */ +static void +test_directory_guard_fetch_with_no_dirinfo(void *arg) +{ + int retval; + char *consensus_text_md = NULL; + or_options_t *options = get_options_mutable(); + + (void) arg; + + hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE); + + /* Initialize the SRV subsystem */ + MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); + mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); + sr_init(0); + UNMOCK(get_my_v3_authority_cert); + + /* Initialize the entry node configuration from the ticket */ + options->UseEntryGuards = 1; + options->StrictNodes = 1; + get_options_mutable()->EntryNodes = routerset_new(); + routerset_parse(get_options_mutable()->EntryNodes, + "2121212121212121212121212121212121212121", "foo"); + + /* Mock some functions */ + dummy_state = tor_malloc_zero(sizeof(or_state_t)); + MOCK(get_or_state, get_or_state_replacement); + MOCK(directory_initiate_request, mock_directory_initiate_request); + /* we need to mock this one to avoid memleaks */ + MOCK(circuit_guard_state_new, mock_circuit_guard_state_new); + + /* Call guards_update_all() to simulate loading our state file (see + * entry_guards_load_guards_from_state() and ticket #23989). */ + guards_update_all(); + + /* Test logic: Simulate the arrival of a new consensus when we have no + * dirinfo at all. Tor will need to fetch the mds from the consensus. Make + * sure that Tor will use the specified entry guard instead of relying on the + * fallback directories. */ + + /* Fixup the dirconn that will deliver the consensus */ + dir_connection_t *conn = dir_connection_new(AF_INET); + tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001); + conn->base_.port = 8800; + TO_CONN(conn)->address = tor_strdup("127.0.0.1"); + conn->base_.purpose = DIR_PURPOSE_FETCH_CONSENSUS; + conn->requested_resource = tor_strdup("ns"); + + /* Construct a consensus */ + construct_consensus(&consensus_text_md); + tt_assert(consensus_text_md); + + /* Place the consensus in the dirconn */ + response_handler_args_t args; + memset(&args, 0, sizeof(response_handler_args_t)); + args.status_code = 200; + args.body = consensus_text_md; + args.body_len = strlen(consensus_text_md); + + /* Update approx time so that the consensus is considered live */ + update_approx_time(time(NULL)+1010); + + setup_capture_of_logs(LOG_DEBUG); + + /* Now handle the consensus */ + retval = handle_response_fetch_consensus(conn, &args); + tt_int_op(retval, OP_EQ, 0); + + /* Make sure that our primary guard was chosen */ + expect_log_msg_containing("Selected primary guard router3"); + + done: + tor_free(consensus_text_md); + tor_free(dummy_state); + connection_free_minimal(TO_CONN(conn)); + entry_guards_free_all(); + teardown_capture_of_logs(); +} + static connection_t *mocked_connection = NULL; /* Mock connection_get_by_type_addr_port_purpose by returning @@ -494,6 +608,8 @@ struct testcase_t routerlist_tests[] = { NODE(launch_descriptor_downloads, 0), NODE(router_is_already_dir_fetching, TT_FORK), ROUTER(pick_directory_server_impl, TT_FORK), + { "directory_guard_fetch_with_no_dirinfo", + test_directory_guard_fetch_with_no_dirinfo, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index c9c69911da..c541324674 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #define ROUTERSET_PRIVATE #include "or.h" @@ -696,7 +699,7 @@ NS(test_main)(void *arg) static void NS(test_main)(void *arg) { - const routerset_t *set; + routerset_t *set; int needs_geoip; (void)arg; @@ -706,14 +709,14 @@ NS(test_main)(void *arg) set = routerset_new(); needs_geoip = routerset_needs_geoip(set); - routerset_free((routerset_t *)set); + routerset_free(set); tt_int_op(needs_geoip, OP_EQ, 0); set = NULL; set = routerset_new(); smartlist_add(set->country_names, tor_strndup("xx", 2)); needs_geoip = routerset_needs_geoip(set); - routerset_free((routerset_t *)set); + routerset_free(set); set = NULL; tt_int_op(needs_geoip, OP_NE, 0); @@ -1944,7 +1947,7 @@ NS(test_main)(void *arg) done: tor_free(s); - routerset_free((routerset_t *)set); + routerset_free(set); } #undef NS_SUBMODULE @@ -2081,28 +2084,28 @@ NS(test_main)(void *arg) * Structural test for routerset_free, where the routerset is NULL. */ -NS_DECL(void, smartlist_free, (smartlist_t *sl)); +NS_DECL(void, smartlist_free_, (smartlist_t *sl)); static void NS(test_main)(void *arg) { (void)arg; - NS_MOCK(smartlist_free); + NS_MOCK(smartlist_free_); - routerset_free(NULL); + routerset_free_(NULL); - tt_int_op(CALLED(smartlist_free), OP_EQ, 0); + tt_int_op(CALLED(smartlist_free_), OP_EQ, 0); done: ; } void -NS(smartlist_free)(smartlist_t *s) +NS(smartlist_free_)(smartlist_t *s) { (void)s; - CALLED(smartlist_free)++; + CALLED(smartlist_free_)++; } #undef NS_SUBMODULE @@ -2112,9 +2115,9 @@ NS(smartlist_free)(smartlist_t *s) * Structural test for routerset_free. */ -NS_DECL(void, smartlist_free, (smartlist_t *sl)); -NS_DECL(void, strmap_free,(strmap_t *map, void (*free_val)(void*))); -NS_DECL(void, digestmap_free, (digestmap_t *map, void (*free_val)(void*))); +NS_DECL(void, smartlist_free_, (smartlist_t *sl)); +NS_DECL(void, strmap_free_,(strmap_t *map, void (*free_val)(void*))); +NS_DECL(void, digestmap_free_, (digestmap_t *map, void (*free_val)(void*))); static void NS(test_main)(void *arg) @@ -2122,39 +2125,39 @@ NS(test_main)(void *arg) routerset_t *routerset = routerset_new(); (void)arg; - NS_MOCK(smartlist_free); - NS_MOCK(strmap_free); - NS_MOCK(digestmap_free); + NS_MOCK(smartlist_free_); + NS_MOCK(strmap_free_); + NS_MOCK(digestmap_free_); routerset_free(routerset); - tt_int_op(CALLED(smartlist_free), OP_NE, 0); - tt_int_op(CALLED(strmap_free), OP_NE, 0); - tt_int_op(CALLED(digestmap_free), OP_NE, 0); + tt_int_op(CALLED(smartlist_free_), OP_NE, 0); + tt_int_op(CALLED(strmap_free_), OP_NE, 0); + tt_int_op(CALLED(digestmap_free_), OP_NE, 0); done: ; } void -NS(smartlist_free)(smartlist_t *s) +NS(smartlist_free_)(smartlist_t *s) { - CALLED(smartlist_free)++; - smartlist_free__real(s); + CALLED(smartlist_free_)++; + smartlist_free___real(s); } void -NS(strmap_free)(strmap_t *map, void (*free_val)(void*)) +NS(strmap_free_)(strmap_t *map, void (*free_val)(void*)) { - CALLED(strmap_free)++; - strmap_free__real(map, free_val); + CALLED(strmap_free_)++; + strmap_free___real(map, free_val); } void -NS(digestmap_free)(digestmap_t *map, void (*free_val)(void*)) +NS(digestmap_free_)(digestmap_t *map, void (*free_val)(void*)) { - CALLED(digestmap_free)++; - digestmap_free__real(map, free_val); + CALLED(digestmap_free_)++; + digestmap_free___real(map, free_val); } #undef NS_SUBMODULE diff --git a/src/test/test_rust.c b/src/test/test_rust.c deleted file mode 100644 index 6ad57d6fcb..0000000000 --- a/src/test/test_rust.c +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "orconfig.h" -#include "compat_rust.h" -#include "test.h" -#include "util.h" - -static void -test_welcome_string(void *arg) -{ - (void)arg; - rust_str_t s = rust_welcome_string(); - const char *c_str = rust_str_get(s); - tt_assert(c_str); - size_t len = strlen(c_str); -#ifdef HAVE_RUST - tt_assert(len > 0); -#else - tt_assert(len == 0); -#endif - - done: - rust_str_free(s); -} - -struct testcase_t rust_tests[] = { - { "welcome_string", test_welcome_string, 0, NULL, NULL }, - END_OF_TESTCASES -}; - diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh index d559f94ce0..133f2bb940 100755 --- a/src/test/test_rust.sh +++ b/src/test/test_rust.sh @@ -1,13 +1,20 @@ #!/bin/sh -# Test all the Rust crates we're using +# Test all Rust crates -crates=tor_util +crates="protover tor_util smartlist tor_allocate" exitcode=0 +set -e + for crate in $crates; do - cd "${abs_top_srcdir:-.}/src/rust/${crate}" - CARGO_TARGET_DIR="${abs_top_builddir}/src/rust/target" CARGO_HOME="${abs_top_builddir}/src/rust" "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} || exitcode=1 + cd "${abs_top_builddir:-../../..}/src/rust" + CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \ + CARGO_HOME="${abs_top_builddir:-../../..}/src/rust" \ + "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \ + --manifest-path "${abs_top_srcdir:-.}/src/rust/${crate}/Cargo.toml" \ + || exitcode=1 + cd - done exit $exitcode diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c index 63add2f382..0d8a9eaa1f 100644 --- a/src/test/test_scheduler.c +++ b/src/test/test_scheduler.c @@ -299,10 +299,6 @@ channel_more_to_flush_mock(channel_t *chan) flush_mock_channel_t *found_mock_ch = NULL; - /* Check if we have any queued */ - if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) - return 1; - SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock, flush_mock_channel_t *, flush_mock_ch) { @@ -444,8 +440,6 @@ perform_channel_state_tests(int KISTSchedRunInterval, int sched_type) /* Start it off in OPENING */ ch1->state = CHANNEL_STATE_OPENING; - /* We'll need a cmux */ - ch1->cmux = circuitmux_alloc(); /* Try to register it */ channel_register(ch1); tt_assert(ch1->registered); @@ -457,7 +451,6 @@ perform_channel_state_tests(int KISTSchedRunInterval, int sched_type) ch2 = new_fake_channel(); tt_assert(ch2); ch2->state = CHANNEL_STATE_OPENING; - ch2->cmux = circuitmux_alloc(); channel_register(ch2); tt_assert(ch2->registered); @@ -656,8 +649,6 @@ test_scheduler_loop_vanilla(void *arg) /* Start it off in OPENING */ ch1->state = CHANNEL_STATE_OPENING; - /* We'll need a cmux */ - ch1->cmux = circuitmux_alloc(); /* Try to register it */ channel_register(ch1); tt_assert(ch1->registered); @@ -672,7 +663,6 @@ test_scheduler_loop_vanilla(void *arg) ch2->magic = TLS_CHAN_MAGIC; tt_assert(ch2); ch2->state = CHANNEL_STATE_OPENING; - ch2->cmux = circuitmux_alloc(); channel_register(ch2); tt_assert(ch2->registered); /* @@ -824,7 +814,6 @@ test_scheduler_loop_kist(void *arg) tt_assert(ch1); ch1->magic = TLS_CHAN_MAGIC; ch1->state = CHANNEL_STATE_OPENING; - ch1->cmux = circuitmux_alloc(); channel_register(ch1); tt_assert(ch1->registered); channel_change_state_open(ch1); @@ -835,7 +824,6 @@ test_scheduler_loop_kist(void *arg) tt_assert(ch2); ch2->magic = TLS_CHAN_MAGIC; ch2->state = CHANNEL_STATE_OPENING; - ch2->cmux = circuitmux_alloc(); channel_register(ch2); tt_assert(ch2->registered); channel_change_state_open(ch2); diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index cac78baecf..96494904e3 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #define SHARED_RANDOM_PRIVATE #define SHARED_RANDOM_STATE_PRIVATE #define CONFIG_PRIVATE @@ -1348,7 +1351,7 @@ test_state_update(void *arg) tt_assert(state->current_srv); done: - sr_state_free(); + sr_state_free_all(); UNMOCK(get_my_v3_authority_cert); } diff --git a/src/test/test_status.c b/src/test/test_status.c index f86f8e3b9e..50ea203e4d 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + #define STATUS_PRIVATE #define HIBERNATE_PRIVATE #define LOG_PRIVATE diff --git a/src/test/test_util.c b/src/test/test_util.c index 0519a4758f..1fd41a348a 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -5801,6 +5801,7 @@ test_util_monotonic_time(void *arg) monotime_coarse_t mtc1, mtc2; uint64_t nsec1, nsec2, usec1, msec1; uint64_t nsecc1, nsecc2, usecc1, msecc1; + uint32_t stamp1, stamp2; monotime_init(); @@ -5812,6 +5813,7 @@ test_util_monotonic_time(void *arg) nsecc1 = monotime_coarse_absolute_nsec(); usecc1 = monotime_coarse_absolute_usec(); msecc1 = monotime_coarse_absolute_msec(); + stamp1 = monotime_coarse_to_stamp(&mtc1); tor_sleep_msec(200); @@ -5819,6 +5821,7 @@ test_util_monotonic_time(void *arg) monotime_coarse_get(&mtc2); nsec2 = monotime_absolute_nsec(); nsecc2 = monotime_coarse_absolute_nsec(); + stamp2 = monotime_coarse_to_stamp(&mtc2); /* We need to be a little careful here since we don't know the system load. */ @@ -5840,6 +5843,11 @@ test_util_monotonic_time(void *arg) tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1); tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 1000); + uint64_t coarse_stamp_diff = + monotime_coarse_stamp_units_to_approx_msec(stamp2-stamp1); + tt_u64_op(coarse_stamp_diff, OP_GE, 120); + tt_u64_op(coarse_stamp_diff, OP_LE, 1200); + done: ; } @@ -5918,6 +5926,64 @@ test_util_monotonic_time_ratchet(void *arg) } static void +test_util_monotonic_time_zero(void *arg) +{ + (void) arg; + monotime_t t1; + monotime_coarse_t ct1; + monotime_init(); + /* Check 1: The current time is not zero. */ + monotime_get(&t1); + monotime_coarse_get(&ct1); + tt_assert(!monotime_is_zero(&t1)); + tt_assert(!monotime_coarse_is_zero(&ct1)); + + /* Check 2: The _zero() makes the time zero. */ + monotime_zero(&t1); + monotime_coarse_zero(&ct1); + tt_assert(monotime_is_zero(&t1)); + tt_assert(monotime_coarse_is_zero(&ct1)); + done: + ; +} + +static void +test_util_monotonic_time_add_msec(void *arg) +{ + (void) arg; + monotime_t t1, t2; + monotime_coarse_t ct1, ct2; + monotime_init(); + + monotime_get(&t1); + monotime_coarse_get(&ct1); + + /* adding zero does nothing */ + monotime_add_msec(&t2, &t1, 0); + monotime_coarse_add_msec(&ct2, &ct1, 0); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 0); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 0); + + /* Add 1337 msec; see if the diff function agree */ + monotime_add_msec(&t2, &t1, 1337); + monotime_coarse_add_msec(&ct2, &ct1, 1337); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337); + + /* Add 1337 msec twice more; make sure that any second rollover issues + * worked. */ + monotime_add_msec(&t2, &t2, 1337); + monotime_coarse_add_msec(&ct2, &ct2, 1337); + monotime_add_msec(&t2, &t2, 1337); + monotime_coarse_add_msec(&ct2, &ct2, 1337); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337*3); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337*3); + + done: + ; +} + +static void test_util_htonll(void *arg) { (void)arg; @@ -6150,6 +6216,8 @@ struct testcase_t util_tests[] = { UTIL_TEST(calloc_check, 0), UTIL_TEST(monotonic_time, 0), UTIL_TEST(monotonic_time_ratchet, TT_FORK), + UTIL_TEST(monotonic_time_zero, 0), + UTIL_TEST(monotonic_time_add_msec, 0), UTIL_TEST(htonll, 0), UTIL_TEST(get_unquoted_path, 0), END_OF_TESTCASES diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 7e9c47b48d..142c681079 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -3,12 +3,6 @@ * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -extern const char tor_git_revision[]; - -/* Ordinarily defined in tor_main.c; this bit is just here to provide one - * since we're not linking to tor_main.c */ -const char tor_git_revision[] = ""; - /** * \file test_common.c * \brief Common pieces to implement unit tests. @@ -299,6 +293,9 @@ main(int c, const char **v) setup_directory(); options_init(options); options->DataDirectory = tor_strdup(temp_dir); + tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys", + options->DataDirectory); + options->CacheDirectory = tor_strdup(temp_dir); options->EntryStatistics = 1; if (set_options(options, &errmsg) < 0) { printf("Failed to set initial options: %s\n", errmsg); |