Merge branch 'maint-0.4.5' into release-0.4.5
[tor.git] / src / test / test_circuitmux.c
blobd6e3300a3015c66b6b4482d205b4fffdad410288
1 /* Copyright (c) 2013-2020, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define CHANNEL_OBJECT_PRIVATE
5 #define CIRCUITMUX_PRIVATE
6 #define CIRCUITMUX_EWMA_PRIVATE
7 #define RELAY_PRIVATE
9 #include "core/or/or.h"
10 #include "core/or/channel.h"
11 #include "core/or/circuitmux.h"
12 #include "core/or/circuitmux_ewma.h"
13 #include "core/or/destroy_cell_queue_st.h"
14 #include "core/or/relay.h"
15 #include "core/or/scheduler.h"
17 #include "test/fakechans.h"
18 #include "test/fakecircs.h"
19 #include "test/test.h"
21 #include <math.h>
23 static int
24 mock_has_queued_writes_true(channel_t *c)
26 (void) c;
27 return 1;
30 /** Test destroy cell queue with no interference from other queues. */
31 static void
32 test_cmux_destroy_cell_queue(void *arg)
34 circuitmux_t *cmux = NULL;
35 channel_t *ch = NULL;
36 circuit_t *circ = NULL;
37 destroy_cell_queue_t *cq = NULL;
38 packed_cell_t *pc = NULL;
39 destroy_cell_t *dc = NULL;
41 MOCK(scheduler_release_channel, scheduler_release_channel_mock);
43 (void) arg;
45 ch = new_fake_channel();
46 ch->has_queued_writes = mock_has_queued_writes_true;
47 ch->wide_circ_ids = 1;
48 cmux = ch->cmux;
50 circ = circuitmux_get_first_active_circuit(cmux, &cq);
51 tt_ptr_op(circ, OP_EQ, NULL);
52 tt_ptr_op(cq, OP_EQ, NULL);
54 circuitmux_append_destroy_cell(ch, cmux, 100, 10);
55 circuitmux_append_destroy_cell(ch, cmux, 190, 6);
56 circuitmux_append_destroy_cell(ch, cmux, 30, 1);
58 tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 3);
60 circ = circuitmux_get_first_active_circuit(cmux, &cq);
61 tt_ptr_op(circ, OP_EQ, NULL);
62 tt_assert(cq);
64 tt_int_op(cq->n, OP_EQ, 3);
66 dc = destroy_cell_queue_pop(cq);
67 tt_assert(dc);
68 tt_uint_op(dc->circid, OP_EQ, 100);
70 tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 2);
72 done:
73 free_fake_channel(ch);
74 packed_cell_free(pc);
75 tor_free(dc);
77 UNMOCK(scheduler_release_channel);
80 static void
81 test_cmux_compute_ticks(void *arg)
83 const int64_t NS_PER_S = 1000 * 1000 * 1000;
84 const int64_t START_NS = UINT64_C(1217709000)*NS_PER_S;
85 int64_t now;
86 double rem;
87 unsigned tick;
88 (void)arg;
89 circuitmux_ewma_free_all();
90 monotime_enable_test_mocking();
92 monotime_coarse_set_mock_time_nsec(START_NS);
93 cell_ewma_initialize_ticks();
94 const unsigned tick_zero = cell_ewma_get_current_tick_and_fraction(&rem);
95 tt_double_op(rem, OP_GT, -1e-9);
96 tt_double_op(rem, OP_LT, 1e-9);
98 /* 1.5 second later and we should still be in the same tick. */
99 now = START_NS + NS_PER_S + NS_PER_S/2;
100 monotime_coarse_set_mock_time_nsec(now);
101 tick = cell_ewma_get_current_tick_and_fraction(&rem);
102 tt_uint_op(tick, OP_EQ, tick_zero);
103 #ifdef USING_32BIT_MSEC_HACK
104 const double tolerance = .0005;
105 #else
106 const double tolerance = .00000001;
107 #endif
108 tt_double_op(fabs(rem - .15), OP_LT, tolerance);
110 /* 25 second later and we should be in another tick. */
111 now = START_NS + NS_PER_S * 25;
112 monotime_coarse_set_mock_time_nsec(now);
113 tick = cell_ewma_get_current_tick_and_fraction(&rem);
114 tt_uint_op(tick, OP_EQ, tick_zero + 2);
115 tt_double_op(fabs(rem - .5), OP_LT, tolerance);
117 done:
121 static void
122 test_cmux_allocate(void *arg)
124 circuitmux_t *cmux = NULL;
126 (void) arg;
128 cmux = circuitmux_alloc();
129 tt_assert(cmux);
130 tt_assert(cmux->chanid_circid_map);
131 tt_int_op(HT_SIZE(cmux->chanid_circid_map), OP_EQ, 0);
132 tt_uint_op(cmux->n_circuits, OP_EQ, 0);
133 tt_uint_op(cmux->n_active_circuits, OP_EQ, 0);
134 tt_uint_op(cmux->n_cells, OP_EQ, 0);
135 tt_uint_op(cmux->last_cell_was_destroy, OP_EQ, 0);
136 tt_i64_op(cmux->destroy_ctr, OP_EQ, 0);
137 tt_ptr_op(cmux->policy, OP_EQ, NULL);
138 tt_ptr_op(cmux->policy_data, OP_EQ, NULL);
140 tt_assert(TOR_SIMPLEQ_EMPTY(&cmux->destroy_cell_queue.head));
142 done:
143 circuitmux_free(cmux);
146 static void
147 test_cmux_attach_circuit(void *arg)
149 circuit_t *circ = NULL;
150 or_circuit_t *orcirc = NULL;
151 channel_t *pchan = NULL, *nchan = NULL;
152 cell_direction_t cdir;
153 unsigned int n_cells;
155 (void) arg;
157 pchan = new_fake_channel();
158 tt_assert(pchan);
159 nchan = new_fake_channel();
160 tt_assert(nchan);
162 orcirc = new_fake_orcirc(nchan, pchan);
163 tt_assert(orcirc);
164 circ = TO_CIRCUIT(orcirc);
166 /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
167 * called for a new channel on the circuit. This means, we should now have
168 * the created circuit attached on both the pchan and nchan cmux. */
169 tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
170 tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
172 /* There should be _no_ active circuit due to no queued cells. */
173 tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
174 tt_uint_op(circuitmux_num_active_circuits(nchan->cmux), OP_EQ, 0);
176 /* Circuit should not be active on the cmux. */
177 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
178 tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
180 /* Not active so no cells. */
181 n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
182 tt_uint_op(n_cells, OP_EQ, 0);
183 n_cells = circuitmux_num_cells(pchan->cmux);
184 tt_uint_op(n_cells, OP_EQ, 0);
185 n_cells = circuitmux_num_cells_for_circuit(nchan->cmux, circ);
186 tt_uint_op(n_cells, OP_EQ, 0);
187 n_cells = circuitmux_num_cells(nchan->cmux);
188 tt_uint_op(n_cells, OP_EQ, 0);
190 /* So it should be attached :) */
191 tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
192 tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
194 /* Query the chanid<->circid map in the cmux subsystem with what we just
195 * created and validate the cell direction. */
196 cdir = circuitmux_attached_circuit_direction(pchan->cmux, circ);
197 tt_int_op(cdir, OP_EQ, CELL_DIRECTION_IN);
198 cdir = circuitmux_attached_circuit_direction(nchan->cmux, circ);
199 tt_int_op(cdir, OP_EQ, CELL_DIRECTION_OUT);
202 * We'll activate->deactivate->activate to test all code paths of
203 * circuitmux_set_num_cells().
206 /* Activate circuit. */
207 circuitmux_set_num_cells(pchan->cmux, circ, 4);
208 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
210 /* Deactivate. */
211 circuitmux_clear_num_cells(pchan->cmux, circ);
212 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
213 tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
215 /* Re-activate. */
216 circuitmux_set_num_cells(pchan->cmux, circ, 4);
217 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
219 /* Once re-attached, it should become inactive because the circuit has no
220 * cells while the chanid<->circid object has some. The attach code will
221 * reset the count on the cmux for that circuit:
223 * if (chanid_circid_muxinfo_t->muxinfo.cell_count > 0 && cell_count == 0) {
225 circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
226 n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
227 tt_uint_op(n_cells, OP_EQ, 0);
228 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
229 tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
231 /* Lets queue a cell on the circuit now so it becomes active when
232 * re-attaching:
234 * else if (chanid_circid_muxinfo_t->muxinfo.cell_count == 0 &&
235 * cell_count > 0) {
237 orcirc->p_chan_cells.n = 1;
238 circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
239 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
241 done:
242 free_fake_orcirc(orcirc);
243 free_fake_channel(pchan);
244 free_fake_channel(nchan);
247 static void
248 test_cmux_detach_circuit(void *arg)
250 circuit_t *circ = NULL;
251 or_circuit_t *orcirc = NULL;
252 channel_t *pchan = NULL, *nchan = NULL;
254 (void) arg;
256 pchan = new_fake_channel();
257 tt_assert(pchan);
258 nchan = new_fake_channel();
259 tt_assert(nchan);
261 orcirc = new_fake_orcirc(nchan, pchan);
262 tt_assert(orcirc);
263 circ = TO_CIRCUIT(orcirc);
265 /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
266 * called for a new channel on the circuit. This means, we should now have
267 * the created circuit attached on both the pchan and nchan cmux. */
268 tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
269 tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
270 tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
271 tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
273 /* Now, detach the circuit from pchan and then nchan. */
274 circuitmux_detach_circuit(pchan->cmux, circ);
275 tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
276 tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
277 circuitmux_detach_circuit(nchan->cmux, circ);
278 tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
279 tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
281 done:
282 free_fake_orcirc(orcirc);
283 free_fake_channel(pchan);
284 free_fake_channel(nchan);
287 static void
288 test_cmux_detach_all_circuits(void *arg)
290 circuit_t *circ = NULL;
291 or_circuit_t *orcirc = NULL;
292 channel_t *pchan = NULL, *nchan = NULL;
293 smartlist_t *detached_out = smartlist_new();
295 (void) arg;
297 /* Channels need to be registered in order for the detach all circuit
298 * function to find them. */
299 pchan = new_fake_channel();
300 tt_assert(pchan);
301 channel_register(pchan);
302 nchan = new_fake_channel();
303 tt_assert(nchan);
304 channel_register(nchan);
306 orcirc = new_fake_orcirc(nchan, pchan);
307 tt_assert(orcirc);
308 circ = TO_CIRCUIT(orcirc);
310 /* Just make sure it is attached. */
311 tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
312 tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
313 tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
314 tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
316 /* Queue some cells so we can test if the circuit becomes inactive on the
317 * cmux after the mass detach. */
318 circuitmux_set_num_cells(pchan->cmux, circ, 4);
319 circuitmux_set_num_cells(nchan->cmux, circ, 4);
321 /* Detach all on pchan and then nchan. */
322 circuitmux_detach_all_circuits(pchan->cmux, detached_out);
323 tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
324 tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
325 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
326 tt_int_op(smartlist_len(detached_out), OP_EQ, 1);
327 circuitmux_detach_all_circuits(nchan->cmux, NULL);
328 tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
329 tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
330 tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
332 done:
333 smartlist_free(detached_out);
334 free_fake_orcirc(orcirc);
335 free_fake_channel(pchan);
336 free_fake_channel(nchan);
339 static void
340 test_cmux_policy(void *arg)
342 circuit_t *circ = NULL;
343 or_circuit_t *orcirc = NULL;
344 channel_t *pchan = NULL, *nchan = NULL;
346 (void) arg;
348 pchan = new_fake_channel();
349 tt_assert(pchan);
350 channel_register(pchan);
351 nchan = new_fake_channel();
352 tt_assert(nchan);
353 channel_register(nchan);
355 orcirc = new_fake_orcirc(nchan, pchan);
356 tt_assert(orcirc);
357 circ = TO_CIRCUIT(orcirc);
359 /* Confirm we have the EWMA policy by default for new channels. */
360 tt_ptr_op(circuitmux_get_policy(pchan->cmux), OP_EQ, &ewma_policy);
361 tt_ptr_op(circuitmux_get_policy(nchan->cmux), OP_EQ, &ewma_policy);
363 /* Putting cell on the cmux means will make the notify policy code path to
364 * trigger. */
365 circuitmux_set_num_cells(pchan->cmux, circ, 4);
367 /* Clear it out. */
368 circuitmux_clear_policy(pchan->cmux);
370 /* Set back the EWMA policy. */
371 circuitmux_set_policy(pchan->cmux, &ewma_policy);
373 done:
374 free_fake_orcirc(orcirc);
375 free_fake_channel(pchan);
376 free_fake_channel(nchan);
379 static void
380 test_cmux_xmit_cell(void *arg)
382 circuit_t *circ = NULL;
383 or_circuit_t *orcirc = NULL;
384 channel_t *pchan = NULL, *nchan = NULL;
386 (void) arg;
388 pchan = new_fake_channel();
389 tt_assert(pchan);
390 nchan = new_fake_channel();
391 tt_assert(nchan);
393 orcirc = new_fake_orcirc(nchan, pchan);
394 tt_assert(orcirc);
395 circ = TO_CIRCUIT(orcirc);
397 /* Queue 4 cells on the circuit. */
398 circuitmux_set_num_cells(pchan->cmux, circ, 4);
399 tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 4);
400 tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 4);
401 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
402 tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
404 /* Emit the first cell. Circuit should still be active. */
405 circuitmux_notify_xmit_cells(pchan->cmux, circ, 1);
406 tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 3);
407 tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 3);
408 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
409 tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
411 /* Emit the last 3 cells. Circuit should become inactive. */
412 circuitmux_notify_xmit_cells(pchan->cmux, circ, 3);
413 tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 0);
414 tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
415 tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
416 tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
418 /* Queue a DESTROY cell. */
419 pchan->has_queued_writes = mock_has_queued_writes_true;
420 circuitmux_append_destroy_cell(pchan, pchan->cmux, orcirc->p_circ_id, 0);
421 tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 1);
422 tt_int_op(pchan->cmux->destroy_cell_queue.n, OP_EQ, 1);
423 tt_i64_op(circuitmux_count_queued_destroy_cells(pchan, pchan->cmux),
424 OP_EQ, 1);
426 /* Emit the DESTROY cell. */
427 circuitmux_notify_xmit_destroy(pchan->cmux);
428 tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 0);
430 done:
431 free_fake_orcirc(orcirc);
432 free_fake_channel(pchan);
433 free_fake_channel(nchan);
436 static void *
437 cmux_setup_test(const struct testcase_t *tc)
439 static int whatever;
441 (void) tc;
443 cell_ewma_initialize_ticks();
444 return &whatever;
447 static int
448 cmux_cleanup_test(const struct testcase_t *tc, void *ptr)
450 (void) tc;
451 (void) ptr;
453 circuitmux_ewma_free_all();
455 return 1;
458 static struct testcase_setup_t cmux_test_setup = {
459 .setup_fn = cmux_setup_test,
460 .cleanup_fn = cmux_cleanup_test,
463 #define TEST_CMUX(name) \
464 { #name, test_cmux_##name, TT_FORK, &cmux_test_setup, NULL }
466 struct testcase_t circuitmux_tests[] = {
467 /* Test circuitmux_t object */
468 TEST_CMUX(allocate),
469 TEST_CMUX(attach_circuit),
470 TEST_CMUX(detach_circuit),
471 TEST_CMUX(detach_all_circuits),
472 TEST_CMUX(policy),
473 TEST_CMUX(xmit_cell),
475 /* Misc. */
476 TEST_CMUX(compute_ticks),
477 TEST_CMUX(destroy_cell_queue),
479 END_OF_TESTCASES