circuitmux.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  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;
  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. /* Function definitions */
  123. /**
  124. * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
  125. * ID and circuit ID for a and b, and return less than, equal to, or greater
  126. * than zero appropriately.
  127. */
  128. static INLINE int
  129. chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
  130. chanid_circid_muxinfo_t *b)
  131. {
  132. return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
  133. }
  134. /**
  135. * Helper: return a hash based on circuit ID and channel ID in a.
  136. */
  137. static INLINE unsigned int
  138. chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
  139. {
  140. return (((unsigned int)(a->circ_id) << 8) ^
  141. ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
  142. ((unsigned int)(a->chan_id & 0xffffffff)));
  143. }
  144. /* Declare the struct chanid_circid_muxinfo_map type */
  145. HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
  146. /* Emit a bunch of hash table stuff */
  147. HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
  148. chanid_circid_entry_hash, chanid_circid_entries_eq);
  149. HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
  150. chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
  151. malloc, realloc, free);
  152. /*
  153. * Circuitmux alloc/free functions
  154. */
  155. /**
  156. * Allocate a new circuitmux_t
  157. */
  158. circuitmux_t *
  159. circuitmux_alloc(void)
  160. {
  161. circuitmux_t *rv = NULL;
  162. rv = tor_malloc_zero(sizeof(*rv));
  163. rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
  164. HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
  165. return rv;
  166. }
  167. /**
  168. * Detach all circuits from a circuitmux (use before circuitmux_free())
  169. */
  170. void
  171. circuitmux_detach_all_circuits(circuitmux_t *cmux)
  172. {
  173. chanid_circid_muxinfo_t **i = NULL, *to_remove;
  174. channel_t *chan = NULL;
  175. circuit_t *circ = NULL;
  176. tor_assert(cmux);
  177. i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
  178. while (i) {
  179. to_remove = *i;
  180. i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
  181. if (to_remove) {
  182. /* Find a channel and circuit */
  183. chan = channel_find_by_global_id(to_remove->chan_id);
  184. if (chan) {
  185. circ = circuit_get_by_circid_channel(to_remove->circ_id, chan);
  186. if (circ) {
  187. /* Clear the circuit's mux for this direction */
  188. if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
  189. /* Clear n_mux */
  190. circ->n_mux = NULL;
  191. } else if (circ->magic == OR_CIRCUIT_MAGIC) {
  192. /*
  193. * It has a sensible p_chan and direction == CELL_DIRECTION_IN,
  194. * so clear p_mux.
  195. */
  196. TO_OR_CIRCUIT(circ)->p_mux = NULL;
  197. } else {
  198. /* Complain and move on */
  199. log_warn(LD_CIRC,
  200. "Circuit %d/channel " U64_FORMAT " had direction == "
  201. "CELL_DIRECTION_IN, but isn't an or_circuit_t",
  202. to_remove->circ_id,
  203. U64_PRINTF_ARG(to_remove->chan_id));
  204. }
  205. /* TODO update active_circuits / active_circuit_pqueue */
  206. } else {
  207. /* Complain and move on */
  208. log_warn(LD_CIRC,
  209. "Couldn't find circuit %d (for channel " U64_FORMAT ")",
  210. to_remove->circ_id,
  211. U64_PRINTF_ARG(to_remove->chan_id));
  212. }
  213. } else {
  214. /* Complain and move on */
  215. log_warn(LD_CIRC,
  216. "Couldn't find channel " U64_FORMAT " (for circuit id %d)",
  217. U64_PRINTF_ARG(to_remove->chan_id),
  218. to_remove->circ_id);
  219. }
  220. /* Free it */
  221. tor_free(to_remove);
  222. }
  223. }
  224. cmux->n_circuits = 0;
  225. cmux->n_active_circuits = 0;
  226. cmux->n_cells = 0;
  227. }
  228. /**
  229. * Free a circuitmux_t; the circuits must be detached first with
  230. * circuitmux_detach_all_circuits().
  231. */
  232. void
  233. circuitmux_free(circuitmux_t *cmux)
  234. {
  235. if (!cmux) return;
  236. tor_assert(cmux->n_circuits == 0);
  237. tor_assert(cmux->n_active_circuits == 0);
  238. smartlist_free(cmux->active_circuit_pqueue);
  239. if (cmux->chanid_circid_map) {
  240. HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
  241. tor_free(cmux->chanid_circid_map);
  242. }
  243. tor_free(cmux);
  244. }
  245. /*
  246. * Circuitmux/circuit attachment status inquiry functions
  247. */
  248. /**
  249. * Query the direction of an attached circuit
  250. */
  251. cell_direction_t
  252. circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
  253. {
  254. chanid_circid_muxinfo_t *hashent = NULL;
  255. /* Try to find a map entry */
  256. hashent = circuitmux_find_map_entry(cmux, circ);
  257. /*
  258. * This function should only be called on attached circuits; assert that
  259. * we had a map entry.
  260. */
  261. tor_assert(hashent);
  262. /* Return the direction from the map entry */
  263. return hashent->muxinfo.direction;
  264. }
  265. /**
  266. * Find an entry in the cmux's map for this circuit or return NULL if there
  267. * is none.
  268. */
  269. static chanid_circid_muxinfo_t *
  270. circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
  271. {
  272. chanid_circid_muxinfo_t search, *hashent = NULL;
  273. /* Sanity-check parameters */
  274. tor_assert(cmux);
  275. tor_assert(cmux->chanid_circid_map);
  276. tor_assert(circ);
  277. tor_assert(circ->n_chan);
  278. /* Okay, let's see if it's attached for n_chan/n_circ_id */
  279. search.chan_id = circ->n_chan->global_identifier;
  280. search.circ_id = circ->n_circ_id;
  281. /* Query */
  282. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  283. &search);
  284. /* Found something? */
  285. if (hashent) {
  286. /*
  287. * Assert that the direction makes sense for a hashent we found by
  288. * n_chan/n_circ_id before we return it.
  289. */
  290. tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
  291. } else {
  292. /* Not there, have we got a p_chan/p_circ_id to try? */
  293. if (circ->magic == OR_CIRCUIT_MAGIC) {
  294. search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  295. /* Check for p_chan */
  296. if (TO_OR_CIRCUIT(circ)->p_chan) {
  297. search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
  298. /* Okay, search for that */
  299. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  300. &search);
  301. /* Find anything? */
  302. if (hashent) {
  303. /* Assert that the direction makes sense before we return it */
  304. tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
  305. }
  306. }
  307. }
  308. }
  309. /* Okay, hashent is it if it was there */
  310. return hashent;
  311. }
  312. /**
  313. * Query whether a circuit is attached to a circuitmux
  314. */
  315. int
  316. circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
  317. {
  318. chanid_circid_muxinfo_t *hashent = NULL;
  319. /* Look if it's in the circuit map */
  320. hashent = circuitmux_find_map_entry(cmux, circ);
  321. return (hashent != NULL);
  322. }
  323. /**
  324. * Query whether a circuit is active on a circuitmux
  325. */
  326. int
  327. circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
  328. {
  329. chanid_circid_muxinfo_t *hashent = NULL;
  330. int is_active = 0;
  331. tor_assert(cmux);
  332. tor_assert(circ);
  333. /* Look if it's in the circuit map */
  334. hashent = circuitmux_find_map_entry(cmux, circ);
  335. if (hashent) {
  336. /* Check the number of cells on this circuit */
  337. is_active = (hashent->muxinfo.cell_count > 0);
  338. }
  339. /* else not attached, so not active */
  340. return is_active;
  341. }
  342. /**
  343. * Query number of available cells for a circuit on a circuitmux
  344. */
  345. unsigned int
  346. circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
  347. {
  348. chanid_circid_muxinfo_t *hashent = NULL;
  349. unsigned int n_cells = 0;
  350. tor_assert(cmux);
  351. tor_assert(circ);
  352. /* Look if it's in the circuit map */
  353. hashent = circuitmux_find_map_entry(cmux, circ);
  354. if (hashent) {
  355. /* Just get the cell count for this circuit */
  356. n_cells = hashent->muxinfo.cell_count;
  357. }
  358. /* else not attached, so 0 cells */
  359. return n_cells;
  360. }
  361. /**
  362. * Query total number of available cells on a circuitmux
  363. */
  364. unsigned int
  365. circuitmux_num_cells(circuitmux_t *cmux)
  366. {
  367. tor_assert(cmux);
  368. return cmux->n_cells;
  369. }
  370. /**
  371. * Query total number of circuits active on a circuitmux
  372. */
  373. unsigned int
  374. circuitmux_num_active_circuits(circuitmux_t *cmux)
  375. {
  376. tor_assert(cmux);
  377. return cmux->n_active_circuits;
  378. }
  379. /**
  380. * Query total number of circuits attached to a circuitmux
  381. */
  382. unsigned int
  383. circuitmux_num_circuits(circuitmux_t *cmux)
  384. {
  385. tor_assert(cmux);
  386. return cmux->n_circuits;
  387. }
  388. /*
  389. * Functions for circuit code to call to update circuit status
  390. */
  391. /**
  392. * Attach a circuit to a circuitmux, for the specified direction.
  393. */
  394. void
  395. circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
  396. cell_direction_t direction)
  397. {
  398. channel_t *chan = NULL;
  399. uint64_t channel_id;
  400. circid_t circ_id;
  401. chanid_circid_muxinfo_t search, *hashent = NULL;
  402. unsigned int cell_count;
  403. tor_assert(cmux);
  404. tor_assert(circ);
  405. tor_assert(direction == CELL_DIRECTION_IN ||
  406. direction == CELL_DIRECTION_OUT);
  407. /*
  408. * Figure out which channel we're using, and get the circuit's current
  409. * cell count and circuit ID; assert that the circuit is not already
  410. * attached to another mux.
  411. */
  412. if (direction == CELL_DIRECTION_OUT) {
  413. /* It's n_chan */
  414. chan = circ->n_chan;
  415. cell_count = circ->n_chan_cells.n;
  416. circ_id = circ->n_circ_id;
  417. } else {
  418. /* We want p_chan */
  419. chan = TO_OR_CIRCUIT(circ)->p_chan;
  420. cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
  421. circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  422. }
  423. /* Assert that we did get a channel */
  424. tor_assert(chan);
  425. /* Assert that the circuit ID is sensible */
  426. tor_assert(circ_id != 0);
  427. /* Get the channel ID */
  428. channel_id = chan->global_identifier;
  429. /* See if we already have this one */
  430. search.chan_id = channel_id;
  431. search.circ_id = circ_id;
  432. hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  433. &search);
  434. if (hashent) {
  435. /*
  436. * This circuit was already attached to this cmux; make sure the
  437. * directions match and update the cell count and active circuit count.
  438. */
  439. log_info(LD_CIRC,
  440. "Circuit %u on channel " U64_FORMAT " was already attached to "
  441. "cmux %p (trying to attach to %p)",
  442. circ_id, U64_PRINTF_ARG(channel_id),
  443. ((direction == CELL_DIRECTION_OUT) ?
  444. circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux),
  445. cmux);
  446. /*
  447. * The mux pointer on this circuit and the direction in result should
  448. * match; otherwise assert.
  449. */
  450. if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux);
  451. else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
  452. tor_assert(hashent->muxinfo.direction == direction);
  453. /*
  454. * Looks okay; just update the cell count and active circuits if we must
  455. */
  456. if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
  457. --(cmux->n_active_circuits);
  458. } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
  459. ++(cmux->n_active_circuits);
  460. }
  461. cmux->n_cells -= hashent->muxinfo.cell_count;
  462. cmux->n_cells += cell_count;
  463. hashent->muxinfo.cell_count = cell_count;
  464. /* TODO update active_circuits / active_circuit_pqueue */
  465. } else {
  466. /*
  467. * New circuit; add an entry and update the circuit/active circuit
  468. * counts.
  469. */
  470. log_debug(LD_CIRC,
  471. "Attaching circuit %u on channel " U64_FORMAT " to cmux %p",
  472. circ_id, U64_PRINTF_ARG(channel_id), cmux);
  473. /*
  474. * Assert that the circuit doesn't already have a mux for this
  475. * direction.
  476. */
  477. if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL);
  478. else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL);
  479. /* Insert it in the map */
  480. hashent = tor_malloc_zero(sizeof(*hashent));
  481. hashent->chan_id = channel_id;
  482. hashent->circ_id = circ_id;
  483. hashent->muxinfo.cell_count = cell_count;
  484. hashent->muxinfo.direction = direction;
  485. HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  486. hashent);
  487. /* Set the circuit's mux for this direction */
  488. if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
  489. else TO_OR_CIRCUIT(circ)->p_mux = cmux;
  490. /* Make sure the next/prev pointers are NULL */
  491. if (direction == CELL_DIRECTION_OUT) {
  492. circ->next_active_on_n_chan = NULL;
  493. circ->prev_active_on_n_chan = NULL;
  494. } else {
  495. TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
  496. TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
  497. }
  498. /* Update counters */
  499. ++(cmux->n_circuits);
  500. if (cell_count > 0) {
  501. ++(cmux->n_active_circuits);
  502. circuitmux_make_circuit_active(cmux, circ, direction);
  503. }
  504. cmux->n_cells += cell_count;
  505. /* TODO update active_circuits / active_circuit_pqueue */
  506. }
  507. }
  508. /**
  509. * Detach a circuit from a circuitmux and update all counters as needed;
  510. * no-op if not attached.
  511. */
  512. void
  513. circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
  514. {
  515. chanid_circid_muxinfo_t search, *hashent = NULL;
  516. /*
  517. * Use this to keep track of whether we found it for n_chan or
  518. * p_chan for consistency checking.
  519. */
  520. cell_direction_t last_searched_direction;
  521. tor_assert(cmux);
  522. tor_assert(cmux->chanid_circid_map);
  523. tor_assert(circ);
  524. tor_assert(circ->n_chan);
  525. /* See if we have it for n_chan/n_circ_id */
  526. search.chan_id = circ->n_chan->global_identifier;
  527. search.circ_id = circ->n_circ_id;
  528. hashent = HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
  529. &search);
  530. last_searched_direction = CELL_DIRECTION_OUT;
  531. /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
  532. if (!hashent) {
  533. if (circ->magic == OR_CIRCUIT_MAGIC) {
  534. search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
  535. if (TO_OR_CIRCUIT(circ)->p_chan) {
  536. search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
  537. hashent = HT_REMOVE(chanid_circid_muxinfo_map,
  538. cmux->chanid_circid_map,
  539. &search);
  540. last_searched_direction = CELL_DIRECTION_IN;
  541. }
  542. }
  543. }
  544. /* If hashent isn't NULL, we just removed it from the map */
  545. if (hashent) {
  546. /* Update counters */
  547. --(cmux->n_circuits);
  548. if (hashent->muxinfo.cell_count > 0) --(cmux->n_active_circuits);
  549. cmux->n_cells -= hashent->muxinfo.cell_count;
  550. /* TODO update active_circuits / active_circuit_pqueue */
  551. /* Consistency check: the direction must match the direction searched */
  552. tor_assert(last_searched_direction == hashent->muxinfo.direction);
  553. /* Clear the circuit's mux for this direction */
  554. if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL;
  555. else TO_OR_CIRCUIT(circ)->p_mux = NULL;
  556. /* Free the hash entry */
  557. tor_free(hashent);
  558. }
  559. }
  560. /**
  561. * Clear the cell counter for a circuit on a circuitmux
  562. */
  563. void
  564. circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
  565. {
  566. /* This is the same as setting the cell count to zero */
  567. circuitmux_set_num_cells(cmux, circ, 0);
  568. }
  569. /**
  570. * Set the cell counter for a circuit on a circuitmux
  571. */
  572. void
  573. circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
  574. unsigned int n_cells)
  575. {
  576. chanid_circid_muxinfo_t *hashent = NULL;
  577. tor_assert(cmux);
  578. tor_assert(circ);
  579. /* Search for this circuit's entry */
  580. hashent = circuitmux_find_map_entry(cmux, circ);
  581. /* Assert that we found one */
  582. tor_assert(hashent);
  583. /* Update cmux cell counter */
  584. cmux->n_cells -= hashent->muxinfo.cell_count;
  585. cmux->n_cells += n_cells;
  586. /*
  587. * Update cmux active circuit counter: is the old cell count > 0 and the
  588. * new cell count == 0 ?
  589. */
  590. if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
  591. --(cmux->n_active_circuits);
  592. /* TODO update active_circuits / active_circuit_pqueue */
  593. /* Is the old cell count == 0 and the new cell count > 0 ? */
  594. } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
  595. ++(cmux->n_active_circuits);
  596. /* TODO update active_circuits / active_circuit_pqueue */
  597. }
  598. /* Update hash entry cell counter */
  599. hashent->muxinfo.cell_count = n_cells;
  600. }