|
@@ -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,
|
|
@@ -101,6 +106,16 @@ mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
|
|
|
conn->edge_.end_reason = 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
|
|
|
};
|
|
|
-
|