circuitmux.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. /* * Copyright (c) 2012, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file circuitmux.c
  5. * \brief Circuit mux/cell selection abstraction
  6. **/
  7. #include "or.h"
  8. #include "channel.h"
  9. #include "circuitlist.h"
  10. #include "circuitmux.h"
  11. /*
  12. * Private typedefs for circuitmux.c
  13. */
  14. /*
  15. * Map of muxinfos for circuitmux_t to use; struct is defined below (name
  16. * of struct must match HT_HEAD line).
  17. */
  18. typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t;
  19. /*
  20. * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
  21. * break the hash table code).
  22. */
  23. typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;
  24. /*
  25. * Anything the mux wants to store per-circuit in the map; right now just
  26. * a count of queued cells.
  27. */
  28. typedef struct circuit_muxinfo_s circuit_muxinfo_t;
  29. /*
  30. * Structures for circuitmux.c
  31. */
  32. /*
  33. * A circuitmux is a collection of circuits; it tracks which subset
  34. * of the attached circuits are 'active' (i.e., have cells available
  35. * to transmit) and how many cells on each. It expoes three distinct
  36. * interfaces to other components:
  37. *
  38. * To channels, which each have a circuitmux_t, the supported operations
  39. * are:
  40. *
  41. * circuitmux_flush_cells():
  42. *
  43. * Retrieve a cell from one of the active circuits, chosen according to
  44. * the circuitmux_t's cell selection policy.
  45. *
  46. * circuitmux_unlink_all():
  47. *
  48. * The channel is closing down, all circuits must be detached.
  49. *
  50. * To circuits, the exposed operations are:
  51. *
  52. * TODO
  53. *
  54. * To circuit selection policies, the exposed operations are:
  55. *
  56. * TODO
  57. *
  58. * General status inquiries?
  59. *
  60. */
  61. struct circuitmux_s {
  62. /* Keep count of attached, active circuits */
  63. unsigned int n_circuits, n_active_circuits;
  64. /* Total number of queued cells on all circuits */
  65. unsigned int n_cells;
  66. /*
  67. * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
  68. */
  69. chanid_circid_muxinfo_map_t *chanid_circid_map;
  70. /*
  71. * Double-linked ring of circuits with queued cells waiting for room to
  72. * free up on this connection's outbuf. Every time we pull cells from
  73. * a circuit, we advance this pointer to the next circuit in the ring.
  74. */
  75. struct circuit_t *active_circuits_head, *active_circuits_tail;
  76. /*
  77. * Priority queue of cell_ewma_t for circuits with queued cells waiting
  78. * for room to free up on this connection's outbuf. Kept in heap order
  79. * according to EWMA.
  80. *
  81. * This is redundant with active_circuits; if we ever decide only to use
  82. * the cell_ewma algorithm for choosing circuits, we can remove
  83. * active_circuits.
  84. */
  85. smartlist_t *active_circuit_pqueue;
  86. /*
  87. * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
  88. * their ewma values rescaled.
  89. */
  90. unsigned int active_circuit_pqueue_last_recalibrated;
  91. };
  92. /*
  93. * This struct holds whatever we want to store per attached circuit on a
  94. * circuitmux_t; right now, just the count of queued cells and the direction.
  95. */
  96. struct circuit_muxinfo_s {
  97. /* Count of cells on this circuit at last update */
  98. unsigned int cell_count;
  99. /* Direction of flow */
  100. cell_direction_t direction;
  101. };
  102. /*
  103. * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
  104. * circuit.
  105. */
  106. struct chanid_circid_muxinfo_t {
  107. HT_ENTRY(chanid_circid_muxinfo_t) node;
  108. uint64_t chan_id;
  109. circid_t circ_id;
  110. circuit_muxinfo_t muxinfo;
  111. };
  112. /*
  113. * Static function declarations
  114. */
  115. static INLINE int
  116. chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
  117. chanid_circid_muxinfo_t *b);
  118. static INLINE unsigned int
  119. chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
  120. static chanid_circid_muxinfo_t *
  121. circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
  122. static void
  123. circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
  124. cell_direction_t direction);
  125. static void
  126. circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
  127. cell_direction_t direction);
  128. static INLINE circuit_t **
  129. circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
  130. static INLINE circuit_t **
  131. circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
  132. /* Function definitions */
  133. /**
  134. * Linked list helpers
  135. */
  136. static INLINE circuit_t **
  137. circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
  138. {
  139. tor_assert(cmux);
  140. tor_assert(circ);
  141. if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
  142. else {
  143. tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
  144. return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
  145. }
  146. }
  147. static INLINE circuit_t **
  148. circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
  149. {
  150. tor_assert(cmux);
  151. tor_assert(circ);
  152. if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
  153. else {
  154. tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
  155. return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
  156. }
  157. }
  158. /**
  159. * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
  160. * ID and circuit ID for a and b, and return less than, equal to, or greater
  161. * than zero appropriately.
  162. */
  163. static INLINE int
  164. chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
  165. chanid_circid_muxinfo_t *b)
  166. {
  167. return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
  168. }
  169. /**
  170. * Helper: return a hash based on circuit ID and channel ID in a.
  171. */
  172. static INLINE unsigned int
  173. chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
  174. {
  175. return (((unsigned int)(a->circ_id) << 8) ^
  176. ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
  177. ((unsigned int)(a->chan_id & 0xffffffff)));
  178. }
  179. /* Declare the struct chanid_circid_muxinfo_map type */
  180. HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
  181. /* Emit a bunch of hash table stuff */
  182. HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
  183. chanid_circid_entry_hash, chanid_circid_entries_eq);
  184. HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
  185. chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
  186. malloc, realloc, free);
  187. /*
  188. * Circuitmux alloc/free functions
  189. */
  190. /**
  191. * Allocate a new circuitmux_t
  192. */
  193. circuitmux_t *
  194. circuitmux_alloc(void)
  195. {
  196. circuitmux_t *rv = NULL;
  197. rv = tor_malloc_zero(sizeof(*rv));
  198. rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
  199. HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
  200. return rv;
  201. }
  202. /**
  203. * Detach all circuits from a circuitmux (use before circuitmux_free())
  204. */
  205. void
  206. circuitmux_detach_all_circuits(circuitmux_t *cmux)
  207. {
  208. chanid_circid_muxinfo_t **i = NULL, *to_remove;
  209. channel_t *chan = NULL;
  210. circuit_t *circ = NULL;
  211. tor_assert(cmux);
  212. i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
  213. while (i) {
  214. to_remove = *i;
  215. i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
  216. if (to_remove) {
  217. /* Find a channel and circuit */
  218. chan = channel_find_by_global_id(to_remove->chan_id);
  219. if (chan) {
  220. circ = circuit_get_by_circid_channel(to_remove->circ_id, chan);
  221. if (circ) {
  222. /* Clear the circuit's mux for this direction */
  223. if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
  224. /* Clear n_mux */
  225. circ->n_mux = NULL;
  226. /* Update active_circuits et al. */
  227. circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
  228. } else if (circ->magic == OR_CIRCUIT_MAGIC) {
  229. /*
  230. * It has a sensible p_chan and direction == CELL_DIRECTION_IN,
  231. * so clear p_mux.
  232. */
  233. TO_OR_CIRCUIT(circ)->p_mux = NULL;
  234. /* Update active_circuits et al. */
  235. circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
  236. } else {
  237. /* Complain and move on */
  238. log_warn(LD_CIRC,
  239. "Circuit %d/channel " U64_FORMAT " had direction == "
  240. "CELL_DIRECTION_IN, but isn't an or_circuit_t",
  241. to_remove->circ_id,
  242. U64_PRINTF_ARG(to_remove->chan_id));
  243. }
  244. } else {
  245. /* Complain and move on */
  246. log_warn(LD_CIRC,
  247. "Couldn't find circuit %d (for channel " U64_FORMAT ")",
  248. to_remove->circ_id,
  249. U64_PRINTF_ARG(to_remove->chan_id));
  250. }
  251. } else {
  252. /* Complain and move on */
  253. log_warn(LD_CIRC,
  254. "Couldn't find channel " U64_FORMAT " (for circuit id %d)",
  255. U64_PRINTF_ARG(to_remove->chan_id),
  256. to_remove->circ_id);
  257. }
  258. /* Free it */
  259. tor_free(to_remove);
  260. }
  261. }
  262. cmux->n_circuits = 0;
  263. cmux->n_active_circuits = 0;
  264. cmux->n_cells = 0;
  265. }
  266. /**
  267. * Free a circuitmux_t; the circuits must be detached first with
  268. * circuitmux_detach_all_circuits().
  269. */
  270. void
  271. circuitmux_free(circuitmux_t *cmux)
  272. {
  273. if (!cmux) return;
  274. tor_assert(cmux->n_circuits == 0);
  275. tor_assert(cmux->n_active_circuits == 0);
  276. smartlist_free(cmux->active_circuit_pqueue);
  277. if (cmux->chanid_circid_map) {
  278. HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
  279. tor_free(cmux->chanid_circid_map);
  280. }
  281. tor_free(cmux);
  282. }
  283. /*
  284. * Circuitmux/circuit attachment status inquiry functions
  285. */
  286. /**
  287. * Query the direction of an attached circuit
  288. */
  289. cell_direction_t
  290. circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
  291. {
  292. chanid_circid_muxinfo_t *hashent = NULL;
  293. /* Try to find a map entry */
  294. hashent = circuitmux_find_map_entry(cmux, circ);
  295. /*
  296. * This function should only be called on attached circuits; assert that
  297. * we had a map entry.
  298. */
  299. tor_assert(hashent);
  300. /* Return the direction from the map entry */
  301. return hashent->muxinfo.direction;
  302. }
  303. /**
  304. * Find an entry in the cmux's map for this circuit or return NULL if there
  305. * is none.
  306. */
  307. static chanid_circid_muxinfo_t *
  308. circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
  309. {
  310. chanid_circid_muxinfo_t search, *hashent = NULL;
  311. /* Sanity-check parameters */
  312. tor_assert(cmux);
  313. tor_assert(cmux->chanid_circid_map);
  314. tor_assert(circ);
  315. tor_assert(circ->n_chan);
  316. /* Okay, let's see if it's attached for n_chan/n_circ_id */
  317. search.chan_id = circ->n_chan->global_identifier;
  318. search.circ_id = circ->n_circ_id;
  319. /* Query */
  320. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  321. &search);
  322. /* Found something? */
  323. if (hashent) {
  324. /*
  325. * Assert that the direction makes sense for a hashent we found by
  326. * n_chan/n_circ_id before we return it.
  327. */
  328. tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
  329. } else {
  330. /* Not there, have we got a p_chan/p_circ_id to try? */
  331. if (circ->magic == OR_CIRCUIT_MAGIC) {
  332. search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  333. /* Check for p_chan */
  334. if (TO_OR_CIRCUIT(circ)->p_chan) {
  335. search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
  336. /* Okay, search for that */
  337. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  338. &search);
  339. /* Find anything? */
  340. if (hashent) {
  341. /* Assert that the direction makes sense before we return it */
  342. tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
  343. }
  344. }
  345. }
  346. }
  347. /* Okay, hashent is it if it was there */
  348. return hashent;
  349. }
  350. /**
  351. * Query whether a circuit is attached to a circuitmux
  352. */
  353. int
  354. circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
  355. {
  356. chanid_circid_muxinfo_t *hashent = NULL;
  357. /* Look if it's in the circuit map */
  358. hashent = circuitmux_find_map_entry(cmux, circ);
  359. return (hashent != NULL);
  360. }
  361. /**
  362. * Query whether a circuit is active on a circuitmux
  363. */
  364. int
  365. circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
  366. {
  367. chanid_circid_muxinfo_t *hashent = NULL;
  368. int is_active = 0;
  369. tor_assert(cmux);
  370. tor_assert(circ);
  371. /* Look if it's in the circuit map */
  372. hashent = circuitmux_find_map_entry(cmux, circ);
  373. if (hashent) {
  374. /* Check the number of cells on this circuit */
  375. is_active = (hashent->muxinfo.cell_count > 0);
  376. }
  377. /* else not attached, so not active */
  378. return is_active;
  379. }
  380. /**
  381. * Query number of available cells for a circuit on a circuitmux
  382. */
  383. unsigned int
  384. circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
  385. {
  386. chanid_circid_muxinfo_t *hashent = NULL;
  387. unsigned int n_cells = 0;
  388. tor_assert(cmux);
  389. tor_assert(circ);
  390. /* Look if it's in the circuit map */
  391. hashent = circuitmux_find_map_entry(cmux, circ);
  392. if (hashent) {
  393. /* Just get the cell count for this circuit */
  394. n_cells = hashent->muxinfo.cell_count;
  395. }
  396. /* else not attached, so 0 cells */
  397. return n_cells;
  398. }
  399. /**
  400. * Query total number of available cells on a circuitmux
  401. */
  402. unsigned int
  403. circuitmux_num_cells(circuitmux_t *cmux)
  404. {
  405. tor_assert(cmux);
  406. return cmux->n_cells;
  407. }
  408. /**
  409. * Query total number of circuits active on a circuitmux
  410. */
  411. unsigned int
  412. circuitmux_num_active_circuits(circuitmux_t *cmux)
  413. {
  414. tor_assert(cmux);
  415. return cmux->n_active_circuits;
  416. }
  417. /**
  418. * Query total number of circuits attached to a circuitmux
  419. */
  420. unsigned int
  421. circuitmux_num_circuits(circuitmux_t *cmux)
  422. {
  423. tor_assert(cmux);
  424. return cmux->n_circuits;
  425. }
  426. /*
  427. * Functions for circuit code to call to update circuit status
  428. */
  429. /**
  430. * Attach a circuit to a circuitmux, for the specified direction.
  431. */
  432. void
  433. circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
  434. cell_direction_t direction)
  435. {
  436. channel_t *chan = NULL;
  437. uint64_t channel_id;
  438. circid_t circ_id;
  439. chanid_circid_muxinfo_t search, *hashent = NULL;
  440. unsigned int cell_count;
  441. tor_assert(cmux);
  442. tor_assert(circ);
  443. tor_assert(direction == CELL_DIRECTION_IN ||
  444. direction == CELL_DIRECTION_OUT);
  445. /*
  446. * Figure out which channel we're using, and get the circuit's current
  447. * cell count and circuit ID; assert that the circuit is not already
  448. * attached to another mux.
  449. */
  450. if (direction == CELL_DIRECTION_OUT) {
  451. /* It's n_chan */
  452. chan = circ->n_chan;
  453. cell_count = circ->n_chan_cells.n;
  454. circ_id = circ->n_circ_id;
  455. } else {
  456. /* We want p_chan */
  457. chan = TO_OR_CIRCUIT(circ)->p_chan;
  458. cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
  459. circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  460. }
  461. /* Assert that we did get a channel */
  462. tor_assert(chan);
  463. /* Assert that the circuit ID is sensible */
  464. tor_assert(circ_id != 0);
  465. /* Get the channel ID */
  466. channel_id = chan->global_identifier;
  467. /* See if we already have this one */
  468. search.chan_id = channel_id;
  469. search.circ_id = circ_id;
  470. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  471. &search);
  472. if (hashent) {
  473. /*
  474. * This circuit was already attached to this cmux; make sure the
  475. * directions match and update the cell count and active circuit count.
  476. */
  477. log_info(LD_CIRC,
  478. "Circuit %u on channel " U64_FORMAT " was already attached to "
  479. "cmux %p (trying to attach to %p)",
  480. circ_id, U64_PRINTF_ARG(channel_id),
  481. ((direction == CELL_DIRECTION_OUT) ?
  482. circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux),
  483. cmux);
  484. /*
  485. * The mux pointer on this circuit and the direction in result should
  486. * match; otherwise assert.
  487. */
  488. if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux);
  489. else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
  490. tor_assert(hashent->muxinfo.direction == direction);
  491. /*
  492. * Looks okay; just update the cell count and active circuits if we must
  493. */
  494. if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
  495. --(cmux->n_active_circuits);
  496. circuitmux_make_circuit_inactive(cmux, circ, direction);
  497. } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
  498. ++(cmux->n_active_circuits);
  499. circuitmux_make_circuit_active(cmux, circ, direction);
  500. }
  501. cmux->n_cells -= hashent->muxinfo.cell_count;
  502. cmux->n_cells += cell_count;
  503. hashent->muxinfo.cell_count = cell_count;
  504. } else {
  505. /*
  506. * New circuit; add an entry and update the circuit/active circuit
  507. * counts.
  508. */
  509. log_debug(LD_CIRC,
  510. "Attaching circuit %u on channel " U64_FORMAT " to cmux %p",
  511. circ_id, U64_PRINTF_ARG(channel_id), cmux);
  512. /*
  513. * Assert that the circuit doesn't already have a mux for this
  514. * direction.
  515. */
  516. if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL);
  517. else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL);
  518. /* Insert it in the map */
  519. hashent = tor_malloc_zero(sizeof(*hashent));
  520. hashent->chan_id = channel_id;
  521. hashent->circ_id = circ_id;
  522. hashent->muxinfo.cell_count = cell_count;
  523. hashent->muxinfo.direction = direction;
  524. HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  525. hashent);
  526. /* Set the circuit's mux for this direction */
  527. if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
  528. else TO_OR_CIRCUIT(circ)->p_mux = cmux;
  529. /* Make sure the next/prev pointers are NULL */
  530. if (direction == CELL_DIRECTION_OUT) {
  531. circ->next_active_on_n_chan = NULL;
  532. circ->prev_active_on_n_chan = NULL;
  533. } else {
  534. TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
  535. TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
  536. }
  537. /* Update counters */
  538. ++(cmux->n_circuits);
  539. if (cell_count > 0) {
  540. ++(cmux->n_active_circuits);
  541. circuitmux_make_circuit_active(cmux, circ, direction);
  542. }
  543. cmux->n_cells += cell_count;
  544. }
  545. }
  546. /**
  547. * Detach a circuit from a circuitmux and update all counters as needed;
  548. * no-op if not attached.
  549. */
  550. void
  551. circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
  552. {
  553. chanid_circid_muxinfo_t search, *hashent = NULL;
  554. /*
  555. * Use this to keep track of whether we found it for n_chan or
  556. * p_chan for consistency checking.
  557. */
  558. cell_direction_t last_searched_direction;
  559. tor_assert(cmux);
  560. tor_assert(cmux->chanid_circid_map);
  561. tor_assert(circ);
  562. tor_assert(circ->n_chan);
  563. /* See if we have it for n_chan/n_circ_id */
  564. search.chan_id = circ->n_chan->global_identifier;
  565. search.circ_id = circ->n_circ_id;
  566. hashent = HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  567. &search);
  568. last_searched_direction = CELL_DIRECTION_OUT;
  569. /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
  570. if (!hashent) {
  571. if (circ->magic == OR_CIRCUIT_MAGIC) {
  572. search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  573. if (TO_OR_CIRCUIT(circ)->p_chan) {
  574. search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
  575. hashent = HT_REMOVE(chanid_circid_muxinfo_map,
  576. cmux->chanid_circid_map,
  577. &search);
  578. last_searched_direction = CELL_DIRECTION_IN;
  579. }
  580. }
  581. }
  582. /* If hashent isn't NULL, we just removed it from the map */
  583. if (hashent) {
  584. /* Update counters */
  585. --(cmux->n_circuits);
  586. if (hashent->muxinfo.cell_count > 0) {
  587. --(cmux->n_active_circuits);
  588. circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
  589. }
  590. cmux->n_cells -= hashent->muxinfo.cell_count;
  591. /* Consistency check: the direction must match the direction searched */
  592. tor_assert(last_searched_direction == hashent->muxinfo.direction);
  593. /* Clear the circuit's mux for this direction */
  594. if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL;
  595. else TO_OR_CIRCUIT(circ)->p_mux = NULL;
  596. /* Free the hash entry */
  597. tor_free(hashent);
  598. }
  599. }
  600. /**
  601. * Make a circuit active; update active list and policy-specific info, but
  602. * we don't mess with the counters or hash table here.
  603. */
  604. static void
  605. circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
  606. cell_direction_t direction)
  607. {
  608. circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
  609. circuitmux_t *circuit_cmux = NULL;
  610. channel_t *chan = NULL;
  611. circid_t circ_id;
  612. int already_active;
  613. tor_assert(cmux);
  614. tor_assert(circ);
  615. tor_assert(direction == CELL_DIRECTION_OUT ||
  616. direction == CELL_DIRECTION_IN);
  617. /* Get the right set of active list links for this direction */
  618. if (direction == CELL_DIRECTION_OUT) {
  619. next_active = &(circ->next_active_on_n_chan);
  620. prev_active = &(circ->prev_active_on_n_chan);
  621. circuit_cmux = circ->n_mux;
  622. chan = circ->n_chan;
  623. circ_id = circ->n_circ_id;
  624. } else {
  625. next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
  626. prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
  627. circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
  628. chan = TO_OR_CIRCUIT(circ)->p_chan;
  629. circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  630. }
  631. /* Assert that it is attached to this mux and a channel */
  632. tor_assert(cmux == circuit_cmux);
  633. tor_assert(chan != NULL);
  634. /*
  635. * Check if the circuit really was inactive; if it's active, at least one
  636. * of the next_active and prev_active pointers will not be NULL, or this
  637. * circuit will be either the head or tail of the list for this cmux.
  638. */
  639. already_active = (*prev_active != NULL || *next_active != NULL ||
  640. cmux->active_circuits_head == circ ||
  641. cmux->active_circuits_tail == circ);
  642. /* If we're already active, log a warning and finish */
  643. if (already_active) {
  644. log_warn(LD_CIRC,
  645. "Circuit %d on channel " U64_FORMAT " was already active",
  646. circ_id, U64_PRINTF_ARG(chan->global_identifier));
  647. return;
  648. }
  649. /*
  650. * This is going at the head of the list; if the old head is not NULL,
  651. * then its prev pointer should point to this.
  652. */
  653. *next_active = cmux->active_circuits_head; /* Next is old head */
  654. *prev_active = NULL; /* Prev is NULL (this will be the head) */
  655. if (cmux->active_circuits_head) {
  656. /* The list had an old head; update its prev pointer */
  657. next_prev =
  658. circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
  659. tor_assert(next_prev);
  660. *next_prev = circ;
  661. } else {
  662. /* The list was empty; this becomes the tail as well */
  663. cmux->active_circuits_tail = circ;
  664. }
  665. /* This becomes the new head of the list */
  666. cmux->active_circuits_head = circ;
  667. /* TODO policy-specific notifications */
  668. }
  669. /**
  670. * Make a circuit inactive; update active list and policy-specific info, but
  671. * we don't mess with the counters or hash table here.
  672. */
  673. static void
  674. circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
  675. cell_direction_t direction)
  676. {
  677. circuit_t **next_active = NULL, **prev_active = NULL;
  678. circuit_t **next_prev = NULL, **prev_next = NULL;
  679. circuitmux_t *circuit_cmux = NULL;
  680. channel_t *chan = NULL;
  681. circid_t circ_id;
  682. int already_inactive;
  683. tor_assert(cmux);
  684. tor_assert(circ);
  685. tor_assert(direction == CELL_DIRECTION_OUT ||
  686. direction == CELL_DIRECTION_IN);
  687. /* Get the right set of active list links for this direction */
  688. if (direction == CELL_DIRECTION_OUT) {
  689. next_active = &(circ->next_active_on_n_chan);
  690. prev_active = &(circ->prev_active_on_n_chan);
  691. circuit_cmux = circ->n_mux;
  692. chan = circ->n_chan;
  693. circ_id = circ->n_circ_id;
  694. } else {
  695. next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
  696. prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
  697. circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
  698. chan = TO_OR_CIRCUIT(circ)->p_chan;
  699. circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  700. }
  701. /* Assert that it is attached to this mux and a channel */
  702. tor_assert(cmux == circuit_cmux);
  703. tor_assert(chan != NULL);
  704. /*
  705. * Check if the circuit really was active; if it's inactive, the
  706. * next_active and prev_active pointers will be NULL and this circuit
  707. * will not be the head or tail of the list for this cmux.
  708. */
  709. already_inactive = (*prev_active == NULL && *next_active == NULL &&
  710. cmux->active_circuits_head != circ &&
  711. cmux->active_circuits_tail != circ);
  712. /* If we're already inactive, log a warning and finish */
  713. if (already_inactive) {
  714. log_warn(LD_CIRC,
  715. "Circuit %d on channel " U64_FORMAT " was already inactive",
  716. circ_id, U64_PRINTF_ARG(chan->global_identifier));
  717. return;
  718. }
  719. /* Remove from the list; first get next_prev and prev_next */
  720. if (*next_active) {
  721. /*
  722. * If there's a next circuit, its previous circuit becomes this
  723. * circuit's previous circuit.
  724. */
  725. next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
  726. } else {
  727. /* Else, the tail becomes this circuit's previous circuit */
  728. next_prev = &(cmux->active_circuits_tail);
  729. }
  730. /* Got next_prev, now prev_next */
  731. if (*prev_active) {
  732. /*
  733. * If there's a previous circuit, its next circuit becomes this circuit's
  734. * next circuit.
  735. */
  736. prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
  737. } else {
  738. /* Else, the head becomes this circuit's next circuit */
  739. prev_next = &(cmux->active_circuits_head);
  740. }
  741. /* Assert that we got sensible values for the next/prev pointers */
  742. tor_assert(next_prev != NULL);
  743. tor_assert(prev_next != NULL);
  744. /* Update the next/prev pointers - this removes circ from the list */
  745. *next_prev = *prev_active;
  746. *prev_next = *next_active;
  747. /* Now null out prev_active/next_active */
  748. *prev_active = NULL;
  749. *next_active = NULL;
  750. /* TODO policy-specific notifications */
  751. }
  752. /**
  753. * Clear the cell counter for a circuit on a circuitmux
  754. */
  755. void
  756. circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
  757. {
  758. /* This is the same as setting the cell count to zero */
  759. circuitmux_set_num_cells(cmux, circ, 0);
  760. }
  761. /**
  762. * Set the cell counter for a circuit on a circuitmux
  763. */
  764. void
  765. circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
  766. unsigned int n_cells)
  767. {
  768. chanid_circid_muxinfo_t *hashent = NULL;
  769. tor_assert(cmux);
  770. tor_assert(circ);
  771. /* Search for this circuit's entry */
  772. hashent = circuitmux_find_map_entry(cmux, circ);
  773. /* Assert that we found one */
  774. tor_assert(hashent);
  775. /* Update cmux cell counter */
  776. cmux->n_cells -= hashent->muxinfo.cell_count;
  777. cmux->n_cells += n_cells;
  778. /*
  779. * Update cmux active circuit counter: is the old cell count > 0 and the
  780. * new cell count == 0 ?
  781. */
  782. if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
  783. --(cmux->n_active_circuits);
  784. circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
  785. /* Is the old cell count == 0 and the new cell count > 0 ? */
  786. } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
  787. ++(cmux->n_active_circuits);
  788. circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
  789. }
  790. /* Update hash entry cell counter */
  791. hashent->muxinfo.cell_count = n_cells;
  792. }