tor/src/test/test_circuitlist.c

353 lines
11 KiB
C
Raw Normal View History

/* Copyright (c) 2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
#include "or.h"
#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "test.h"
static channel_t *
new_fake_channel(void)
{
channel_t *chan = tor_malloc_zero(sizeof(channel_t));
channel_init(chan);
return chan;
}
static struct {
int ncalls;
void *cmux;
void *circ;
cell_direction_t dir;
} cam;
static void
circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t dir)
{
++cam.ncalls;
cam.cmux = cmux;
cam.circ = circ;
cam.dir = dir;
}
static struct {
int ncalls;
void *cmux;
void *circ;
} cdm;
static void
circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
{
++cdm.ncalls;
cdm.cmux = cmux;
cdm.circ = circ;
}
#define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
tt_int_op(cam.ncalls, ==, 1); \
tt_ptr_op(cam.cmux, ==, (mux_)); \
tt_ptr_op(cam.circ, ==, (circ_)); \
tt_int_op(cam.dir, ==, (dir_)); \
memset(&cam, 0, sizeof(cam)); \
} while (0)
#define GOT_CMUX_DETACH(mux_, circ_) do { \
tt_int_op(cdm.ncalls, ==, 1); \
tt_ptr_op(cdm.cmux, ==, (mux_)); \
tt_ptr_op(cdm.circ, ==, (circ_)); \
memset(&cdm, 0, sizeof(cdm)); \
} while (0)
static void
test_clist_maps(void *arg)
{
channel_t *ch1 = new_fake_channel();
channel_t *ch2 = new_fake_channel();
channel_t *ch3 = new_fake_channel();
or_circuit_t *or_c1=NULL, *or_c2=NULL;
(void) arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
memset(&cam, 0, sizeof(cam));
memset(&cdm, 0, sizeof(cdm));
tt_assert(ch1);
tt_assert(ch2);
tt_assert(ch3);
ch1->cmux = tor_malloc(1);
ch2->cmux = tor_malloc(1);
ch3->cmux = tor_malloc(1);
or_c1 = or_circuit_new(100, ch2);
tt_assert(or_c1);
GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
tt_int_op(or_c1->p_circ_id, ==, 100);
tt_ptr_op(or_c1->p_chan, ==, ch2);
or_c2 = or_circuit_new(100, ch1);
tt_assert(or_c2);
GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
tt_int_op(or_c2->p_circ_id, ==, 100);
tt_ptr_op(or_c2->p_chan, ==, ch1);
circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1));
tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
/* Try the same thing again, to test the "fast" path. */
tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
tt_assert(circuit_id_in_use_on_channel(100, ch2));
tt_assert(! circuit_id_in_use_on_channel(101, ch2));
/* Try changing the circuitid and channel of that circuit. */
circuit_set_p_circid_chan(or_c1, 500, ch3);
GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL);
tt_assert(! circuit_id_in_use_on_channel(100, ch2));
tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1));
/* Now let's see about destroy handling. */
tt_assert(! circuit_id_in_use_on_channel(205, ch2));
tt_assert(circuit_id_in_use_on_channel(200, ch2));
channel_note_destroy_pending(ch2, 200);
channel_note_destroy_pending(ch2, 205);
channel_note_destroy_pending(ch1, 100);
tt_assert(circuit_id_in_use_on_channel(205, ch2))
tt_assert(circuit_id_in_use_on_channel(200, ch2));
tt_assert(circuit_id_in_use_on_channel(100, ch1));
tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2));
/* 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, ==, 0);
circuit_free(TO_CIRCUIT(or_c2));
or_c2 = NULL; /* prevent free */
tt_int_op(cdm.ncalls, ==, 2);
memset(&cdm, 0, sizeof(cdm));
tt_assert(circuit_id_in_use_on_channel(200, ch2));
tt_assert(circuit_id_in_use_on_channel(100, ch1));
tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
/* Now say that the destroy is nonpending */
channel_note_destroy_not_pending(ch2, 200);
tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
channel_note_destroy_not_pending(ch1, 100);
tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
tt_assert(! circuit_id_in_use_on_channel(200, ch2));
tt_assert(! circuit_id_in_use_on_channel(100, ch1));
2013-07-15 23:35:56 +02:00
done:
if (or_c1)
circuit_free(TO_CIRCUIT(or_c1));
if (or_c2)
circuit_free(TO_CIRCUIT(or_c2));
if (ch1)
tor_free(ch1->cmux);
if (ch2)
tor_free(ch2->cmux);
if (ch3)
tor_free(ch3->cmux);
tor_free(ch1);
tor_free(ch2);
tor_free(ch3);
UNMOCK(circuitmux_attach_circuit);
UNMOCK(circuitmux_detach_circuit);
}
static void
test_rend_token_maps(void *arg)
{
or_circuit_t *c1, *c2, *c3, *c4;
const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
/* -- Adapted from a quote by Fredrik Lundh. */
(void)arg;
(void)tok1; //xxxx
c1 = or_circuit_new(0, NULL);
c2 = or_circuit_new(0, NULL);
c3 = or_circuit_new(0, NULL);
c4 = or_circuit_new(0, NULL);
/* Make sure we really filled up the tok* variables */
tt_int_op(tok1[REND_TOKEN_LEN-1], ==, 'y');
tt_int_op(tok2[REND_TOKEN_LEN-1], ==, ' ');
tt_int_op(tok3[REND_TOKEN_LEN-1], ==, '.');
/* No maps; nothing there. */
tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
circuit_set_rendezvous_cookie(c1, tok1);
circuit_set_intro_point_digest(c2, tok2);
tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok3));
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
/* Without purpose set, we don't get the circuits */
tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
/* Okay, make sure they show up now. */
tt_ptr_op(c1, ==, circuit_get_rendezvous(tok1));
tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
/* Two items at the same place with the same token. */
c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
circuit_set_rendezvous_cookie(c3, tok2);
tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
/* 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, ==, circuit_get_rendezvous(tok1));
circuit_free(TO_CIRCUIT(c1));
c1 = NULL;
/* Freeing a circuit makes it not get returned any more. */
circuit_free(TO_CIRCUIT(c2));
c2 = NULL;
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
/* c3 -- are you still there? */
tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
/* Change its cookie. This never happens in Tor per se, but hey. */
c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
circuit_set_intro_point_digest(c3, tok3);
tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
tt_ptr_op(c3, ==, circuit_get_intro_point(tok3));
/* Now replace c3 with c4. */
c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
circuit_set_intro_point_digest(c4, tok3);
tt_ptr_op(c4, ==, circuit_get_intro_point(tok3));
tt_ptr_op(c3->rendinfo, ==, NULL);
tt_ptr_op(c4->rendinfo, !=, NULL);
Use coccinelle scripts to clean up our unit tests This should get rid of most of the users of the old test_* functions. Some are in macros and will need manual cleanup, though. This patch is for 13119, and was automatically generated with these scripts. The perl scripts are there because coccinelle hates operators as macro arguments. ------------------------------ s/==,/_X_EQ_,/g; s/!=,/_X_NE_,/g; s/<,/_X_LT_,/g; s/>,/_X_GT_,/g; s/>=,/_X_GEQ_,/g; s/<=,/_X_LEQ_,/g; ------------------------------ @@ expression a; identifier func; @@ func (...) { <... -test_fail_msg +TT_DIE ( +( a +) ) ...> } @@ identifier func; @@ func (...) { <... -test_fail() +TT_DIE(("Assertion failed.")) ...> } @@ expression a; identifier func; @@ func (...) { <... -test_assert +tt_assert (a) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq +tt_int_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_neq +tt_int_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_streq +tt_str_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_strneq +tt_str_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq_ptr +tt_ptr_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func() { <... -test_neq_ptr +tt_ptr_op (a, +_X_NEQ_, b) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memeq +tt_mem_op (a, +_X_EQ_, b, len) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memneq +tt_mem_op (a, +_X_NEQ_, b, len) ...> } ------------------------------ @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } ------------------------------ s/_X_NEQ_/!=/g; s/_X_NE_/!=/g; s/_X_EQ_/==/g; s/_X_GT_/>/g; s/_X_LT_/</g; s/_X_GEQ_/>=/g; s/_X_LEQ_/<=/g; s/test_mem_op\(/tt_mem_op\(/g;
2014-09-16 03:18:21 +02:00
tt_mem_op(c4->rendinfo, ==, tok3, REND_TOKEN_LEN);
/* Now clear c4's cookie. */
circuit_set_intro_point_digest(c4, NULL);
tt_ptr_op(c4->rendinfo, ==, NULL);
tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
done:
if (c1)
circuit_free(TO_CIRCUIT(c1));
if (c2)
circuit_free(TO_CIRCUIT(c2));
if (c3)
circuit_free(TO_CIRCUIT(c3));
if (c4)
circuit_free(TO_CIRCUIT(c4));
}
static void
test_pick_circid(void *arg)
{
bitarray_t *ba = NULL;
channel_t *chan1, *chan2;
circid_t circid;
int i;
(void) arg;
chan1 = tor_malloc_zero(sizeof(channel_t));
chan2 = tor_malloc_zero(sizeof(channel_t));
chan2->wide_circ_ids = 1;
chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
tt_int_op(0, ==, get_unique_circ_id_by_chan(chan1));
/* Basic tests, with no collisions */
chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan1);
tt_uint_op(0, <, circid);
tt_uint_op(circid, <, (1<<15));
}
chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan1);
tt_uint_op((1<<15), <, circid);
tt_uint_op(circid, <, (1<<16));
}
chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
tt_uint_op(0, <, circid);
tt_uint_op(circid, <, (1u<<31));
}
chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
tt_uint_op((1u<<31), <, circid);
}
/* Now make sure that we can behave well when we are full up on circuits */
chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
ba = bitarray_init_zero((1<<15));
for (i = 0; i < (1<<15); ++i) {
circid = get_unique_circ_id_by_chan(chan1);
if (circid == 0) {
tt_int_op(i, >, (1<<14));
break;
}
tt_uint_op(circid, <, (1<<15));
tt_assert(! bitarray_is_set(ba, circid));
bitarray_set(ba, circid);
channel_mark_circid_unusable(chan1, circid);
}
tt_int_op(i, <, (1<<15));
/* Make sure that being full on chan1 does not interfere with chan2 */
for (i = 0; i < 100; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
tt_uint_op(circid, >, 0);
tt_uint_op(circid, <, (1<<15));
channel_mark_circid_unusable(chan2, circid);
}
done:
tor_free(chan1);
tor_free(chan2);
bitarray_free(ba);
circuit_free_all();
}
struct testcase_t circuitlist_tests[] = {
{ "maps", test_clist_maps, TT_FORK, NULL, NULL },
{ "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
{ "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
2013-07-15 23:35:56 +02:00