diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-11-15 16:58:16 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-11-15 16:58:16 -0500 |
commit | 80a6228aacc9083fae07d4373d9c41017420e6b9 (patch) | |
tree | 6be586086b61c6533257debf4cfdcc14f8979e58 /src/test | |
parent | 15e752e6b111e159b1dee3bb4692d8de3c4d1c7f (diff) | |
parent | 6d33f65638734593d10c5c3a5e2eb9d7bdff8000 (diff) | |
download | tor-80a6228aacc9083fae07d4373d9c41017420e6b9.tar.gz tor-80a6228aacc9083fae07d4373d9c41017420e6b9.zip |
Merge branch 'bug25573-034-typefix' into maint-0.3.4
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/test_relaycell.c | 641 |
1 files changed, 598 insertions, 43 deletions
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 1bd17b73bf..2fc0288f69 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -5,17 +5,27 @@ #define RELAY_PRIVATE #define CIRCUITLIST_PRIVATE +#define CONNECTION_EDGE_PRIVATE +#define CONNECTION_PRIVATE + #include "or.h" #include "main.h" #include "config.h" #include "connection.h" #include "crypto.h" +#include "crypto_rand.h" #include "circuitbuild.h" #include "circuitlist.h" #include "connection_edge.h" +#include "log_test_helpers.h" #include "relay.h" #include "test.h" +#include "log_test_helpers.h" + +#include "circpathbias.h" +#include "connection_edge.h" + static int srm_ncalls; static entry_connection_t *srm_conn; static int srm_atype; @@ -25,11 +35,6 @@ static uint8_t srm_answer[512]; static int srm_ttl; static time_t srm_expires; -void connection_free_minimal(connection_t*); -int connected_cell_format_payload(uint8_t *payload_out, - const tor_addr_t *addr, - uint32_t ttl); - /* Mock replacement for connection_ap_hannshake_socks_resolved() */ static void socks_resolved_mock(entry_connection_t *conn, @@ -102,6 +107,16 @@ mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, } static void +mock_mark_circ_for_close(circuit_t *circ, int reason, int line, + const char *file) +{ + (void)reason; (void)line; (void)file; + + circ->marked_for_close = 1; + return; +} + +static void mock_mark_for_close(connection_t *conn, int line, const char *file) { @@ -119,19 +134,38 @@ mock_start_reading(connection_t *conn) return; } -static void -test_circbw_relay(void *arg) +static int +mock_send_command(streamid_t stream_id, circuit_t *circ, + uint8_t relay_command, const char *payload, + size_t payload_len, crypt_path_t *cpath_layer, + const char *filename, int lineno) +{ + (void)stream_id; (void)circ; + (void)relay_command; (void)payload; + (void)payload_len; (void)cpath_layer; + (void)filename; (void)lineno; + + return 0; +} + +static entry_connection_t * +fake_entry_conn(origin_circuit_t *oncirc, streamid_t id) { - cell_t cell; - relay_header_t rh; - tor_addr_t addr; edge_connection_t *edgeconn; entry_connection_t *entryconn; - origin_circuit_t *circ; - int delivered = 0; - int overhead = 0; - (void)arg; + entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET); + edgeconn = ENTRY_TO_EDGE_CONN(entryconn); + edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; + edgeconn->deliver_window = STREAMWINDOW_START; + edgeconn->package_window = STREAMWINDOW_START; + + edgeconn->stream_id = id; + edgeconn->on_circuit = TO_CIRCUIT(oncirc); + edgeconn->cpath_layer = oncirc->cpath; + + return entryconn; +} #define PACK_CELL(id, cmd, body_s) do { \ memset(&cell, 0, sizeof(cell)); \ @@ -154,18 +188,521 @@ test_circbw_relay(void *arg) tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, overhead); \ } while (0) +static int +subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) +{ + cell_t cell; + relay_header_t rh; + edge_connection_t *edgeconn; + entry_connection_t *entryconn2=NULL; + entry_connection_t *entryconn3=NULL; + entry_connection_t *entryconn4=NULL; + int delivered = circ->n_delivered_read_circ_bw; + int overhead = circ->n_overhead_read_circ_bw; + + /* Make new entryconns */ + entryconn2 = fake_entry_conn(circ, init_id); + entryconn2->socks_request->has_finished = 1; + entryconn3 = fake_entry_conn(circ, init_id+1); + entryconn3->socks_request->has_finished = 1; + entryconn4 = fake_entry_conn(circ, init_id+2); + entryconn4->socks_request->has_finished = 1; + edgeconn = ENTRY_TO_EDGE_CONN(entryconn2); + edgeconn->package_window = 23; + edgeconn->base_.state = AP_CONN_STATE_OPEN; + + int data_cells = edgeconn->deliver_window; + int sendme_cells = (STREAMWINDOW_START-edgeconn->package_window) + /STREAMWINDOW_INCREMENT; + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + connection_edge_reached_eof(edgeconn); + + /* Data cell not in the half-opened list */ + PACK_CELL(4000, RELAY_COMMAND_DATA, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Sendme cell not in the half-opened list */ + PACK_CELL(4000, RELAY_COMMAND_SENDME, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Connected cell not in the half-opened list */ + PACK_CELL(4000, RELAY_COMMAND_CONNECTED, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Resolved cell not in the half-opened list */ + PACK_CELL(4000, RELAY_COMMAND_RESOLVED, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Connected cell: not counted -- we were open */ + edgeconn = ENTRY_TO_EDGE_CONN(entryconn2); + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* DATA cells up to limit */ + while (data_cells > 0) { + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + data_cells--; + } + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* SENDME cells up to limit */ + while (sendme_cells > 0) { + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + sendme_cells--; + } + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Only one END cell */ + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + + ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + edgeconn = ENTRY_TO_EDGE_CONN(entryconn3); + edgeconn->base_.state = AP_CONN_STATE_OPEN; + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + /* sendme cell on open entryconn with full window */ + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); + int ret = + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + circ->cpath); + tt_int_op(ret, OP_EQ, -END_CIRC_REASON_TORPROTOCOL); + ASSERT_UNCOUNTED_BW(); + + /* connected cell on a after EOF */ + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; + connection_edge_reached_eof(edgeconn); + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* DATA and SENDME after END cell */ + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); + ret = + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + tt_int_op(ret, OP_NE, -END_CIRC_REASON_TORPROTOCOL); + ASSERT_UNCOUNTED_BW(); + + ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Resolved: 1 counted, more not */ + edgeconn = ENTRY_TO_EDGE_CONN(entryconn4); + entryconn4->socks_request->command = SOCKS_COMMAND_RESOLVE; + edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; + edgeconn->on_circuit = TO_CIRCUIT(circ); + ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; + connection_edge_reached_eof(edgeconn); + + ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, + "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_COUNTED_BW(); + + ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, + "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Data not counted after resolved */ + ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* End not counted after resolved */ + ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; + PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); + if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + else + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + connection_free_minimal(ENTRY_TO_CONN(entryconn2)); + connection_free_minimal(ENTRY_TO_CONN(entryconn3)); + connection_free_minimal(ENTRY_TO_CONN(entryconn4)); + return 1; + done: + connection_free_minimal(ENTRY_TO_CONN(entryconn2)); + connection_free_minimal(ENTRY_TO_CONN(entryconn3)); + connection_free_minimal(ENTRY_TO_CONN(entryconn4)); + return 0; +} + +static int +halfstream_insert(origin_circuit_t *circ, edge_connection_t *edgeconn, + streamid_t *streams, int num, int random) +{ + int inserted = 0; + + /* Insert num random elements */ + while (inserted < num) { + streamid_t id; + + if (random) + id = (streamid_t)crypto_rand_int(65535)+1; + else + id = get_unique_stream_id_by_circ(circ); + + edgeconn->stream_id = id; + + /* Ensure it isn't there */ + if (connection_half_edge_find_stream_id(circ->half_streams, id)) { + continue; + } + + connection_half_edge_add(edgeconn, circ); + if (streams) + streams[inserted] = id; + inserted++; + } + + return inserted; +} + +static void +subtest_halfstream_insertremove(int num) +{ + origin_circuit_t *circ = + helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0); + edge_connection_t *edgeconn; + entry_connection_t *entryconn; + streamid_t *streams = tor_malloc_zero(num*sizeof(streamid_t)); + int i = 0; + + circ->cpath->state = CPATH_STATE_AWAITING_KEYS; + circ->cpath->deliver_window = CIRCWINDOW_START; + + entryconn = fake_entry_conn(circ, 23); + edgeconn = ENTRY_TO_EDGE_CONN(entryconn); + + /* Explicity test all operations on an absent stream list */ + tt_int_op(connection_half_edge_is_valid_data(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 23), OP_EQ, 0); + + /* Insert a duplicate element; verify that other elements absent; + * ensure removing it once works */ + edgeconn->stream_id = 23; + connection_half_edge_add(edgeconn, circ); + connection_half_edge_add(edgeconn, circ); + connection_half_edge_add(edgeconn, circ); + + /* Verify that other elements absent */ + tt_int_op(connection_half_edge_is_valid_data(circ->half_streams, + 22), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams, + 22), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams, + 22), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams, + 22), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 22), OP_EQ, 0); + + tt_int_op(connection_half_edge_is_valid_data(circ->half_streams, + 24), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams, + 24), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams, + 24), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams, + 24), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 24), OP_EQ, 0); + + /* Verify we only remove it once */ + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 23), OP_EQ, 1); + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 23), OP_EQ, 0); + + halfstream_insert(circ, edgeconn, streams, num, 1); + + /* Remove half of them */ + for (i = 0; i < num/2; i++) { + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + streams[i]), + OP_EQ, 1); + } + + /* Verify first half of list is gone */ + for (i = 0; i < num/2; i++) { + tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams, + streams[i]), + OP_EQ, NULL); + } + + /* Verify second half of list is present */ + for (; i < num; i++) { + tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams, + streams[i]), + OP_NE, NULL); + } + + /* Remove other half. Verify list is empty. */ + for (i = num/2; i < num; i++) { + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + streams[i]), + OP_EQ, 1); + } + tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 0); + + /* Explicity test all operations on an empty stream list */ + tt_int_op(connection_half_edge_is_valid_data(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams, + 23), OP_EQ, 0); + tt_int_op(connection_half_edge_is_valid_end(circ->half_streams, + 23), OP_EQ, 0); + + /* For valgrind, leave some around then free the circ */ + halfstream_insert(circ, edgeconn, NULL, 10, 0); + + done: + tor_free(streams); + circuit_free_(TO_CIRCUIT(circ)); + connection_free_minimal(ENTRY_TO_CONN(entryconn)); +} + +static void +test_halfstream_insertremove(void *arg) +{ + (void)arg; + + /* Suppress the WARN message we generate in this test */ + setup_full_capture_of_logs(LOG_WARN); + + /* Test insertion and removal with a few different sizes */ + subtest_halfstream_insertremove(10); + subtest_halfstream_insertremove(100); + subtest_halfstream_insertremove(1000); +} + +static void +test_halfstream_wrap(void *arg) +{ + origin_circuit_t *circ = + helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0); + edge_connection_t *edgeconn; + entry_connection_t *entryconn; + + circ->cpath->state = CPATH_STATE_AWAITING_KEYS; + circ->cpath->deliver_window = CIRCWINDOW_START; + + entryconn = fake_entry_conn(circ, 23); + edgeconn = ENTRY_TO_EDGE_CONN(entryconn); + + (void)arg; + + /* Suppress the WARN message we generate in this test */ + setup_full_capture_of_logs(LOG_WARN); + MOCK(connection_mark_for_close_internal_, mock_mark_for_close); + + /* Verify that get_unique_stream_id_by_circ() can wrap uint16_t */ + circ->next_stream_id = 65530; + halfstream_insert(circ, edgeconn, NULL, 7, 0); + tt_int_op(circ->next_stream_id, OP_EQ, 2); + tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 7); + + /* Insert full-1 */ + halfstream_insert(circ, edgeconn, NULL, + 65534-smartlist_len(circ->half_streams), 0); + tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534); + + /* Verify that we can get_unique_stream_id_by_circ() successfully */ + edgeconn->stream_id = get_unique_stream_id_by_circ(circ); + tt_int_op(edgeconn->stream_id, OP_NE, 0); /* 0 is failure */ + + /* Insert an opened stream on the circ with that id */ + ENTRY_TO_CONN(entryconn)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; + circ->p_streams = edgeconn; + + /* Verify that get_unique_stream_id_by_circ() fails */ + tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */ + + /* eof the one opened stream. Verify it is now in half-closed */ + tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534); + connection_edge_reached_eof(edgeconn); + tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65535); + + /* Verify get_unique_stream_id_by_circ() fails due to full half-closed */ + circ->p_streams = NULL; + tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */ + + done: + circuit_free_(TO_CIRCUIT(circ)); + connection_free_minimal(ENTRY_TO_CONN(entryconn)); + UNMOCK(connection_mark_for_close_internal_); +} + +static void +test_circbw_relay(void *arg) +{ + cell_t cell; + relay_header_t rh; + tor_addr_t addr; + edge_connection_t *edgeconn; + entry_connection_t *entryconn1=NULL; + origin_circuit_t *circ; + int delivered = 0; + int overhead = 0; + + (void)arg; + MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_); MOCK(connection_start_reading, mock_start_reading); MOCK(connection_mark_for_close_internal_, mock_mark_for_close); + MOCK(relay_send_command_from_edge_, mock_send_command); + MOCK(circuit_mark_for_close_, mock_mark_circ_for_close); - entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET); - edgeconn = ENTRY_TO_EDGE_CONN(entryconn); - edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; - edgeconn->deliver_window = 1000; circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0); - edgeconn->cpath_layer = circ->cpath; circ->cpath->state = CPATH_STATE_AWAITING_KEYS; - circ->cpath->deliver_window = 1000; + circ->cpath->deliver_window = CIRCWINDOW_START; + + entryconn1 = fake_entry_conn(circ, 1); + edgeconn = ENTRY_TO_EDGE_CONN(entryconn1); /* Stream id 0: Not counted */ PACK_CELL(0, RELAY_COMMAND_END, "Data1234"); @@ -191,7 +728,7 @@ test_circbw_relay(void *arg) /* Properly formatted resolved cell in correct state: counted */ edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; - entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; + entryconn1->socks_request->command = SOCKS_COMMAND_RESOLVE; edgeconn->on_circuit = TO_CIRCUIT(circ); PACK_CELL(1, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); @@ -200,7 +737,7 @@ test_circbw_relay(void *arg) ASSERT_COUNTED_BW(); edgeconn->base_.state = AP_CONN_STATE_OPEN; - entryconn->socks_request->has_finished = 1; + entryconn1->socks_request->has_finished = 1; /* Connected cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); @@ -221,42 +758,43 @@ test_circbw_relay(void *arg) ASSERT_UNCOUNTED_BW(); /* Data cell on stream 0: not counted */ - PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234"); + PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Data cell on open connection: counted */ - ENTRY_TO_CONN(entryconn)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Empty Data cell on open connection: not counted */ - ENTRY_TO_CONN(entryconn)->marked_for_close = 0; + ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, ""); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on valid stream: counted */ - ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + edgeconn->package_window -= STREAMWINDOW_INCREMENT; + ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Sendme on valid stream with full window: not counted */ - ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); - edgeconn->package_window = 500; + edgeconn->package_window = STREAMWINDOW_START; connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on unknown stream: not counted */ - ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); @@ -275,18 +813,6 @@ test_circbw_relay(void *arg) circ->cpath); ASSERT_COUNTED_BW(); - /* End cell on non-closed connection: counted */ - PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, - circ->cpath); - ASSERT_COUNTED_BW(); - - /* End cell on connection that already got one: not counted */ - PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, - circ->cpath); - ASSERT_UNCOUNTED_BW(); - /* Invalid extended cell: not counted */ PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, @@ -312,12 +838,40 @@ test_circbw_relay(void *arg) circ->cpath); ASSERT_COUNTED_BW(); + /* End cell on non-closed connection: counted */ + PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + circ->cpath); + ASSERT_COUNTED_BW(); + + /* End cell on connection that already got one: not counted */ + PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Simulate closed stream on entryconn, then test: */ + if (!subtest_circbw_halfclosed(circ, 2)) + goto done; + + circ->base_.purpose = CIRCUIT_PURPOSE_PATH_BIAS_TESTING; + if (!subtest_circbw_halfclosed(circ, 6)) + goto done; + + /* Path bias: truncated */ + tt_int_op(circ->base_.marked_for_close, OP_EQ, 0); + PACK_CELL(0, RELAY_COMMAND_TRUNCATED, "Data1234"); + pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + tt_int_op(circ->base_.marked_for_close, OP_EQ, 1); + done: UNMOCK(connection_start_reading); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_mark_for_close_internal_); + UNMOCK(relay_send_command_from_edge_); + UNMOCK(circuit_mark_for_close_); circuit_free_(TO_CIRCUIT(circ)); - connection_free_minimal(ENTRY_TO_CONN(entryconn)); + connection_free_minimal(ENTRY_TO_CONN(entryconn1)); } /* Tests for connection_edge_process_resolved_cell(). @@ -505,6 +1059,7 @@ test_relaycell_resolved(void *arg) struct testcase_t relaycell_tests[] = { { "resolved", test_relaycell_resolved, TT_FORK, NULL, NULL }, { "circbw", test_circbw_relay, TT_FORK, NULL, NULL }, + { "halfstream", test_halfstream_insertremove, TT_FORK, NULL, NULL }, + { "streamwrap", test_halfstream_wrap, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - |