test_circuitlist.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /* Copyright (c) 2013, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. #define TOR_CHANNEL_INTERNAL_
  4. #define CIRCUITBUILD_PRIVATE
  5. #define CIRCUITLIST_PRIVATE
  6. #include "or.h"
  7. #include "channel.h"
  8. #include "circuitbuild.h"
  9. #include "circuitlist.h"
  10. #include "test.h"
  11. static channel_t *
  12. new_fake_channel(void)
  13. {
  14. channel_t *chan = tor_malloc_zero(sizeof(channel_t));
  15. channel_init(chan);
  16. return chan;
  17. }
  18. static struct {
  19. int ncalls;
  20. void *cmux;
  21. void *circ;
  22. cell_direction_t dir;
  23. } cam;
  24. static void
  25. circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
  26. cell_direction_t dir)
  27. {
  28. ++cam.ncalls;
  29. cam.cmux = cmux;
  30. cam.circ = circ;
  31. cam.dir = dir;
  32. }
  33. static struct {
  34. int ncalls;
  35. void *cmux;
  36. void *circ;
  37. } cdm;
  38. static void
  39. circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
  40. {
  41. ++cdm.ncalls;
  42. cdm.cmux = cmux;
  43. cdm.circ = circ;
  44. }
  45. #define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
  46. tt_int_op(cam.ncalls, ==, 1); \
  47. tt_ptr_op(cam.cmux, ==, (mux_)); \
  48. tt_ptr_op(cam.circ, ==, (circ_)); \
  49. tt_int_op(cam.dir, ==, (dir_)); \
  50. memset(&cam, 0, sizeof(cam)); \
  51. } while (0)
  52. #define GOT_CMUX_DETACH(mux_, circ_) do { \
  53. tt_int_op(cdm.ncalls, ==, 1); \
  54. tt_ptr_op(cdm.cmux, ==, (mux_)); \
  55. tt_ptr_op(cdm.circ, ==, (circ_)); \
  56. memset(&cdm, 0, sizeof(cdm)); \
  57. } while (0)
  58. static void
  59. test_clist_maps(void *arg)
  60. {
  61. channel_t *ch1 = new_fake_channel();
  62. channel_t *ch2 = new_fake_channel();
  63. channel_t *ch3 = new_fake_channel();
  64. or_circuit_t *or_c1=NULL, *or_c2=NULL;
  65. (void) arg;
  66. MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
  67. MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
  68. memset(&cam, 0, sizeof(cam));
  69. memset(&cdm, 0, sizeof(cdm));
  70. ch1->cmux = (void*)0x1001;
  71. ch2->cmux = (void*)0x1002;
  72. ch3->cmux = (void*)0x1003;
  73. or_c1 = or_circuit_new(100, ch2);
  74. tt_assert(or_c1);
  75. GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
  76. tt_int_op(or_c1->p_circ_id, ==, 100);
  77. tt_ptr_op(or_c1->p_chan, ==, ch2);
  78. or_c2 = or_circuit_new(100, ch1);
  79. tt_assert(or_c2);
  80. GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
  81. tt_int_op(or_c2->p_circ_id, ==, 100);
  82. tt_ptr_op(or_c2->p_chan, ==, ch1);
  83. circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
  84. GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
  85. circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
  86. GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
  87. tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1));
  88. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
  89. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
  90. /* Try the same thing again, to test the "fast" path. */
  91. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
  92. tt_assert(circuit_id_in_use_on_channel(100, ch2));
  93. tt_assert(! circuit_id_in_use_on_channel(101, ch2));
  94. /* Try changing the circuitid and channel of that circuit. */
  95. circuit_set_p_circid_chan(or_c1, 500, ch3);
  96. GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
  97. GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
  98. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL);
  99. tt_assert(! circuit_id_in_use_on_channel(100, ch2));
  100. tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1));
  101. /* Now let's see about destroy handling. */
  102. tt_assert(! circuit_id_in_use_on_channel(205, ch2));
  103. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  104. channel_note_destroy_pending(ch2, 200);
  105. channel_note_destroy_pending(ch2, 205);
  106. channel_note_destroy_pending(ch1, 100);
  107. tt_assert(circuit_id_in_use_on_channel(205, ch2))
  108. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  109. tt_assert(circuit_id_in_use_on_channel(100, ch1));
  110. tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
  111. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
  112. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2));
  113. /* Okay, now free ch2 and make sure that the circuit ID is STILL not
  114. * usable, because we haven't declared the destroy to be nonpending */
  115. tt_int_op(cdm.ncalls, ==, 0);
  116. circuit_free(TO_CIRCUIT(or_c2));
  117. or_c2 = NULL; /* prevent free */
  118. tt_int_op(cdm.ncalls, ==, 2);
  119. memset(&cdm, 0, sizeof(cdm));
  120. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  121. tt_assert(circuit_id_in_use_on_channel(100, ch1));
  122. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
  123. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
  124. /* Now say that the destroy is nonpending */
  125. channel_note_destroy_not_pending(ch2, 200);
  126. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
  127. channel_note_destroy_not_pending(ch1, 100);
  128. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
  129. tt_assert(! circuit_id_in_use_on_channel(200, ch2));
  130. tt_assert(! circuit_id_in_use_on_channel(100, ch1));
  131. done:
  132. if (or_c1)
  133. circuit_free(TO_CIRCUIT(or_c1));
  134. if (or_c2)
  135. circuit_free(TO_CIRCUIT(or_c2));
  136. tor_free(ch1);
  137. tor_free(ch2);
  138. tor_free(ch3);
  139. UNMOCK(circuitmux_attach_circuit);
  140. UNMOCK(circuitmux_detach_circuit);
  141. }
  142. static void
  143. test_rend_token_maps(void *arg)
  144. {
  145. or_circuit_t *c1, *c2, *c3, *c4;
  146. const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
  147. const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
  148. const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
  149. /* -- Adapted from a quote by Fredrik Lundh. */
  150. (void)arg;
  151. (void)tok1; //xxxx
  152. c1 = or_circuit_new(0, NULL);
  153. c2 = or_circuit_new(0, NULL);
  154. c3 = or_circuit_new(0, NULL);
  155. c4 = or_circuit_new(0, NULL);
  156. /* Make sure we really filled up the tok* variables */
  157. tt_int_op(tok1[REND_TOKEN_LEN-1], ==, 'y');
  158. tt_int_op(tok2[REND_TOKEN_LEN-1], ==, ' ');
  159. tt_int_op(tok3[REND_TOKEN_LEN-1], ==, '.');
  160. /* No maps; nothing there. */
  161. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
  162. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
  163. circuit_set_rendezvous_cookie(c1, tok1);
  164. circuit_set_intro_point_digest(c2, tok2);
  165. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok3));
  166. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
  167. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
  168. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
  169. /* Without purpose set, we don't get the circuits */
  170. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
  171. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
  172. c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  173. c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  174. /* Okay, make sure they show up now. */
  175. tt_ptr_op(c1, ==, circuit_get_rendezvous(tok1));
  176. tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
  177. /* Two items at the same place with the same token. */
  178. c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  179. circuit_set_rendezvous_cookie(c3, tok2);
  180. tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
  181. tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
  182. /* Marking a circuit makes it not get returned any more */
  183. circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
  184. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
  185. circuit_free(TO_CIRCUIT(c1));
  186. c1 = NULL;
  187. /* Freeing a circuit makes it not get returned any more. */
  188. circuit_free(TO_CIRCUIT(c2));
  189. c2 = NULL;
  190. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
  191. /* c3 -- are you still there? */
  192. tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
  193. /* Change its cookie. This never happens in Tor per se, but hey. */
  194. c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  195. circuit_set_intro_point_digest(c3, tok3);
  196. tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
  197. tt_ptr_op(c3, ==, circuit_get_intro_point(tok3));
  198. /* Now replace c3 with c4. */
  199. c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  200. circuit_set_intro_point_digest(c4, tok3);
  201. tt_ptr_op(c4, ==, circuit_get_intro_point(tok3));
  202. tt_ptr_op(c3->rendinfo, ==, NULL);
  203. tt_ptr_op(c4->rendinfo, !=, NULL);
  204. test_mem_op(c4->rendinfo, ==, tok3, REND_TOKEN_LEN);
  205. /* Now clear c4's cookie. */
  206. circuit_set_intro_point_digest(c4, NULL);
  207. tt_ptr_op(c4->rendinfo, ==, NULL);
  208. tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
  209. done:
  210. if (c1)
  211. circuit_free(TO_CIRCUIT(c1));
  212. if (c2)
  213. circuit_free(TO_CIRCUIT(c2));
  214. if (c3)
  215. circuit_free(TO_CIRCUIT(c3));
  216. if (c4)
  217. circuit_free(TO_CIRCUIT(c4));
  218. }
  219. static void
  220. test_pick_circid(void *arg)
  221. {
  222. bitarray_t *ba = NULL;
  223. channel_t *chan1, *chan2;
  224. circid_t circid;
  225. int i;
  226. (void) arg;
  227. chan1 = tor_malloc_zero(sizeof(channel_t));
  228. chan2 = tor_malloc_zero(sizeof(channel_t));
  229. chan2->wide_circ_ids = 1;
  230. chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
  231. tt_int_op(0, ==, get_unique_circ_id_by_chan(chan1));
  232. /* Basic tests, with no collisions */
  233. chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  234. for (i = 0; i < 50; ++i) {
  235. circid = get_unique_circ_id_by_chan(chan1);
  236. tt_uint_op(0, <, circid);
  237. tt_uint_op(circid, <, (1<<15));
  238. }
  239. chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
  240. for (i = 0; i < 50; ++i) {
  241. circid = get_unique_circ_id_by_chan(chan1);
  242. tt_uint_op((1<<15), <, circid);
  243. tt_uint_op(circid, <, (1<<16));
  244. }
  245. chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  246. for (i = 0; i < 50; ++i) {
  247. circid = get_unique_circ_id_by_chan(chan2);
  248. tt_uint_op(0, <, circid);
  249. tt_uint_op(circid, <, (1u<<31));
  250. }
  251. chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
  252. for (i = 0; i < 50; ++i) {
  253. circid = get_unique_circ_id_by_chan(chan2);
  254. tt_uint_op((1u<<31), <, circid);
  255. }
  256. /* Now make sure that we can behave well when we are full up on circuits */
  257. chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  258. chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  259. chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
  260. ba = bitarray_init_zero((1<<15));
  261. for (i = 0; i < (1<<15); ++i) {
  262. circid = get_unique_circ_id_by_chan(chan1);
  263. if (circid == 0) {
  264. tt_int_op(i, >, (1<<14));
  265. break;
  266. }
  267. tt_uint_op(circid, <, (1<<15));
  268. tt_assert(! bitarray_is_set(ba, circid));
  269. bitarray_set(ba, circid);
  270. channel_mark_circid_unusable(chan1, circid);
  271. }
  272. tt_int_op(i, <, (1<<15));
  273. /* Make sure that being full on chan1 does not interfere with chan2 */
  274. for (i = 0; i < 100; ++i) {
  275. circid = get_unique_circ_id_by_chan(chan2);
  276. tt_uint_op(circid, >, 0);
  277. tt_uint_op(circid, <, (1<<15));
  278. channel_mark_circid_unusable(chan2, circid);
  279. }
  280. done:
  281. tor_free(chan1);
  282. tor_free(chan2);
  283. bitarray_free(ba);
  284. circuit_free_all();
  285. }
  286. struct testcase_t circuitlist_tests[] = {
  287. { "maps", test_clist_maps, TT_FORK, NULL, NULL },
  288. { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
  289. { "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
  290. END_OF_TESTCASES
  291. };