diff options
Diffstat (limited to 'src/test')
60 files changed, 3022 insertions, 2038 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..92d7a244f7 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. @@ -718,11 +713,15 @@ main(int argc, const char **argv) printf("Couldn't seed RNG; exiting.\n"); return 1; } + + init_protocol_warning_severity_level(); crypto_init_siphash_key(); options = options_new(); init_logging(1); options->command = CMD_RUN_UNITTESTS; options->DataDirectory = tor_strdup(""); + options->KeyDirectory = tor_strdup(""); + options->CacheDirectory = tor_strdup(""); options_init(options); if (set_options(options, &errmsg) < 0) { printf("Failed to set initial options: %s\n", errmsg); 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..a96552f0fc 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) @@ -113,6 +110,9 @@ global_init(void) /* Make BUG() and nonfatal asserts crash */ tor_set_failed_assertion_callback(abort); + + /* Make protocol warnings handled correctly. */ + init_protocol_warning_severity_level(); } #ifdef LLVM_FUZZ diff --git a/src/test/include.am b/src/test/include.am index 230845a1ed..cc4f3e5c88 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -9,6 +9,7 @@ TESTS_ENVIRONMENT = \ export builddir="$(builddir)"; \ export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)"; \ export CARGO="$(CARGO)"; \ + export EXTRA_CARGO_OPTIONS="$(EXTRA_CARGO_OPTIONS)"; \ export CARGO_ONLINE="$(CARGO_ONLINE)"; TESTSCRIPTS = \ @@ -99,6 +100,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 \ @@ -110,11 +112,11 @@ src_test_test_SOURCES = \ src/test/test_controller_events.c \ src/test/test_crypto.c \ src/test/test_crypto_openssl.c \ - src/test/test_dos.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_dir_common.c \ src/test/test_dir_handle_get.c \ + src/test/test_dos.c \ src/test/test_entryconn.c \ src/test/test_entrynodes.c \ src/test/test_guardfraction.c \ @@ -127,6 +129,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 \ @@ -154,7 +157,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 \ @@ -358,3 +360,5 @@ EXTRA_DIST += \ src/test/test_workqueue_pipe2.sh \ src/test/test_workqueue_socketpair.sh +test-rust: + $(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh" 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 383bc00002..2712de4ed1 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -62,7 +62,6 @@ double fabs(double x); #include "routerparse.h" #include "statefile.h" #include "crypto_curve25519.h" -#include "onion_ntor.h" /** Run unit tests for the onion handshake code. */ static void @@ -174,7 +173,7 @@ test_bad_onion_handshake(void *arg) s_buf, s_keys, 40)); c_buf[64] ^= 33; - /* (Let the server procede) */ + /* (Let the server proceed) */ tt_int_op(0, OP_EQ, onion_skin_TAP_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); @@ -345,8 +344,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 +615,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) @@ -1197,6 +1196,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 }, @@ -1208,10 +1208,10 @@ struct testgroup_t testgroups[] = { { "control/event/", controller_event_tests }, { "crypto/", crypto_tests }, { "crypto/openssl/", crypto_openssl_tests }, - { "dos/", dos_tests }, { "dir/", dir_tests }, { "dir_handle_get/", dir_handle_get_tests }, { "dir/md/", microdesc_tests }, + { "dos/", dos_tests }, { "entryconn/", entryconn_tests }, { "entrynodes/", entrynodes_tests }, { "guardfraction/", guardfraction_tests }, @@ -1221,6 +1221,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 }, @@ -1247,7 +1248,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 3c12d2b673..26139fc5fe 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -189,6 +189,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[]; @@ -200,9 +201,9 @@ extern struct testcase_t controller_tests[]; extern struct testcase_t controller_event_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t crypto_openssl_tests[]; -extern struct testcase_t dos_tests[]; extern struct testcase_t dir_tests[]; extern struct testcase_t dir_handle_get_tests[]; +extern struct testcase_t dos_tests[]; extern struct testcase_t entryconn_tests[]; extern struct testcase_t entrynodes_tests[]; extern struct testcase_t guardfraction_tests[]; @@ -212,6 +213,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[]; @@ -241,7 +243,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_formats.c b/src/test/test_cell_formats.c index 007f7e3d3e..88cdef383f 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -477,7 +477,7 @@ test_cfmt_create_cells(void *arg) cell.command = CELL_CREATED; tt_int_op(-1, OP_EQ, create_cell_parse(&cc, &cell)); - /* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */ + /* You can't actually make an unparseable CREATE or CREATE_FAST cell. */ /* Try some CREATE2 cells. First with a bad type. */ cell.command = CELL_CREATE2; 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 391ead3c72..90da2163a6 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); @@ -444,7 +457,7 @@ test_channelpadding_killonehop(void *arg) tt_assert(relay3_client->padding_enabled); tt_assert(client_relay3->padding_enabled); get_options_mutable()->Tor2webMode = 1; - /* For the relay to recieve the negotiate: */ + /* For the relay to receive the negotiate: */ get_options_mutable()->ORPort_set = 1; decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD); @@ -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); @@ -514,7 +530,7 @@ test_channelpadding_killonehop(void *arg) // Test client side (it should stop immediately) get_options_mutable()->HiddenServiceSingleHopMode = 1; get_options_mutable()->HiddenServiceNonAnonymousMode = 1; - /* For the relay to recieve the negotiate: */ + /* For the relay to receive the negotiate: */ get_options_mutable()->ORPort_set = 1; decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD); @@ -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); @@ -817,7 +838,7 @@ test_channelpadding_negotiation(void *arg) get_options_mutable()->ORPort_set = 0; /* Test case #2: Torrc options */ - /* ConnectionPadding auto; Relay doesn't suport us */ + /* ConnectionPadding auto; Relay doesn't support us */ ((channel_tls_t*)relay3_client)->conn->link_proto = 4; relay3_client->padding_enabled = 0; tried_to_write_cell = 0; @@ -828,7 +849,7 @@ test_channelpadding_negotiation(void *arg) ((channel_tls_t*)relay3_client)->conn->link_proto = 5; relay3_client->padding_enabled = 1; - /* ConnectionPadding 1; Relay doesn't suport us */ + /* ConnectionPadding 1; Relay doesn't support us */ get_options_mutable()->ConnectionPadding = 1; tried_to_write_cell = 0; decision = channelpadding_decide_to_pad_channel(client_relay3); @@ -944,6 +965,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); @@ -960,7 +984,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); @@ -968,23 +992,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); @@ -995,16 +1023,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); @@ -1012,7 +1041,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); @@ -1020,7 +1049,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); @@ -1031,9 +1060,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); @@ -1041,7 +1071,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); @@ -1051,9 +1081,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); @@ -1062,16 +1093,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); @@ -1090,7 +1122,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); @@ -1100,9 +1132,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..8ebef659ca --- /dev/null +++ b/src/test/test_circuitstats.c @@ -0,0 +1,201 @@ +/* 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); + + tor_free(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..e214a82771 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -323,7 +323,7 @@ test_config_write_to_data_subdir(void *arg) tt_int_op(mkdir(options->DataDirectory, 0700), OP_EQ, 0); #endif - // Write attempt shoudl fail, if subdirectory doesn't exist. + // Write attempt should fail, if subdirectory doesn't exist. tt_assert(write_to_data_subdir(subdir, fname, str, NULL)); tt_assert(! check_or_create_data_subdir(subdir)); @@ -585,6 +585,22 @@ test_config_parse_transport_options_line(void *arg) } } +/* Mocks needed for the compute_max_mem_in_queues test */ +static int get_total_system_memory_mock(size_t *mem_out); + +static size_t total_system_memory_output = 0; +static int total_system_memory_return = 0; + +static int +get_total_system_memory_mock(size_t *mem_out) +{ + if (! mem_out) + return -1; + + *mem_out = total_system_memory_output; + return total_system_memory_return; +} + /* Mocks needed for the transport plugin line test */ static void pt_kickstart_proxy_mock(const smartlist_t *transport_list, @@ -1391,7 +1407,7 @@ test_config_resolve_my_address(void *arg) * if running on. * 3. Hostname from previous step cannot be converted to * address by using tor_inet_aton() function. - * 4. However, tor_lookup_hostname() succeds in resolving the + * 4. However, tor_lookup_hostname() succeeds in resolving the * hostname from step 2. * 5. Unfortunately, tor_addr_is_internal() deems this address * to be internal. @@ -4833,7 +4849,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 +4879,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 +4911,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 +4953,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 +4991,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 +5048,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 +5113,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 +5202,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 +5256,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 +5311,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 +5533,153 @@ 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); +} + +static void +test_config_compute_max_mem_in_queues(void *data) +{ +#define GIGABYTE(x) (U64_LITERAL(x) << 30) +#define MEGABYTE(x) (U64_LITERAL(x) << 20) + (void)data; + MOCK(get_total_system_memory, get_total_system_memory_mock); + + /* We are unable to detect the amount of memory on the system. Tor will try + * to use some sensible default values for 64-bit and 32-bit systems. */ + total_system_memory_return = -1; + +#if SIZEOF_VOID_P >= 8 + /* We are on a 64-bit system. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, GIGABYTE(8)); +#else + /* We are on a 32-bit system. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, GIGABYTE(1)); +#endif + + /* We are able to detect the amount of RAM on the system. */ + total_system_memory_return = 0; + + /* We are running on a system with one gigabyte of RAM. */ + total_system_memory_output = GIGABYTE(1); + + /* We have 0.75 * RAM available. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, + 3 * (GIGABYTE(1) / 4)); + + /* We are running on a tiny machine with 256 MB of RAM. */ + total_system_memory_output = MEGABYTE(256); + + /* We will now enforce a minimum of 256 MB of RAM available for the + * MaxMemInQueues here, even though we should only have had 0.75 * 256 = 192 + * MB available. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, MEGABYTE(256)); + +#if SIZEOF_SIZE_T > 4 + /* We are running on a machine with 8 GB of RAM. */ + total_system_memory_output = GIGABYTE(8); + + /* We will have 0.4 * RAM available. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, + 2 * (GIGABYTE(8) / 5)); + + /* We are running on a machine with 16 GB of RAM. */ + total_system_memory_output = GIGABYTE(16); + + /* We will have 0.4 * RAM available. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, + 2 * (GIGABYTE(16) / 5)); + + /* We are running on a machine with 32 GB of RAM. */ + total_system_memory_output = GIGABYTE(32); + + /* We will at maximum get MAX_DEFAULT_MEMORY_QUEUE_SIZE here. */ + tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, + MAX_DEFAULT_MEMORY_QUEUE_SIZE); +#endif + + done: + UNMOCK(get_total_system_memory); + +#undef GIGABYTE +#undef MEGABYTE +} + #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } @@ -5563,6 +5727,8 @@ 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), + CONFIG_TEST(compute_max_mem_in_queues, 0), END_OF_TESTCASES }; diff --git a/src/test/test_connection.c b/src/test/test_connection.c index 314b90cfda..dc0f6860d9 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -5,6 +5,7 @@ #define CONNECTION_PRIVATE #define MAIN_PRIVATE +#define CONNECTION_OR_PRIVATE #include "or.h" #include "test.h" @@ -13,9 +14,11 @@ #include "hs_common.h" #include "main.h" #include "microdesc.h" +#include "nodelist.h" #include "networkstatus.h" #include "rendcache.h" #include "directory.h" +#include "connection_or.h" #include "test_connection.h" #include "test_helpers.h" @@ -776,10 +779,103 @@ test_conn_download_status(void *arg) /* the teardown function removes all the connections in the global list*/; } +static node_t test_node; + +static node_t * +mock_node_get_mutable_by_id(const char *digest) +{ + (void) digest; + static routerinfo_t node_ri; + memset(&node_ri, 0, sizeof(node_ri)); + + test_node.ri = &node_ri; + memset(test_node.identity, 'c', sizeof(test_node.identity)); + + tor_addr_t ipv4_addr; + tor_addr_parse(&ipv4_addr, "18.0.0.1"); + node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr); + node_ri.or_port = 1; + + return &test_node; +} + +static const node_t * +mock_node_get_by_id(const char *digest) +{ + (void) digest; + memset(test_node.identity, 'c', sizeof(test_node.identity)); + return &test_node; +} + +/* Test whether we correctly track failed connections between relays. */ +static void +test_failed_orconn_tracker(void *arg) +{ + (void) arg; + + int can_connect; + time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ + (void) now; + + update_approx_time(now); + + /* Prepare the OR connection that will be used in this test */ + or_connection_t or_conn; + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, "18.0.0.1")); + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1")); + or_conn.base_.port = 1; + memset(or_conn.identity_digest, 'c', sizeof(or_conn.identity_digest)); + + /* Check whether we can connect with an empty failure cache: + * this should succeed */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Now add the destination to the failure cache */ + note_or_connect_failed(&or_conn); + + /* Check again: now it shouldn't connect */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 0); + + /* Move time forward and check again: the cache should have been cleared and + * now it should connect */ + now += 3600; + update_approx_time(now); + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Now mock the node_get_*by_id() functions to start using the node subsystem + * optimization. */ + MOCK(node_get_by_id, mock_node_get_by_id); + MOCK(node_get_mutable_by_id, mock_node_get_mutable_by_id); + + /* Since we just started using the node subsystem it will allow connections + * now */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Mark it as failed */ + note_or_connect_failed(&or_conn); + + /* Check that it shouldn't connect now */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 0); + + /* Move time forward and check again: now it should connect */ + now += 3600; + update_approx_time(now); + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + done: + ; +} + #define CONNECTION_TESTCASE(name, fork, setup) \ { #name, test_conn_##name, fork, &setup, NULL } -/* where arg is an expression (constant, varaible, compound expression) */ +/* where arg is an expression (constant, variable, compound expression) */ #define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \ { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg } @@ -792,6 +888,7 @@ struct testcase_t connection_tests[] = { CONNECTION_TESTCASE_ARG(download_status, TT_FORK, test_conn_download_status_st, FLAV_NS), //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), + { "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL }, 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..1c285bb3a2 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); @@ -301,7 +396,7 @@ test_add_onion_helper_clientauth(void *arg) static const download_status_t dl_status_default = { 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }; + DL_SCHED_INCREMENT_FAILURE, 0, 0 }; static download_status_t ns_dl_status[N_CONSENSUS_FLAVORS]; static download_status_t ns_dl_status_bootstrap[N_CONSENSUS_FLAVORS]; static download_status_t ns_dl_status_running[N_CONSENSUS_FLAVORS]; @@ -312,7 +407,7 @@ static download_status_t ns_dl_status_running[N_CONSENSUS_FLAVORS]; */ static const download_status_t dls_sample_1 = { 1467163900, 0, 0, DL_SCHED_GENERIC, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_DETERMINISTIC, 0, 0 }; + DL_SCHED_INCREMENT_FAILURE, 0, 0 }; static const char * dls_sample_1_str = "next-attempt-at 2016-06-29 01:31:40\n" "n-download-failures 0\n" @@ -320,10 +415,12 @@ static const char * dls_sample_1_str = "schedule DL_SCHED_GENERIC\n" "want-authority DL_WANT_ANY_DIRSERVER\n" "increment-on DL_SCHED_INCREMENT_FAILURE\n" - "backoff DL_SCHED_DETERMINISTIC\n"; + "backoff DL_SCHED_RANDOM_EXPONENTIAL\n" + "last-backoff-position 0\n" + "last-delay-used 0\n"; static const download_status_t dls_sample_2 = { 1467164400, 1, 2, DL_SCHED_CONSENSUS, DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_DETERMINISTIC, 0, 0 }; + DL_SCHED_INCREMENT_FAILURE, 0, 0 }; static const char * dls_sample_2_str = "next-attempt-at 2016-06-29 01:40:00\n" "n-download-failures 1\n" @@ -331,10 +428,12 @@ static const char * dls_sample_2_str = "schedule DL_SCHED_CONSENSUS\n" "want-authority DL_WANT_AUTHORITY\n" "increment-on DL_SCHED_INCREMENT_FAILURE\n" - "backoff DL_SCHED_DETERMINISTIC\n"; + "backoff DL_SCHED_RANDOM_EXPONENTIAL\n" + "last-backoff-position 0\n" + "last-delay-used 0\n"; static const download_status_t dls_sample_3 = { 1467154400, 12, 25, DL_SCHED_BRIDGE, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_DETERMINISTIC, 0, 0 }; + DL_SCHED_INCREMENT_ATTEMPT, 0, 0 }; static const char * dls_sample_3_str = "next-attempt-at 2016-06-28 22:53:20\n" "n-download-failures 12\n" @@ -342,10 +441,12 @@ static const char * dls_sample_3_str = "schedule DL_SCHED_BRIDGE\n" "want-authority DL_WANT_ANY_DIRSERVER\n" "increment-on DL_SCHED_INCREMENT_ATTEMPT\n" - "backoff DL_SCHED_DETERMINISTIC\n"; + "backoff DL_SCHED_RANDOM_EXPONENTIAL\n" + "last-backoff-position 0\n" + "last-delay-used 0\n"; static const download_status_t dls_sample_4 = { 1467166600, 3, 0, DL_SCHED_GENERIC, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }; + DL_SCHED_INCREMENT_FAILURE, 0, 0 }; static const char * dls_sample_4_str = "next-attempt-at 2016-06-29 02:16:40\n" "n-download-failures 3\n" @@ -358,7 +459,7 @@ static const char * dls_sample_4_str = "last-delay-used 0\n"; static const download_status_t dls_sample_5 = { 1467164600, 3, 7, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 1, 2112, }; + DL_SCHED_INCREMENT_FAILURE, 1, 2112, }; static const char * dls_sample_5_str = "next-attempt-at 2016-06-29 01:43:20\n" "n-download-failures 3\n" @@ -371,7 +472,7 @@ static const char * dls_sample_5_str = "last-delay-used 2112\n"; static const download_status_t dls_sample_6 = { 1467164200, 4, 9, DL_SCHED_CONSENSUS, DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_RANDOM_EXPONENTIAL, 3, 432 }; + DL_SCHED_INCREMENT_ATTEMPT, 3, 432 }; static const char * dls_sample_6_str = "next-attempt-at 2016-06-29 01:36:40\n" "n-download-failures 4\n" @@ -1370,7 +1471,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 b21ce5048c..165029d232 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(); } @@ -1270,7 +1270,7 @@ test_dir_versions(void *arg) tt_int_op(0,OP_EQ, tor_version_as_new_as( "Tor 0.2.9.9 (git-00)", "Tor 0.2.9.9 (git-01)")); - /* In #21278, we comapre without integer overflows. + /* In #21278, we compare without integer overflows. * But since #21450 limits version components to [0, INT32_MAX], it is no * longer possible to cause an integer overflow in tor_version_compare() */ tt_int_op(0,OP_EQ, tor_version_as_new_as( @@ -3984,164 +3984,11 @@ test_dir_packages(void *arg) } static void -test_dir_download_status_schedule(void *arg) -{ - (void)arg; - download_status_t dls_failure = { 0, 0, 0, DL_SCHED_GENERIC, - DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_FAILURE, - DL_SCHED_DETERMINISTIC, 0, 0 }; - download_status_t dls_attempt = { 0, 0, 0, DL_SCHED_CONSENSUS, - DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_ATTEMPT, - DL_SCHED_DETERMINISTIC, 0, 0 }; - download_status_t dls_bridge = { 0, 0, 0, DL_SCHED_BRIDGE, - DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_FAILURE, - DL_SCHED_DETERMINISTIC, 0, 0 }; - int increment = -1; - int expected_increment = -1; - time_t current_time = time(NULL); - int delay1 = -1; - int delay2 = -1; - smartlist_t *schedule = smartlist_new(); - - /* Make a dummy schedule */ - smartlist_add(schedule, (void *)&delay1); - smartlist_add(schedule, (void *)&delay2); - - /* check a range of values */ - delay1 = 1000; - increment = download_status_schedule_get_delay(&dls_failure, - schedule, - 0, INT_MAX, - TIME_MIN); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_failure.next_attempt_at == TIME_MIN + expected_increment); - - delay1 = INT_MAX; - increment = download_status_schedule_get_delay(&dls_failure, - schedule, - 0, INT_MAX, - -1); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_failure.next_attempt_at == TIME_MAX); - - delay1 = 0; - increment = download_status_schedule_get_delay(&dls_attempt, - schedule, - 0, INT_MAX, - 0); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_attempt.next_attempt_at == 0 + expected_increment); - - delay1 = 1000; - increment = download_status_schedule_get_delay(&dls_attempt, - schedule, - 0, INT_MAX, - 1); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_attempt.next_attempt_at == 1 + expected_increment); - - delay1 = INT_MAX; - increment = download_status_schedule_get_delay(&dls_bridge, - schedule, - 0, INT_MAX, - current_time); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_bridge.next_attempt_at == TIME_MAX); - - delay1 = 1; - increment = download_status_schedule_get_delay(&dls_bridge, - schedule, - 0, INT_MAX, - TIME_MAX); - expected_increment = delay1; - tt_assert(increment == expected_increment); - tt_assert(dls_bridge.next_attempt_at == TIME_MAX); - - /* see what happens when we reach the end */ - dls_attempt.n_download_attempts++; - dls_bridge.n_download_failures++; - - delay2 = 100; - increment = download_status_schedule_get_delay(&dls_attempt, - schedule, - 0, INT_MAX, - current_time); - expected_increment = delay2; - tt_assert(increment == expected_increment); - tt_assert(dls_attempt.next_attempt_at == current_time + delay2); - - delay2 = 1; - increment = download_status_schedule_get_delay(&dls_bridge, - schedule, - 0, INT_MAX, - current_time); - expected_increment = delay2; - tt_assert(increment == expected_increment); - tt_assert(dls_bridge.next_attempt_at == current_time + delay2); - - /* see what happens when we try to go off the end */ - dls_attempt.n_download_attempts++; - dls_bridge.n_download_failures++; - - delay2 = 5; - increment = download_status_schedule_get_delay(&dls_attempt, - schedule, - 0, INT_MAX, - current_time); - expected_increment = delay2; - tt_assert(increment == expected_increment); - tt_assert(dls_attempt.next_attempt_at == current_time + delay2); - - delay2 = 17; - increment = download_status_schedule_get_delay(&dls_bridge, - schedule, - 0, INT_MAX, - current_time); - expected_increment = delay2; - tt_assert(increment == expected_increment); - tt_assert(dls_bridge.next_attempt_at == current_time + delay2); - - /* see what happens when we reach IMPOSSIBLE_TO_DOWNLOAD */ - dls_attempt.n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD; - dls_bridge.n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; - - delay2 = 35; - increment = download_status_schedule_get_delay(&dls_attempt, - schedule, - 0, INT_MAX, - current_time); - expected_increment = INT_MAX; - tt_assert(increment == expected_increment); - tt_assert(dls_attempt.next_attempt_at == TIME_MAX); - - delay2 = 99; - increment = download_status_schedule_get_delay(&dls_bridge, - schedule, - 0, INT_MAX, - current_time); - expected_increment = INT_MAX; - tt_assert(increment == expected_increment); - tt_assert(dls_bridge.next_attempt_at == TIME_MAX); - - done: - /* the pointers in schedule are allocated on the stack */ - smartlist_free(schedule); -} - -static void -download_status_random_backoff_helper(int min_delay, int max_delay) +download_status_random_backoff_helper(int min_delay) { download_status_t dls_random = { 0, 0, 0, DL_SCHED_GENERIC, DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }; + DL_SCHED_INCREMENT_FAILURE, 0, 0 }; int increment = -1; int old_increment = -1; time_t current_time = time(NULL); @@ -4150,23 +3997,21 @@ download_status_random_backoff_helper(int min_delay, int max_delay) int n_attempts = 0; do { increment = download_status_schedule_get_delay(&dls_random, - NULL, - min_delay, max_delay, + min_delay, current_time); - log_debug(LD_DIR, "Min: %d, Max: %d, Inc: %d, Old Inc: %d", - min_delay, max_delay, increment, old_increment); + log_debug(LD_DIR, "Min: %d, Inc: %d, Old Inc: %d", + min_delay, increment, old_increment); /* Regression test for 20534 and friends * increment must always increase after the first */ - if (dls_random.last_backoff_position > 0 && max_delay > 0) { + if (dls_random.last_backoff_position > 0) { /* Always increment the exponential backoff */ tt_int_op(increment, OP_GE, 1); } /* Test */ tt_int_op(increment, OP_GE, min_delay); - tt_int_op(increment, OP_LE, max_delay); /* Advance */ if (dls_random.n_download_attempts < IMPOSSIBLE_TO_DOWNLOAD - 1) { @@ -4176,7 +4021,7 @@ download_status_random_backoff_helper(int min_delay, int max_delay) /* Try another maybe */ old_increment = increment; - } while (increment < max_delay && ++n_attempts < 1000); + } while (++n_attempts < 1000); done: return; @@ -4188,19 +4033,13 @@ test_dir_download_status_random_backoff(void *arg) (void)arg; /* Do a standard test */ - download_status_random_backoff_helper(0, 1000000); - /* Regression test for 20534 and friends: - * try tighter bounds */ - download_status_random_backoff_helper(0, 100); + download_status_random_backoff_helper(0); /* regression tests for 17750: initial delay */ - download_status_random_backoff_helper(10, 1000); - download_status_random_backoff_helper(20, 30); + download_status_random_backoff_helper(10); + download_status_random_backoff_helper(20); /* Pathological cases */ - download_status_random_backoff_helper(0, 0); - download_status_random_backoff_helper(1, 1); - download_status_random_backoff_helper(0, INT_MAX); - download_status_random_backoff_helper(INT_MAX/2, INT_MAX); + download_status_random_backoff_helper(INT_MAX/2); } static void @@ -4239,18 +4078,10 @@ static void test_dir_download_status_increment(void *arg) { (void)arg; - download_status_t dls_failure = { 0, 0, 0, DL_SCHED_GENERIC, - DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_FAILURE, - DL_SCHED_DETERMINISTIC, 0, 0 }; - download_status_t dls_attempt = { 0, 0, 0, DL_SCHED_BRIDGE, - DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_ATTEMPT, - DL_SCHED_DETERMINISTIC, 0, 0 }; download_status_t dls_exp = { 0, 0, 0, DL_SCHED_GENERIC, DL_WANT_ANY_DIRSERVER, DL_SCHED_INCREMENT_ATTEMPT, - DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }; + 0, 0 }; int no_delay = 0; int delay0 = -1; int delay1 = -1; @@ -4258,7 +4089,6 @@ test_dir_download_status_increment(void *arg) smartlist_t *schedule = smartlist_new(); smartlist_t *schedule_no_initial_delay = smartlist_new(); or_options_t test_options; - time_t next_at = TIME_MAX; time_t current_time = time(NULL); /* Provide some values for the schedules */ @@ -4291,26 +4121,6 @@ test_dir_download_status_increment(void *arg) mock_get_options_calls = 0; /* we really want to test that it's equal to time(NULL) + delay0, but that's * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_failure) - >= current_time + no_delay); - tt_assert(download_status_get_next_attempt_at(&dls_failure) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* regression test for 17750: initial delay */ - mock_options->TestingClientDownloadSchedule = schedule; - mock_get_options_calls = 0; - /* we really want to test that it's equal to time(NULL) + delay0, but that's - * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_failure) - >= current_time + delay0); - tt_assert(download_status_get_next_attempt_at(&dls_failure) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); /* regression test for 17750: exponential, no initial delay */ mock_options->TestingClientDownloadSchedule = schedule_no_initial_delay; @@ -4338,258 +4148,6 @@ test_dir_download_status_increment(void *arg) tt_int_op(download_status_get_n_attempts(&dls_exp), OP_EQ, 0); tt_int_op(mock_get_options_calls, OP_GE, 1); - /* Check that a failure reset works */ - mock_get_options_calls = 0; - download_status_reset(&dls_failure); - /* we really want to test that it's equal to time(NULL) + delay0, but that's - * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_failure) - >= current_time + delay0); - tt_assert(download_status_get_next_attempt_at(&dls_failure) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* avoid timing inconsistencies */ - dls_failure.next_attempt_at = current_time + delay0; - - /* check that a reset schedule becomes ready at the right time */ - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay0 - 1, 1), - OP_EQ, 0); - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay0, 1), - OP_EQ, 1); - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay0 + 1, 1), - OP_EQ, 1); - - /* Check that a failure increment works */ - mock_get_options_calls = 0; - next_at = download_status_increment_failure(&dls_failure, 404, "test", 0, - current_time); - tt_assert(next_at == current_time + delay1); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 1); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 1); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* check that an incremented schedule becomes ready at the right time */ - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay1 - 1, 1), - OP_EQ, 0); - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay1, 1), - OP_EQ, 1); - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay1 + 1, 1), - OP_EQ, 1); - - /* check that a schedule isn't ready if it's had too many failures */ - tt_int_op(download_status_is_ready(&dls_failure, - current_time + delay1 + 10, 0), - OP_EQ, 0); - - /* Check that failure increments do happen on 503 for clients, and - * attempt increments do too. */ - mock_get_options_calls = 0; - next_at = download_status_increment_failure(&dls_failure, 503, "test", 0, - current_time); - tt_i64_op(next_at, OP_EQ, current_time + delay2); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 2); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 2); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check that failure increments do happen on 503 for servers */ - mock_get_options_calls = 0; - next_at = download_status_increment_failure(&dls_failure, 503, "test", 1, - current_time); - tt_assert(next_at == current_time + delay2); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 3); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 3); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check what happens when we run off the end of the schedule */ - mock_get_options_calls = 0; - next_at = download_status_increment_failure(&dls_failure, 404, "test", 0, - current_time); - tt_assert(next_at == current_time + delay2); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 4); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 4); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check what happens when we hit the failure limit */ - mock_get_options_calls = 0; - download_status_mark_impossible(&dls_failure); - next_at = download_status_increment_failure(&dls_failure, 404, "test", 0, - current_time); - tt_assert(next_at == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check that a failure reset doesn't reset at the limit */ - mock_get_options_calls = 0; - download_status_reset(&dls_failure); - tt_assert(download_status_get_next_attempt_at(&dls_failure) - == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(mock_get_options_calls, OP_EQ, 0); - - /* Check that a failure reset resets just before the limit */ - mock_get_options_calls = 0; - dls_failure.n_download_failures = IMPOSSIBLE_TO_DOWNLOAD - 1; - dls_failure.n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD - 1; - download_status_reset(&dls_failure); - /* we really want to test that it's equal to time(NULL) + delay0, but that's - * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_failure) - >= current_time + delay0); - tt_assert(download_status_get_next_attempt_at(&dls_failure) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check that failure increments do happen on attempt-based schedules, - * but that the retry is set at the end of time */ - mock_options->UseBridges = 1; - mock_get_options_calls = 0; - next_at = download_status_increment_failure(&dls_attempt, 404, "test", 0, - current_time); - tt_assert(next_at == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 1); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check that an attempt reset works */ - mock_get_options_calls = 0; - download_status_reset(&dls_attempt); - /* we really want to test that it's equal to time(NULL) + delay0, but that's - * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_attempt) - >= current_time + delay0); - tt_assert(download_status_get_next_attempt_at(&dls_attempt) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* avoid timing inconsistencies */ - dls_attempt.next_attempt_at = current_time + delay0; - - /* check that a reset schedule becomes ready at the right time */ - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay0 - 1, 1), - OP_EQ, 0); - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay0, 1), - OP_EQ, 1); - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay0 + 1, 1), - OP_EQ, 1); - - /* Check that an attempt increment works */ - mock_get_options_calls = 0; - next_at = download_status_increment_attempt(&dls_attempt, "test", - current_time); - tt_assert(next_at == current_time + delay1); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 1); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* check that an incremented schedule becomes ready at the right time */ - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay1 - 1, 1), - OP_EQ, 0); - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay1, 1), - OP_EQ, 1); - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay1 + 1, 1), - OP_EQ, 1); - - /* check that a schedule isn't ready if it's had too many attempts */ - tt_int_op(download_status_is_ready(&dls_attempt, - current_time + delay1 + 10, 0), - OP_EQ, 0); - - /* Check what happens when we reach then run off the end of the schedule */ - mock_get_options_calls = 0; - next_at = download_status_increment_attempt(&dls_attempt, "test", - current_time); - tt_assert(next_at == current_time + delay2); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 2); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - mock_get_options_calls = 0; - next_at = download_status_increment_attempt(&dls_attempt, "test", - current_time); - tt_assert(next_at == current_time + delay2); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 3); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check what happens when we hit the attempt limit */ - mock_get_options_calls = 0; - download_status_mark_impossible(&dls_attempt); - next_at = download_status_increment_attempt(&dls_attempt, "test", - current_time); - tt_assert(next_at == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(mock_get_options_calls, OP_GE, 1); - - /* Check that an attempt reset doesn't reset at the limit */ - mock_get_options_calls = 0; - download_status_reset(&dls_attempt); - tt_assert(download_status_get_next_attempt_at(&dls_attempt) - == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, - IMPOSSIBLE_TO_DOWNLOAD); - tt_int_op(mock_get_options_calls, OP_EQ, 0); - - /* Check that an attempt reset resets just before the limit */ - mock_get_options_calls = 0; - dls_attempt.n_download_failures = IMPOSSIBLE_TO_DOWNLOAD - 1; - dls_attempt.n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD - 1; - download_status_reset(&dls_attempt); - /* we really want to test that it's equal to time(NULL) + delay0, but that's - * an unrealiable test, because time(NULL) might change. */ - tt_assert(download_status_get_next_attempt_at(&dls_attempt) - >= current_time + delay0); - tt_assert(download_status_get_next_attempt_at(&dls_attempt) - != TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_GE, 1); - mock_options->UseBridges = 0; - - /* Check that attempt increments don't happen on failure-based schedules, - * and that the attempt is set at the end of time */ - mock_get_options_calls = 0; - setup_full_capture_of_logs(LOG_WARN); - next_at = download_status_increment_attempt(&dls_failure, "test", - current_time); - expect_single_log_msg_containing( - "Tried to launch an attempt-based connection on a failure-based " - "schedule."); - teardown_capture_of_logs(); - tt_assert(next_at == TIME_MAX); - tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0); - tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0); - tt_int_op(mock_get_options_calls, OP_EQ, 0); - done: /* the pointers in schedule are allocated on the stack */ smartlist_free(schedule); @@ -4893,9 +4451,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; /* @@ -5052,7 +4612,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); /* @@ -5570,7 +5130,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); @@ -6193,6 +5753,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 = approx_time() - 60; + has_ipv6 = networkstatus_consensus_has_ipv6(get_options()); + tt_assert(has_ipv6); + + /* Not reasonably live */ + mock_networkstatus->valid_after = approx_time() - 24*60*60 - 3600; + mock_networkstatus->valid_until = approx_time() - 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 } @@ -6236,7 +5896,6 @@ struct testcase_t dir_tests[] = { DIR(post_parsing, 0), DIR(fetch_type, 0), DIR(packages, 0), - DIR(download_status_schedule, 0), DIR(download_status_random_backoff, 0), DIR(download_status_random_backoff_ranges, 0), DIR(download_status_increment, TT_FORK), @@ -6261,6 +5920,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, TT_FORK), 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 7d85b09e03..505e09e36f 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -2030,7 +2030,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg) tt_mem_op(g->identity, OP_NE, g_prev->identity, DIGEST_LEN); tt_int_op(g->is_primary, OP_EQ, 1); tt_i64_op(g->last_tried_to_connect, OP_EQ, start+60); - tt_int_op(g->confirmed_idx, OP_EQ, -1); // not confirmd now. + tt_int_op(g->confirmed_idx, OP_EQ, -1); // not confirmed now. /* Call this one up; watch it get confirmed. */ update_approx_time(start+90); @@ -2378,8 +2378,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 09db176df8..07daebc164 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"; @@ -360,6 +361,7 @@ test_pick_tor2web_rendezvous_node(void *arg) /* Parse Tor2webRendezvousPoints as a routerset. */ options->Tor2webRendezvousPoints = routerset_new(); + options->UseMicrodescriptors = 0; retval = routerset_parse(options->Tor2webRendezvousPoints, tor2web_rendezvous_str, "test_tor2web_rp"); @@ -1012,7 +1014,7 @@ test_prune_services_on_reload(void *arg) set_rend_service_list(old); set_rend_rend_service_staging_list(new); rend_service_prune_list_impl_(); - /* Check if they've all been transfered. */ + /* Check if they've all been transferred. */ tt_int_op(smartlist_len(old), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 2); } 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_common.c b/src/test/test_hs_common.c index 3ae623ed0a..16803dbd16 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -290,7 +290,7 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns, memcpy(rs->identity_digest, identity, DIGEST_LEN); rs->is_hs_dir = is_hsdir; - rs->supports_v3_hsdir = 1; + rs->pv.supports_v3_hsdir = 1; strlcpy(rs->nickname, nickname, sizeof(rs->nickname)); tor_addr_parse(&ipv4_addr, "1.2.3.4"); ri->addr = tor_addr_to_ipv4h(&ipv4_addr); @@ -307,7 +307,8 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns, node = node_get_mutable_by_id(ri->cache_info.identity_digest); tt_assert(node); node->rs = rs; - /* We need this to exist for node_has_descriptor() to return true. */ + /* We need this to exist for node_has_preferred_descriptor() to return + * true. */ node->md = tor_malloc_zero(sizeof(microdesc_t)); /* Do this now the nodelist_set_routerinfo() function needs a "rs" to set * the indexes which it doesn't have when it is called. */ 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_descriptor.c b/src/test/test_hs_descriptor.c index 897b441888..8772461f90 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -415,7 +415,7 @@ test_decode_invalid_intro_point(void *arg) (void) arg; - /* Seperate pieces of a valid encoded introduction point. */ + /* Separate pieces of a valid encoded introduction point. */ const char *intro_point = "introduction-point AQIUMDI5OUYyNjhGQ0E5RDU1Q0QxNTc="; const char *auth_key = diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index b2d2700f8b..5b75e38935 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -146,7 +146,7 @@ helper_create_introduce1_cell(void) memcpy(auth_key_ptr, auth_key_kp.pubkey.pubkey, auth_key_len); } - /* Set the cell extentions to none. */ + /* Set the cell extensions to none. */ { trn_cell_extension_t *ext = trn_cell_extension_new(); trn_cell_extension_set_num(ext, 0); @@ -201,7 +201,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 */ @@ -235,7 +235,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. */ @@ -270,7 +270,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. */ @@ -340,7 +340,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 @@ -385,7 +385,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 @@ -430,7 +430,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 @@ -467,7 +467,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 @@ -559,7 +559,7 @@ test_circuitmap_free_all(void) ; } -/** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS +/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS * circuitmap is maintained properly. */ static void test_intro_point_registration(void *arg) @@ -636,8 +636,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(); @@ -657,7 +657,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); } @@ -666,7 +666,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); } @@ -677,7 +677,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); } @@ -688,7 +688,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); } @@ -732,6 +732,7 @@ test_introduce1_validation(void *arg) /* Create our decoy cell that we'll modify as we go to test the validation * function of that parsed cell. */ cell = helper_create_introduce1_cell(); + tt_assert(cell); /* It should NOT be a legacy cell which will trigger a BUG(). */ memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id)); @@ -807,7 +808,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 @@ -820,7 +821,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); } @@ -845,8 +846,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); } @@ -874,8 +875,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 d040f10e0c..2e5280610f 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -20,6 +20,7 @@ #define STATEFILE_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define HS_CLIENT_PRIVATE +#define ROUTERPARSE_PRIVATE #include "test.h" #include "test_helpers.h" @@ -37,6 +38,7 @@ #include "networkstatus.h" #include "nodelist.h" #include "relay.h" +#include "routerparse.h" #include "hs_common.h" #include "hs_config.h" @@ -182,7 +184,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 +196,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 +208,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 +220,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 +242,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 +253,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; } @@ -658,13 +658,13 @@ 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_); } -/** Test the operations we do on a circuit after we learn that we successfuly +/** Test the operations we do on a circuit after we learn that we successfully * established an intro point on it */ static void test_intro_established(void *arg) @@ -733,7 +733,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_); } @@ -775,7 +775,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_); @@ -828,7 +828,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); @@ -860,7 +860,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(); @@ -941,7 +941,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_); } @@ -1025,7 +1025,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_); } @@ -1215,6 +1215,7 @@ test_build_update_descriptors(void *arg) /* Ugly yes but we never free the "ri" object so this just makes things * easier. */ ri.protocol_list = (char *) "HSDir=1-2 LinkAuth=3"; + summarize_protover_flags(&ri.pv, ri.protocol_list, NULL); ret = curve25519_secret_key_generate(&curve25519_secret_key, 0); tt_int_op(ret, OP_EQ, 0); ri.onion_curve25519_pkey = @@ -1236,6 +1237,10 @@ test_build_update_descriptors(void *arg) node->is_running = node->is_valid = node->is_fast = node->is_stable = 1; } + /* We have to set thise, or the lack of microdescriptors for these + * nodes will make them unusable. */ + get_options_mutable()->UseMicrodescriptors = 0; + /* We expect to pick only one intro point from the node above. */ setup_full_capture_of_logs(LOG_INFO); update_all_descriptors(now); @@ -1579,8 +1584,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 4106425cb3..455f9e7d42 100755 --- a/src/test/test_keygen.sh +++ b/src/test/test_keygen.sh @@ -48,6 +48,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 @@ -371,6 +377,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_options.c b/src/test/test_options.c index 62732cabf7..eaf5034397 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -377,17 +377,11 @@ fixed_get_uname(void) } #define TEST_OPTIONS_OLD_VALUES "TestingV3AuthInitialVotingInterval 1800\n" \ - "ClientBootstrapConsensusMaxDownloadTries 7\n" \ - "ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries 4\n" \ "ClientBootstrapConsensusMaxInProgressTries 3\n" \ "TestingV3AuthInitialVoteDelay 300\n" \ "TestingV3AuthInitialDistDelay 300\n" \ "TestingClientMaxIntervalWithoutRequest 600\n" \ "TestingDirConnectionMaxStall 600\n" \ - "TestingConsensusMaxDownloadTries 8\n" \ - "TestingDescriptorMaxDownloadTries 8\n" \ - "TestingMicrodescMaxDownloadTries 8\n" \ - "TestingCertMaxDownloadTries 8\n" #define TEST_OPTIONS_DEFAULT_VALUES TEST_OPTIONS_OLD_VALUES \ "MaxClientCircuitsPending 1\n" \ @@ -906,7 +900,7 @@ test_options_validate__authdir(void *ignored) "Address 100.200.10.1\n" "BridgeAuthoritativeDir 1\n" "ContactInfo hello@hello.com\n" - "V3BandwidthsFile non-existant-file\n"); + "V3BandwidthsFile non-existent-file\n"); mock_clean_saved_logs(); options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg); tt_str_op(msg, OP_EQ, @@ -918,7 +912,7 @@ test_options_validate__authdir(void *ignored) "Address 100.200.10.1\n" "BridgeAuthoritativeDir 1\n" "ContactInfo hello@hello.com\n" - "V3BandwidthsFile non-existant-file\n"); + "V3BandwidthsFile non-existent-file\n"); mock_clean_saved_logs(); options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg); tt_str_op(msg, OP_EQ, @@ -930,7 +924,7 @@ test_options_validate__authdir(void *ignored) "Address 100.200.10.1\n" "BridgeAuthoritativeDir 1\n" "ContactInfo hello@hello.com\n" - "GuardfractionFile non-existant-file\n"); + "GuardfractionFile non-existent-file\n"); mock_clean_saved_logs(); options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg); tt_str_op(msg, OP_EQ, @@ -942,7 +936,7 @@ test_options_validate__authdir(void *ignored) "Address 100.200.10.1\n" "BridgeAuthoritativeDir 1\n" "ContactInfo hello@hello.com\n" - "GuardfractionFile non-existant-file\n"); + "GuardfractionFile non-existent-file\n"); mock_clean_saved_logs(); options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg); tt_str_op(msg, OP_EQ, @@ -1112,7 +1106,7 @@ test_options_validate__transproxy(void *ignored) // Test unknown trans proxy free_options_test_data(tdata); - tdata = get_options_test_data("TransProxyType non-existant\n"); + tdata = get_options_test_data("TransProxyType non-existent\n"); ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg); tt_int_op(ret, OP_EQ, -1); tt_str_op(msg, OP_EQ, "Unrecognized value for TransProxyType"); @@ -2081,10 +2075,6 @@ test_options_validate__testing(void *ignored) ENSURE_DEFAULT(TestingBridgeBootstrapDownloadSchedule, 3000); ENSURE_DEFAULT(TestingClientMaxIntervalWithoutRequest, 3000); ENSURE_DEFAULT(TestingDirConnectionMaxStall, 3000); - ENSURE_DEFAULT(TestingConsensusMaxDownloadTries, 3000); - ENSURE_DEFAULT(TestingDescriptorMaxDownloadTries, 3000); - ENSURE_DEFAULT(TestingMicrodescMaxDownloadTries, 3000); - ENSURE_DEFAULT(TestingCertMaxDownloadTries, 3000); ENSURE_DEFAULT(TestingAuthKeyLifetime, 3000); ENSURE_DEFAULT(TestingLinkCertLifetime, 3000); ENSURE_DEFAULT(TestingSigningKeySlop, 3000); @@ -4069,15 +4059,6 @@ test_options_validate__testing_options(void *ignored) "is way too low."); TEST_TESTING_OPTION(TestingDirConnectionMaxStall, 1, 3601, "is way too low."); - // TODO: I think this points to a bug/regression in options_validate - TEST_TESTING_OPTION(TestingConsensusMaxDownloadTries, 1, 801, - "must be greater than 2."); - TEST_TESTING_OPTION(TestingDescriptorMaxDownloadTries, 1, 801, - "must be greater than 1."); - TEST_TESTING_OPTION(TestingMicrodescMaxDownloadTries, 1, 801, - "must be greater than 1."); - TEST_TESTING_OPTION(TestingCertMaxDownloadTries, 1, 801, - "must be greater than 1."); free_options_test_data(tdata); tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES 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 9b94044b91..0948cd5640 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -8,10 +8,20 @@ #include "protover.h" +#include "or.h" +#include "connection_or.h" + 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 +88,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 */ @@ -110,6 +126,13 @@ test_protover_parse_fail(void *arg) elts = parse_protocol_list("Link=1,9-8,3"); tt_ptr_op(elts, OP_EQ, NULL); + /* Protocol name too long */ + elts = parse_protocol_list("DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + tt_ptr_op(elts, OP_EQ, NULL); + +#endif done: ; } @@ -203,6 +226,15 @@ test_protover_vote(void *arg) tt_str_op(result, OP_EQ, ""); tor_free(result); + /* Protocol name too long */ + smartlist_clear(lst); + smartlist_add(lst, (void*) "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + result = protover_compute_vote(lst, 1); + tt_str_op(result, OP_EQ, ""); + tor_free(result); + done: tor_free(result); smartlist_free(lst); @@ -238,11 +270,26 @@ test_protover_all_supported(void *arg) tt_assert(! protover_all_supported("Link=3-4 Wombat=9", &msg)); tt_str_op(msg, OP_EQ, "Wombat=9"); tor_free(msg); + + /* Mix of things we support and don't support within a single protocol + * which we do support */ tt_assert(! protover_all_supported("Link=3-999", &msg)); - tt_str_op(msg, OP_EQ, "Link=3-999"); + tt_str_op(msg, OP_EQ, "Link=6-999"); + tor_free(msg); + tt_assert(! protover_all_supported("Link=1-3,345-666", &msg)); + tt_str_op(msg, OP_EQ, "Link=345-666"); + tor_free(msg); + tt_assert(! protover_all_supported("Link=1-3,5-12", &msg)); + tt_str_op(msg, OP_EQ, "Link=6-12"); + tor_free(msg); + + /* Mix of protocols we do support and some we don't, where the protocols + * we do support have some versions we don't support. */ + tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=9000-9001", &msg)); + tt_str_op(msg, OP_EQ, "Link=6-12 Quokka=9000-9001"); tor_free(msg); - /* CPU/RAM DoS loop: Rust only */ + /* We shouldn't be able to DoS ourselves parsing a large range. */ tt_assert(! protover_all_supported("Sleen=0-2147483648", &msg)); tt_str_op(msg, OP_EQ, "Sleen=0-2147483648"); tor_free(msg); @@ -252,21 +299,31 @@ test_protover_all_supported(void *arg) tt_str_op(msg, OP_EQ, "Sleen=0-4294967294"); tor_free(msg); - /* If we get an unparseable list, we say "yes, that's supported." */ -#ifndef HAVE_RUST - // XXXX let's make this section unconditional: rust should behave the - // XXXX same as C here! + /* If we get a (barely) valid (but unsupported list, we say "yes, that's + * supported." */ + tt_assert(protover_all_supported("Fribble=", &msg)); + tt_ptr_op(msg, OP_EQ, NULL); + + /* If we get a completely unparseable list, protover_all_supported should + * hit a fatal assertion for BUG(entries == NULL). */ tor_capture_bugs_(1); tt_assert(protover_all_supported("Fribble", &msg)); - tt_ptr_op(msg, OP_EQ, NULL); tor_end_capture_bugs_(); - /* This case is forbidden. Since it came from a protover_all_supported, - * it can trigger a bug message. */ + /* If we get a completely unparseable list, protover_all_supported should + * hit a fatal assertion for BUG(entries == NULL). */ tor_capture_bugs_(1); tt_assert(protover_all_supported("Sleen=0-4294967295", &msg)); - tt_ptr_op(msg, OP_EQ, NULL); - tor_free(msg); + tor_end_capture_bugs_(); + + /* Protocol name too long */ +#ifndef HAVE_RUST // XXXXXX ????? + tor_capture_bugs_(1); + tt_assert(protover_all_supported( + "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaa=1-65536", &msg)); tor_end_capture_bugs_(); #endif @@ -276,6 +333,209 @@ test_protover_all_supported(void *arg) } 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: + ; +} + +/* This could be MAX_PROTOCOLS_TO_EXPAND, but that's not exposed by protover */ +#define MAX_PROTOCOLS_TO_TEST 1024 + +/* LinkAuth and Relay protocol versions. + * Hard-coded here, because they are not in the code, or not exposed in the + * headers. */ +#define PROTOVER_LINKAUTH_V1 1 +#define PROTOVER_LINKAUTH_V3 3 + +#define PROTOVER_RELAY_V1 1 +#define PROTOVER_RELAY_V2 2 + +/* Highest supported HSv2 introduce protocol version. + * Hard-coded here, because it does not appear anywhere in the code. + * It's not clear if we actually support version 2, see #25068. */ +#define PROTOVER_HSINTRO_V2 3 + +/* HSv2 Rend and HSDir protocol versions. + * Hard-coded here, because they do not appear anywhere in the code. */ +#define PROTOVER_HS_RENDEZVOUS_POINT_V2 1 +#define PROTOVER_HSDIR_V2 1 + +/* DirCache, Desc, Microdesc, and Cons protocol versions. + * Hard-coded here, because they do not appear anywhere in the code. */ +#define PROTOVER_DIRCACHE_V1 1 +#define PROTOVER_DIRCACHE_V2 2 + +#define PROTOVER_DESC_V1 1 +#define PROTOVER_DESC_V2 2 + +#define PROTOVER_MICRODESC_V1 1 +#define PROTOVER_MICRODESC_V2 2 + +#define PROTOVER_CONS_V1 1 +#define PROTOVER_CONS_V2 2 + +/* Make sure we haven't forgotten any supported protocols */ +static void +test_protover_supported_protocols(void *arg) +{ + (void)arg; + + const char *supported_protocols = protover_get_supported_protocols(); + + /* Test for new Link in the code, that hasn't been added to supported + * protocols */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_LINK, + MAX_LINK_PROTO)); + for (uint16_t i = 0; i < MAX_PROTOCOLS_TO_TEST; i++) { + if (is_or_protocol_version_known(i)) { + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_LINK, + i)); + } + } + + /* Legacy LinkAuth does not appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_LINKAUTH, + PROTOVER_LINKAUTH_V1)); + /* Latest LinkAuth is not exposed in the headers. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_LINKAUTH, + PROTOVER_LINKAUTH_V3)); + /* Is there any way to test for new LinkAuth? */ + + /* Relay protovers do not appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_RELAY, + PROTOVER_RELAY_V1)); + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_RELAY, + PROTOVER_RELAY_V2)); + /* Is there any way to test for new Relay? */ + + /* We could test legacy HSIntro by calling rend_service_update_descriptor(), + * and checking the protocols field. But that's unlikely to change, so + * we just use a hard-coded value. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSINTRO, + PROTOVER_HSINTRO_V2)); + /* Test for HSv3 HSIntro */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSINTRO, + PROTOVER_HS_INTRO_V3)); + /* Is there any way to test for new HSIntro? */ + + /* Legacy HSRend does not appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSREND, + PROTOVER_HS_RENDEZVOUS_POINT_V2)); + /* Test for HSv3 HSRend */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSREND, + PROTOVER_HS_RENDEZVOUS_POINT_V3)); + /* Is there any way to test for new HSRend? */ + + /* Legacy HSDir does not appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSDIR, + PROTOVER_HSDIR_V2)); + /* Test for HSv3 HSDir */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_HSDIR, + PROTOVER_HSDIR_V3)); + /* Is there any way to test for new HSDir? */ + + /* No DirCache versions appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_DIRCACHE, + PROTOVER_DIRCACHE_V1)); + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_DIRCACHE, + PROTOVER_DIRCACHE_V2)); + /* Is there any way to test for new DirCache? */ + + /* No Desc versions appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_DESC, + PROTOVER_DESC_V1)); + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_DESC, + PROTOVER_DESC_V2)); + /* Is there any way to test for new Desc? */ + + /* No Microdesc versions appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_MICRODESC, + PROTOVER_MICRODESC_V1)); + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_MICRODESC, + PROTOVER_MICRODESC_V2)); + /* Is there any way to test for new Microdesc? */ + + /* No Cons versions appear anywhere in the code. */ + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_CONS, + PROTOVER_CONS_V1)); + tt_assert(protocol_list_supports_protocol(supported_protocols, + PRT_CONS, + PROTOVER_CONS_V2)); + /* Is there any way to test for new Cons? */ + + done: + ; +} + +static void test_protover_vote_roundtrip(void *args) { (void) args; @@ -312,8 +572,6 @@ test_protover_vote_roundtrip(void *args) { "Link=1,9-8,3", NULL }, { "Faux=-0", NULL }, { "Faux=0--0", NULL }, - // "These fail at the splitting stage in Rust, but the number parsing - // stage in C." { "Faux=-1", NULL }, { "Faux=-1-3", NULL }, { "Faux=1--1", NULL }, @@ -322,9 +580,9 @@ test_protover_vote_roundtrip(void *args) /* Large range */ { "Sleen=1-501", "Sleen=1-501" }, { "Sleen=1-65537", NULL }, - /* CPU/RAM DoS Loop: Rust only. */ + /* Both C/Rust implementations should be able to handle this mild DoS. */ { "Sleen=0-2147483648", NULL }, - /* Rust seems to experience an internal error here. */ + /* Rust tests are built in debug mode, so ints are bounds-checked. */ { "Sleen=0-4294967295", NULL }, }; unsigned u; @@ -360,6 +618,10 @@ 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), + PV_TEST(supported_protocols, 0), PV_TEST(vote_roundtrip, 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..c7d0439ad1 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 +set -e -exitcode=0 -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 +for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do + if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then + cd "${cargo_toml_dir}" && \ + CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \ + CARGO_HOME="${abs_top_builddir:-../../..}/src/rust/.cargo" \ + "${CARGO:-cargo}" test --all-features ${CARGO_ONLINE-"--frozen"} \ + ${EXTRA_CARGO_OPTIONS} \ + --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1 + fi done exit $exitcode + + diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c index 724a6b56b2..ebba71266c 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); @@ -668,8 +661,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); @@ -684,7 +675,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); /* @@ -836,7 +826,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); @@ -847,7 +836,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); @@ -1083,6 +1071,271 @@ test_scheduler_ns_changed(void *arg) return; } +/* + * Mocked functions for the kist_pending_list test. + */ + +static int mock_flush_some_cells_num = 1; +static int mock_more_to_flush = 0; +static int mock_update_socket_info_limit = 0; + +static ssize_t +channel_flush_some_cells_mock_var(channel_t *chan, ssize_t num_cells) +{ + (void) chan; + (void) num_cells; + return mock_flush_some_cells_num; +} + +/* Because when we flush cells, it is possible that the connection outbuf gets + * fully drained, the wants to write scheduler event is fired back while we + * are in the scheduler loop so this mock function does it for us. + * Furthermore, the socket limit is set to 0 so once this is triggered, it + * informs the scheduler that it can't write on the socket anymore. */ +static void +channel_write_to_kernel_mock_trigger_24700(channel_t *chan) +{ + static int chan_id_seen[2] = {0}; + if (++chan_id_seen[chan->global_identifier - 1] > 1) { + tt_assert(0); + } + + scheduler_channel_wants_writes(chan); + + done: + return; +} + +static int +channel_more_to_flush_mock_var(channel_t *chan) +{ + (void) chan; + return mock_more_to_flush; +} + +static void +update_socket_info_impl_mock_var(socket_table_ent_t *ent) +{ + ent->cwnd = ent->unacked = ent->mss = ent->notsent = 0; + ent->limit = mock_update_socket_info_limit; +} + +static void +test_scheduler_kist_pending_list(void *arg) +{ + (void) arg; + +#ifndef HAVE_KIST_SUPPORT + return; +#endif + + /* This is for testing the channel flow with the pending list that is + * depending on the channel state, what will be the expected behavior of the + * scheduler with that list. + * + * For instance, we want to catch double channel add or removing a channel + * that doesn't exists, or putting a channel in the list in a wrong state. + * Essentially, this will articifically test cases of the KIST main loop and + * entry point in the channel subsystem. + * + * In part, this is to also catch things like #24700 and provide a test bed + * for more testing in the future like so. */ + + /* Mocking a series of scheduler function to control the flow of the + * scheduler loop to test every use cases and assess the pending list. */ + MOCK(get_options, mock_get_options); + MOCK(channel_flush_some_cells, channel_flush_some_cells_mock_var); + MOCK(channel_more_to_flush, channel_more_to_flush_mock_var); + MOCK(update_socket_info_impl, update_socket_info_impl_mock_var); + MOCK(channel_write_to_kernel, channel_write_to_kernel_mock); + MOCK(channel_should_write_to_kernel, channel_should_write_to_kernel_mock); + + /* Setup options so we're sure about what sched we are running */ + mocked_options.KISTSchedRunInterval = 10; + set_scheduler_options(SCHEDULER_KIST); + + /* Init scheduler. */ + scheduler_init(); + + /* Initialize a channel. We'll need a second channel for the #24700 bug + * test. */ + channel_t *chan1 = new_fake_channel(); + channel_t *chan2 = new_fake_channel(); + tt_assert(chan1); + tt_assert(chan2); + chan1->magic = chan2->magic = TLS_CHAN_MAGIC; + channel_register(chan1); + channel_register(chan2); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE); + tt_int_op(chan1->sched_heap_idx, OP_EQ, -1); + tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE); + tt_int_op(chan2->sched_heap_idx, OP_EQ, -1); + + /* Once a channel becomes OPEN, it always have at least one cell in it so + * the scheduler is notified that the channel wants to write so this is the + * first step. Might not make sense to you but it is the way it is. */ + scheduler_channel_wants_writes(chan1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + + /* Signal the scheduler that it has waiting cells which means the channel + * will get scheduled. */ + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + /* Subsequent call should not add it more times. It is possible we add many + * cells in rapid succession before the channel is scheduled. */ + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + + /* We'll flush one cell and make it that the socket can write but no more to + * flush else we end up in an infinite loop. We expect the channel to be put + * in waiting for cells state and the pending list empty. */ + mock_update_socket_info_limit = INT_MAX; + mock_more_to_flush = 0; + the_scheduler->run(); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS); + + /* Lets make believe that a cell is now in the channel but this time the + * channel can't write so obviously it has more to flush. We expect the + * channel to be back in the pending list. */ + scheduler_channel_has_waiting_cells(chan1); + mock_update_socket_info_limit = 0; + mock_more_to_flush = 1; + the_scheduler->run(); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + + /* Channel is in the pending list now, during that time, we'll trigger a + * wants to write event because maybe the channel buffers were emptied in + * the meantime. This is possible because once the connection outbuf is + * flushed down the low watermark, the scheduler is notified. + * + * We expect the channel to NOT be added in the pending list again and stay + * in PENDING state. */ + scheduler_channel_wants_writes(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + + /* Make it that the channel can write now but has nothing else to flush. We + * expect that it is removed from the pending list and waiting for cells. */ + mock_update_socket_info_limit = INT_MAX; + mock_more_to_flush = 0; + the_scheduler->run(); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS); + + /* While waiting for cells, lets say we were able to write more things on + * the connection outbuf (unlikely that this can happen but let say it + * does). We expect the channel to stay in waiting for cells. */ + scheduler_channel_wants_writes(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS); + + /* We'll not put it in the pending list and make the flush cell fail with 0 + * cell flushed. We expect that it is put back in waiting for cells. */ + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + mock_flush_some_cells_num = 0; + the_scheduler->run(); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS); + + /* Set the channel to a state where it doesn't want to write more. We expect + * that the channel becomes idle. */ + scheduler_channel_doesnt_want_writes(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE); + + /* Some cells arrive on the channel now. We expect it to go back in waiting + * to write. You might wonder why it is not put in the pending list? Because + * once the channel becomes OPEN again (the doesn't want to write event only + * occurs if the channel goes in MAINT mode), if there are cells in the + * channel, the wants to write event is triggered thus putting the channel + * in pending mode. + * + * Else, if no cells, it stays IDLE and then once a cell comes in, it should + * go in waiting to write which is a BUG itself because the channel can't be + * scheduled until a second cell comes in. Hopefully, #24554 will fix that + * for KIST. */ + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE); + + /* Second cell comes in, unfortunately, it won't get scheduled until a wants + * to write event occurs like described above. */ + scheduler_channel_has_waiting_cells(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE); + + /* Unblock everything putting the channel in the pending list. */ + scheduler_channel_wants_writes(chan1); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + + /* Testing bug #24700 which is the situation where we have at least two + * different channels in the pending list. The first one gets flushed and + * bytes are written on the wire which triggers a wants to write event + * because the outbuf is below the low watermark. The bug was that this + * exact channel was added back in the pending list because its state wasn't + * PENDING. + * + * The following does some ninja-tsu to try to make it happen. We need two + * different channels so we create a second one and add it to the pending + * list. Then, we have a custom function when we write to kernel that does + * two important things: + * + * 1) Calls scheduler_channel_wants_writes(chan) on the channel. + * 2) Keeps track of how many times it sees the channel going through. If + * that limit goes > 1, it means we've added the channel twice in the + * pending list. + * + * In the end, we expect both channels to be in the pending list after this + * scheduler run. */ + + /* Put the second channel in the pending list. */ + scheduler_channel_wants_writes(chan2); + scheduler_channel_has_waiting_cells(chan2); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 2); + tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + + /* This makes it that the first pass on socket_can_write() will be true but + * then when a single cell is flushed (514 + 29 bytes), the second call to + * socket_can_write() will be false. If it wasn't sending back false on the + * second run, we end up in an infinite loop of the scheduler. */ + mock_update_socket_info_limit = 600; + /* We want to hit "Case 3:" of the scheduler so channel_more_to_flush() is + * true but socket_can_write() has to be false on the second check on the + * channel. */ + mock_more_to_flush = 1; + mock_flush_some_cells_num = 1; + MOCK(channel_write_to_kernel, channel_write_to_kernel_mock_trigger_24700); + the_scheduler->run(); + tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 2); + tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING); + + done: + chan1->state = chan2->state = CHANNEL_STATE_CLOSED; + chan1->registered = chan2->registered = 0; + channel_free(chan1); + channel_free(chan2); + scheduler_free_all(); + + UNMOCK(get_options); + UNMOCK(channel_flush_some_cells); + UNMOCK(channel_more_to_flush); + UNMOCK(update_socket_info_impl); + UNMOCK(channel_write_to_kernel); + UNMOCK(channel_should_write_to_kernel); +} + struct testcase_t scheduler_tests[] = { { "compare_channels", test_scheduler_compare_channels, TT_FORK, NULL, NULL }, @@ -1092,6 +1345,8 @@ struct testcase_t scheduler_tests[] = { { "loop_kist", test_scheduler_loop_kist, TT_FORK, NULL, NULL }, { "ns_changed", test_scheduler_ns_changed, TT_FORK, NULL, NULL}, { "should_use_kist", test_scheduler_can_use_kist, TT_FORK, NULL, NULL }, + { "kist_pending_list", test_scheduler_kist_pending_list, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index b7cd33715f..437fc38deb 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 @@ -399,7 +402,7 @@ test_sr_commit(void *arg) sizeof(our_commit->hashed_reveal))); /* Do we have a valid encoded commit and reveal. Note the following only * tests if the generated values are correct. Their could be a bug in - * the decode function but we test them seperately. */ + * the decode function but we test them separately. */ tt_int_op(0, OP_EQ, reveal_decode(our_commit->encoded_reveal, &test_commit)); tt_int_op(0, OP_EQ, commit_decode(our_commit->encoded_commit, @@ -609,7 +612,7 @@ test_vote(void *arg) ret = smartlist_split_string(chunks, lines, "\n", SPLIT_IGNORE_BLANK, 0); tt_int_op(ret, OP_EQ, 4); tt_str_op(smartlist_get(chunks, 0), OP_EQ, "shared-rand-participate"); - /* Get our commitment line and will validate it agains our commit. The + /* Get our commitment line and will validate it against our commit. The * format is as follow: * "shared-rand-commitment" SP version SP algname SP identity * SP COMMIT [SP REVEAL] NL @@ -1350,7 +1353,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_socks.c b/src/test/test_socks.c index 9ae7530e22..8da7191e82 100644 --- a/src/test/test_socks.c +++ b/src/test/test_socks.c @@ -347,17 +347,35 @@ test_socks_5_supported_commands(void *ptr) socks_request_clear(socks); - /* SOCKS 5 should NOT reject RESOLVE [F0] reject for IPv6 address + /* SOCKS 5 should NOT reject RESOLVE [F0] request for IPv6 address * string if SafeSocks is enabled. */ ADD_DATA(buf, "\x05\x01\x00"); + ADD_DATA(buf, "\x05\xF0\x00\x03\x29"); + ADD_DATA(buf, "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"); + ADD_DATA(buf, "\x01\x02"); + tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1), + OP_EQ, 1); + + tt_str_op("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", OP_EQ, + socks->address); + tt_int_op(258, OP_EQ, socks->port); + + tt_int_op(0, OP_EQ, buf_datalen(buf)); + + socks_request_clear(socks); + + /* Also allow bracket-less form. */ + + ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF0\x00\x03\x27"); ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); ADD_DATA(buf, "\x01\x02"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1), - OP_EQ, -1); + OP_EQ, 1); - tt_str_op("2001:0db8:85a3:0000:0000:8a2e:0370:7334", OP_EQ, socks->address); + tt_str_op("2001:0db8:85a3:0000:0000:8a2e:0370:7334", OP_EQ, + socks->address); tt_int_op(258, OP_EQ, socks->port); tt_int_op(0, OP_EQ, buf_datalen(buf)); diff --git a/src/test/test_status.c b/src/test/test_status.c index f86f8e3b9e..b4ca17891b 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 @@ -337,7 +340,7 @@ NS(test_main)(void *arg) actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); - tt_int_op(CALLED(logv), OP_EQ, 5); + tt_int_op(CALLED(logv), OP_EQ, 6); done: NS_UNMOCK(tls_get_write_overhead_ratio); @@ -436,6 +439,16 @@ NS(logv)(int severity, log_domain_mask_t domain, tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"), OP_NE, NULL); break; + case 5: + tt_int_op(severity, OP_EQ, LOG_NOTICE); + tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s"); + tt_str_op(va_arg(ap, char *), OP_EQ, + " 0 circuits killed with too many cells."); + tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]"); + tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]"); + tt_str_op(va_arg(ap, char *), OP_EQ, ""); + break; default: tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args break; diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 29f7cc9c37..ef038c661e 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -841,8 +841,10 @@ test_tortls_classify_client_ciphers(void *ignored) sk_SSL_CIPHER_zero(ciphers); one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384"); + tt_assert(one); one->id = 0x00ff; two = get_cipher_by_name("ECDHE-RSA-AES128-GCM-SHA256"); + tt_assert(two); two->id = 0x0000; sk_SSL_CIPHER_push(ciphers, one); tls->client_cipher_list_type = 0; @@ -913,6 +915,7 @@ test_tortls_client_is_using_v2_ciphers(void *ignored) ciphers = sk_SSL_CIPHER_new_null(); SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384"); + tt_assert(one); one->id = 0x00ff; sk_SSL_CIPHER_push(ciphers, one); sess->ciphers = ciphers; diff --git a/src/test/test_util.c b/src/test/test_util.c index 0519a4758f..036f739b89 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -703,7 +703,7 @@ test_util_time(void *arg) * a "correct" retrospective gregorian negative year value, * which I'm pretty sure is: * -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657 - * 730485 is the number of days in two millenia, including leap days */ + * 730485 is the number of days in two millennia, including leap days */ a_time.tm_year = -292277022657-1900; CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); @@ -739,7 +739,7 @@ test_util_time(void *arg) * a "correct" proleptic gregorian year value, * which I'm pretty sure is: * (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596 - * 730485 is the number of days in two millenia, including leap days */ + * 730485 is the number of days in two millennia, including leap days */ a_time.tm_year = 292277026596-1900; CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); @@ -875,7 +875,7 @@ test_util_time(void *arg) * a "correct" retrospective gregorian negative year value, * which I'm pretty sure is: * -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657 - * 730485 is the number of days in two millenia, including leap days + * 730485 is the number of days in two millennia, including leap days * (int64_t)b_time.tm_year == (-292277022657LL-1900LL) without clamping */ t_res = INT64_MIN; CAPTURE(); @@ -921,7 +921,7 @@ test_util_time(void *arg) * a "correct" proleptic gregorian year value, * which I'm pretty sure is: * (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596 - * 730485 is the number of days in two millenia, including leap days + * 730485 is the number of days in two millennia, including leap days * (int64_t)b_time.tm_year == (292277026596L-1900L) without clamping */ t_res = INT64_MAX; CAPTURE(); @@ -5465,7 +5465,7 @@ is_there_a_localhost(int family) #endif /* 0 */ /* Test for socketpair and ersatz_socketpair(). We test them both, since - * the latter is a tolerably good way to exersize tor_accept_socket(). */ + * the latter is a tolerably good way to exercise tor_accept_socket(). */ static void test_util_socketpair(void *arg) { @@ -5542,47 +5542,74 @@ test_util_max_mem(void *arg) } static void +test_util_dest_validation_edgecase(void *arg) +{ + (void)arg; + + tt_assert(!string_is_valid_dest(NULL)); + tt_assert(!string_is_valid_dest("")); + + done: + return; +} + +static void test_util_hostname_validation(void *arg) { (void)arg; // Lets try valid hostnames first. - tt_assert(string_is_valid_hostname("torproject.org")); - tt_assert(string_is_valid_hostname("ocw.mit.edu")); - tt_assert(string_is_valid_hostname("i.4cdn.org")); - tt_assert(string_is_valid_hostname("stanford.edu")); - tt_assert(string_is_valid_hostname("multiple-words-with-hypens.jp")); + tt_assert(string_is_valid_nonrfc_hostname("torproject.org")); + tt_assert(string_is_valid_nonrfc_hostname("ocw.mit.edu")); + tt_assert(string_is_valid_nonrfc_hostname("i.4cdn.org")); + tt_assert(string_is_valid_nonrfc_hostname("stanford.edu")); + tt_assert(string_is_valid_nonrfc_hostname("multiple-words-with-hypens.jp")); // Subdomain name cannot start with '-' or '_'. - tt_assert(!string_is_valid_hostname("-torproject.org")); - tt_assert(!string_is_valid_hostname("subdomain.-domain.org")); - tt_assert(!string_is_valid_hostname("-subdomain.domain.org")); - tt_assert(!string_is_valid_hostname("___abc.org")); + tt_assert(!string_is_valid_nonrfc_hostname("-torproject.org")); + tt_assert(!string_is_valid_nonrfc_hostname("subdomain.-domain.org")); + tt_assert(!string_is_valid_nonrfc_hostname("-subdomain.domain.org")); + tt_assert(!string_is_valid_nonrfc_hostname("___abc.org")); // Hostnames cannot contain non-alphanumeric characters. - tt_assert(!string_is_valid_hostname("%%domain.\\org.")); - tt_assert(!string_is_valid_hostname("***x.net")); - tt_assert(!string_is_valid_hostname("\xff\xffxyz.org")); - tt_assert(!string_is_valid_hostname("word1 word2.net")); + tt_assert(!string_is_valid_nonrfc_hostname("%%domain.\\org.")); + tt_assert(!string_is_valid_nonrfc_hostname("***x.net")); + tt_assert(!string_is_valid_nonrfc_hostname("\xff\xffxyz.org")); + tt_assert(!string_is_valid_nonrfc_hostname("word1 word2.net")); // Test workaround for nytimes.com stupidity, technically invalid, // but we allow it since they are big, even though they are failing to // comply with a ~30 year old standard. - tt_assert(string_is_valid_hostname("core3_euw1.fabrik.nytimes.com")); + tt_assert(string_is_valid_nonrfc_hostname("core3_euw1.fabrik.nytimes.com")); // Firefox passes FQDNs with trailing '.'s directly to the SOCKS proxy, // which is redundant since the spec states DOMAINNAME addresses are fully // qualified. While unusual, this should be tollerated. - tt_assert(string_is_valid_hostname("core9_euw1.fabrik.nytimes.com.")); - tt_assert(!string_is_valid_hostname("..washingtonpost.is.better.com")); - tt_assert(!string_is_valid_hostname("so.is..ft.com")); - tt_assert(!string_is_valid_hostname("...")); + tt_assert(string_is_valid_nonrfc_hostname("core9_euw1.fabrik.nytimes.com.")); + tt_assert(!string_is_valid_nonrfc_hostname( + "..washingtonpost.is.better.com")); + tt_assert(!string_is_valid_nonrfc_hostname("so.is..ft.com")); + tt_assert(!string_is_valid_nonrfc_hostname("...")); // XXX: do we allow single-label DNS names? // We shouldn't for SOCKS (spec says "contains a fully-qualified domain name" // but only test pathologically malformed traling '.' cases for now. - tt_assert(!string_is_valid_hostname(".")); - tt_assert(!string_is_valid_hostname("..")); + tt_assert(!string_is_valid_nonrfc_hostname(".")); + tt_assert(!string_is_valid_nonrfc_hostname("..")); + + // IP address strings are not hostnames. + tt_assert(!string_is_valid_nonrfc_hostname("8.8.8.8")); + tt_assert(!string_is_valid_nonrfc_hostname("[2a00:1450:401b:800::200e]")); + tt_assert(!string_is_valid_nonrfc_hostname("2a00:1450:401b:800::200e")); + + // We allow alphanumeric TLDs. For discussion, see ticket #25055. + tt_assert(string_is_valid_nonrfc_hostname("lucky.13")); + tt_assert(string_is_valid_nonrfc_hostname("luck.y13")); + tt_assert(string_is_valid_nonrfc_hostname("luck.y13.")); + + // We allow punycode TLDs. For examples, see + // http://data.iana.org/TLD/tlds-alpha-by-domain.txt + tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc")); done: return; @@ -5801,6 +5828,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 +5840,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 +5848,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. */ @@ -5835,10 +5865,15 @@ test_util_monotonic_time(void *arg) tt_u64_op(usec1, OP_GE, nsec1 / 1000); tt_u64_op(msecc1, OP_GE, nsecc1 / 1000000); tt_u64_op(usecc1, OP_GE, nsecc1 / 1000); - tt_u64_op(msec1, OP_LE, nsec1 / 1000000 + 1); - tt_u64_op(usec1, OP_LE, nsec1 / 1000 + 1000); - tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1); - tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 1000); + tt_u64_op(msec1, OP_LE, nsec1 / 1000000 + 10); + tt_u64_op(usec1, OP_LE, nsec1 / 1000 + 10000); + tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 10); + tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 10000); + + 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 +5953,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; @@ -6142,6 +6235,7 @@ struct testcase_t util_tests[] = { &passthrough_setup, (void*)"1" }, UTIL_TEST(max_mem, 0), UTIL_TEST(hostname_validation, 0), + UTIL_TEST(dest_validation_edgecase, 0), UTIL_TEST(ipv4_validation, 0), UTIL_TEST(writepid, 0), UTIL_TEST(get_avail_disk_space, 0), @@ -6150,6 +6244,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..52729147b2 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. @@ -284,6 +278,7 @@ main(int c, const char **v) s.masks[LOG_WARN-LOG_ERR] |= LD_BUG; add_stream_log(&s, "", fileno(stdout)); } + init_protocol_warning_severity_level(); options->command = CMD_RUN_UNITTESTS; if (crypto_global_init(accel_crypto, NULL, NULL)) { @@ -299,6 +294,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); |