1 /* Copyright (c) 2013-2015, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define TOR_CHANNEL_INTERNAL_
5 #define CIRCUITBUILD_PRIVATE
6 #define CIRCUITLIST_PRIVATE
9 #include "circuitbuild.h"
10 #include "circuitlist.h"
14 new_fake_channel(void)
16 channel_t
*chan
= tor_malloc_zero(sizeof(channel_t
));
29 circuitmux_attach_mock(circuitmux_t
*cmux
, circuit_t
*circ
,
45 circuitmux_detach_mock(circuitmux_t
*cmux
, circuit_t
*circ
)
52 #define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
53 tt_int_op(cam.ncalls, OP_EQ, 1); \
54 tt_ptr_op(cam.cmux, OP_EQ, (mux_)); \
55 tt_ptr_op(cam.circ, OP_EQ, (circ_)); \
56 tt_int_op(cam.dir, OP_EQ, (dir_)); \
57 memset(&cam, 0, sizeof(cam)); \
60 #define GOT_CMUX_DETACH(mux_, circ_) do { \
61 tt_int_op(cdm.ncalls, OP_EQ, 1); \
62 tt_ptr_op(cdm.cmux, OP_EQ, (mux_)); \
63 tt_ptr_op(cdm.circ, OP_EQ, (circ_)); \
64 memset(&cdm, 0, sizeof(cdm)); \
68 test_clist_maps(void *arg
)
70 channel_t
*ch1
= new_fake_channel();
71 channel_t
*ch2
= new_fake_channel();
72 channel_t
*ch3
= new_fake_channel();
73 or_circuit_t
*or_c1
=NULL
, *or_c2
=NULL
;
77 MOCK(circuitmux_attach_circuit
, circuitmux_attach_mock
);
78 MOCK(circuitmux_detach_circuit
, circuitmux_detach_mock
);
79 memset(&cam
, 0, sizeof(cam
));
80 memset(&cdm
, 0, sizeof(cdm
));
86 ch1
->cmux
= tor_malloc(1);
87 ch2
->cmux
= tor_malloc(1);
88 ch3
->cmux
= tor_malloc(1);
90 or_c1
= or_circuit_new(100, ch2
);
92 GOT_CMUX_ATTACH(ch2
->cmux
, or_c1
, CELL_DIRECTION_IN
);
93 tt_int_op(or_c1
->p_circ_id
, OP_EQ
, 100);
94 tt_ptr_op(or_c1
->p_chan
, OP_EQ
, ch2
);
96 or_c2
= or_circuit_new(100, ch1
);
98 GOT_CMUX_ATTACH(ch1
->cmux
, or_c2
, CELL_DIRECTION_IN
);
99 tt_int_op(or_c2
->p_circ_id
, OP_EQ
, 100);
100 tt_ptr_op(or_c2
->p_chan
, OP_EQ
, ch1
);
102 circuit_set_n_circid_chan(TO_CIRCUIT(or_c1
), 200, ch1
);
103 GOT_CMUX_ATTACH(ch1
->cmux
, or_c1
, CELL_DIRECTION_OUT
);
105 circuit_set_n_circid_chan(TO_CIRCUIT(or_c2
), 200, ch2
);
106 GOT_CMUX_ATTACH(ch2
->cmux
, or_c2
, CELL_DIRECTION_OUT
);
108 tt_ptr_op(circuit_get_by_circid_channel(200, ch1
), OP_EQ
, TO_CIRCUIT(or_c1
));
109 tt_ptr_op(circuit_get_by_circid_channel(200, ch2
), OP_EQ
, TO_CIRCUIT(or_c2
));
110 tt_ptr_op(circuit_get_by_circid_channel(100, ch2
), OP_EQ
, TO_CIRCUIT(or_c1
));
111 /* Try the same thing again, to test the "fast" path. */
112 tt_ptr_op(circuit_get_by_circid_channel(100, ch2
), OP_EQ
, TO_CIRCUIT(or_c1
));
113 tt_assert(circuit_id_in_use_on_channel(100, ch2
));
114 tt_assert(! circuit_id_in_use_on_channel(101, ch2
));
116 /* Try changing the circuitid and channel of that circuit. */
117 circuit_set_p_circid_chan(or_c1
, 500, ch3
);
118 GOT_CMUX_DETACH(ch2
->cmux
, TO_CIRCUIT(or_c1
));
119 GOT_CMUX_ATTACH(ch3
->cmux
, TO_CIRCUIT(or_c1
), CELL_DIRECTION_IN
);
120 tt_ptr_op(circuit_get_by_circid_channel(100, ch2
), OP_EQ
, NULL
);
121 tt_assert(! circuit_id_in_use_on_channel(100, ch2
));
122 tt_ptr_op(circuit_get_by_circid_channel(500, ch3
), OP_EQ
, TO_CIRCUIT(or_c1
));
124 /* Now let's see about destroy handling. */
125 tt_assert(! circuit_id_in_use_on_channel(205, ch2
));
126 tt_assert(circuit_id_in_use_on_channel(200, ch2
));
127 channel_note_destroy_pending(ch2
, 200);
128 channel_note_destroy_pending(ch2
, 205);
129 channel_note_destroy_pending(ch1
, 100);
130 tt_assert(circuit_id_in_use_on_channel(205, ch2
))
131 tt_assert(circuit_id_in_use_on_channel(200, ch2
));
132 tt_assert(circuit_id_in_use_on_channel(100, ch1
));
134 tt_assert(TO_CIRCUIT(or_c2
)->n_delete_pending
!= 0);
135 tt_ptr_op(circuit_get_by_circid_channel(200, ch2
), OP_EQ
, TO_CIRCUIT(or_c2
));
136 tt_ptr_op(circuit_get_by_circid_channel(100, ch1
), OP_EQ
, TO_CIRCUIT(or_c2
));
138 /* Okay, now free ch2 and make sure that the circuit ID is STILL not
139 * usable, because we haven't declared the destroy to be nonpending */
140 tt_int_op(cdm
.ncalls
, OP_EQ
, 0);
141 circuit_free(TO_CIRCUIT(or_c2
));
142 or_c2
= NULL
; /* prevent free */
143 tt_int_op(cdm
.ncalls
, OP_EQ
, 2);
144 memset(&cdm
, 0, sizeof(cdm
));
145 tt_assert(circuit_id_in_use_on_channel(200, ch2
));
146 tt_assert(circuit_id_in_use_on_channel(100, ch1
));
147 tt_ptr_op(circuit_get_by_circid_channel(200, ch2
), OP_EQ
, NULL
);
148 tt_ptr_op(circuit_get_by_circid_channel(100, ch1
), OP_EQ
, NULL
);
150 /* Now say that the destroy is nonpending */
151 channel_note_destroy_not_pending(ch2
, 200);
152 tt_ptr_op(circuit_get_by_circid_channel(200, ch2
), OP_EQ
, NULL
);
153 channel_note_destroy_not_pending(ch1
, 100);
154 tt_ptr_op(circuit_get_by_circid_channel(100, ch1
), OP_EQ
, NULL
);
155 tt_assert(! circuit_id_in_use_on_channel(200, ch2
));
156 tt_assert(! circuit_id_in_use_on_channel(100, ch1
));
160 circuit_free(TO_CIRCUIT(or_c1
));
162 circuit_free(TO_CIRCUIT(or_c2
));
172 UNMOCK(circuitmux_attach_circuit
);
173 UNMOCK(circuitmux_detach_circuit
);
177 test_rend_token_maps(void *arg
)
179 or_circuit_t
*c1
, *c2
, *c3
, *c4
;
180 const uint8_t tok1
[REND_TOKEN_LEN
] = "The cat can't tell y";
181 const uint8_t tok2
[REND_TOKEN_LEN
] = "ou its name, and it ";
182 const uint8_t tok3
[REND_TOKEN_LEN
] = "doesn't really care.";
183 /* -- Adapted from a quote by Fredrik Lundh. */
187 c1
= or_circuit_new(0, NULL
);
188 c2
= or_circuit_new(0, NULL
);
189 c3
= or_circuit_new(0, NULL
);
190 c4
= or_circuit_new(0, NULL
);
192 /* Make sure we really filled up the tok* variables */
193 tt_int_op(tok1
[REND_TOKEN_LEN
-1], OP_EQ
, 'y');
194 tt_int_op(tok2
[REND_TOKEN_LEN
-1], OP_EQ
, ' ');
195 tt_int_op(tok3
[REND_TOKEN_LEN
-1], OP_EQ
, '.');
197 /* No maps; nothing there. */
198 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok1
));
199 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok1
));
201 circuit_set_rendezvous_cookie(c1
, tok1
);
202 circuit_set_intro_point_digest(c2
, tok2
);
204 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok3
));
205 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok3
));
206 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok2
));
207 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok1
));
209 /* Without purpose set, we don't get the circuits */
210 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok1
));
211 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok2
));
213 c1
->base_
.purpose
= CIRCUIT_PURPOSE_REND_POINT_WAITING
;
214 c2
->base_
.purpose
= CIRCUIT_PURPOSE_INTRO_POINT
;
216 /* Okay, make sure they show up now. */
217 tt_ptr_op(c1
, OP_EQ
, circuit_get_rendezvous(tok1
));
218 tt_ptr_op(c2
, OP_EQ
, circuit_get_intro_point(tok2
));
220 /* Two items at the same place with the same token. */
221 c3
->base_
.purpose
= CIRCUIT_PURPOSE_REND_POINT_WAITING
;
222 circuit_set_rendezvous_cookie(c3
, tok2
);
223 tt_ptr_op(c2
, OP_EQ
, circuit_get_intro_point(tok2
));
224 tt_ptr_op(c3
, OP_EQ
, circuit_get_rendezvous(tok2
));
226 /* Marking a circuit makes it not get returned any more */
227 circuit_mark_for_close(TO_CIRCUIT(c1
), END_CIRC_REASON_FINISHED
);
228 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok1
));
229 circuit_free(TO_CIRCUIT(c1
));
232 /* Freeing a circuit makes it not get returned any more. */
233 circuit_free(TO_CIRCUIT(c2
));
235 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok2
));
237 /* c3 -- are you still there? */
238 tt_ptr_op(c3
, OP_EQ
, circuit_get_rendezvous(tok2
));
239 /* Change its cookie. This never happens in Tor per se, but hey. */
240 c3
->base_
.purpose
= CIRCUIT_PURPOSE_INTRO_POINT
;
241 circuit_set_intro_point_digest(c3
, tok3
);
243 tt_ptr_op(NULL
, OP_EQ
, circuit_get_rendezvous(tok2
));
244 tt_ptr_op(c3
, OP_EQ
, circuit_get_intro_point(tok3
));
246 /* Now replace c3 with c4. */
247 c4
->base_
.purpose
= CIRCUIT_PURPOSE_INTRO_POINT
;
248 circuit_set_intro_point_digest(c4
, tok3
);
250 tt_ptr_op(c4
, OP_EQ
, circuit_get_intro_point(tok3
));
252 tt_ptr_op(c3
->rendinfo
, OP_EQ
, NULL
);
253 tt_ptr_op(c4
->rendinfo
, OP_NE
, NULL
);
254 tt_mem_op(c4
->rendinfo
, OP_EQ
, tok3
, REND_TOKEN_LEN
);
256 /* Now clear c4's cookie. */
257 circuit_set_intro_point_digest(c4
, NULL
);
258 tt_ptr_op(c4
->rendinfo
, OP_EQ
, NULL
);
259 tt_ptr_op(NULL
, OP_EQ
, circuit_get_intro_point(tok3
));
263 circuit_free(TO_CIRCUIT(c1
));
265 circuit_free(TO_CIRCUIT(c2
));
267 circuit_free(TO_CIRCUIT(c3
));
269 circuit_free(TO_CIRCUIT(c4
));
273 test_pick_circid(void *arg
)
275 bitarray_t
*ba
= NULL
;
276 channel_t
*chan1
, *chan2
;
281 chan1
= tor_malloc_zero(sizeof(channel_t
));
282 chan2
= tor_malloc_zero(sizeof(channel_t
));
283 chan2
->wide_circ_ids
= 1;
285 chan1
->circ_id_type
= CIRC_ID_TYPE_NEITHER
;
286 tt_int_op(0, OP_EQ
, get_unique_circ_id_by_chan(chan1
));
288 /* Basic tests, with no collisions */
289 chan1
->circ_id_type
= CIRC_ID_TYPE_LOWER
;
290 for (i
= 0; i
< 50; ++i
) {
291 circid
= get_unique_circ_id_by_chan(chan1
);
292 tt_uint_op(0, OP_LT
, circid
);
293 tt_uint_op(circid
, OP_LT
, (1<<15));
295 chan1
->circ_id_type
= CIRC_ID_TYPE_HIGHER
;
296 for (i
= 0; i
< 50; ++i
) {
297 circid
= get_unique_circ_id_by_chan(chan1
);
298 tt_uint_op((1<<15), OP_LT
, circid
);
299 tt_uint_op(circid
, OP_LT
, (1<<16));
302 chan2
->circ_id_type
= CIRC_ID_TYPE_LOWER
;
303 for (i
= 0; i
< 50; ++i
) {
304 circid
= get_unique_circ_id_by_chan(chan2
);
305 tt_uint_op(0, OP_LT
, circid
);
306 tt_uint_op(circid
, OP_LT
, (1u<<31));
308 chan2
->circ_id_type
= CIRC_ID_TYPE_HIGHER
;
309 for (i
= 0; i
< 50; ++i
) {
310 circid
= get_unique_circ_id_by_chan(chan2
);
311 tt_uint_op((1u<<31), OP_LT
, circid
);
314 /* Now make sure that we can behave well when we are full up on circuits */
315 chan1
->circ_id_type
= CIRC_ID_TYPE_LOWER
;
316 chan2
->circ_id_type
= CIRC_ID_TYPE_LOWER
;
317 chan1
->wide_circ_ids
= chan2
->wide_circ_ids
= 0;
318 ba
= bitarray_init_zero((1<<15));
319 for (i
= 0; i
< (1<<15); ++i
) {
320 circid
= get_unique_circ_id_by_chan(chan1
);
322 tt_int_op(i
, OP_GT
, (1<<14));
325 tt_uint_op(circid
, OP_LT
, (1<<15));
326 tt_assert(! bitarray_is_set(ba
, circid
));
327 bitarray_set(ba
, circid
);
328 channel_mark_circid_unusable(chan1
, circid
);
330 tt_int_op(i
, OP_LT
, (1<<15));
331 /* Make sure that being full on chan1 does not interfere with chan2 */
332 for (i
= 0; i
< 100; ++i
) {
333 circid
= get_unique_circ_id_by_chan(chan2
);
334 tt_uint_op(circid
, OP_GT
, 0);
335 tt_uint_op(circid
, OP_LT
, (1<<15));
336 channel_mark_circid_unusable(chan2
, circid
);
346 struct testcase_t circuitlist_tests
[] = {
347 { "maps", test_clist_maps
, TT_FORK
, NULL
, NULL
},
348 { "rend_token_maps", test_rend_token_maps
, TT_FORK
, NULL
, NULL
},
349 { "pick_circid", test_pick_circid
, TT_FORK
, NULL
, NULL
},