Tor  0.4.3.0-alpha-dev
circuitmux.c
Go to the documentation of this file.
1 /* * Copyright (c) 2012-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file circuitmux.c
6  * \brief Circuit mux/cell selection abstraction
7  *
8  * A circuitmux is responsible for <b>MU</b>ltiple<b>X</b>ing all of the
9  * circuits that are writing on a single channel. It keeps track of which of
10  * these circuits has something to write (aka, "active" circuits), and which
11  * one should write next. A circuitmux corresponds 1:1 with a channel.
12  *
13  * There can be different implementations of the circuitmux's rules (which
14  * decide which circuit is next to write).
15  *
16  * A circuitmux exposes three distinct
17  * interfaces to other components:
18  *
19  * To channels, which each have a circuitmux_t, the supported operations
20  * (invoked from relay.c) are:
21  *
22  * circuitmux_get_first_active_circuit():
23  *
24  * Pick one of the circuitmux's active circuits to send cells from.
25  *
26  * circuitmux_notify_xmit_cells():
27  *
28  * Notify the circuitmux that cells have been sent on a circuit.
29  *
30  * To circuits, the exposed operations are:
31  *
32  * circuitmux_attach_circuit():
33  *
34  * Attach a circuit to the circuitmux; this will allocate any policy-
35  * specific data wanted for this circuit and add it to the active
36  * circuits list if it has queued cells.
37  *
38  * circuitmux_detach_circuit():
39  *
40  * Detach a circuit from the circuitmux, freeing associated structures.
41  *
42  * circuitmux_clear_num_cells():
43  *
44  * Clear the circuitmux's cell counter for this circuit.
45  *
46  * circuitmux_set_num_cells():
47  *
48  * Set the circuitmux's cell counter for this circuit. One of
49  * circuitmuc_clear_num_cells() or circuitmux_set_num_cells() MUST be
50  * called when the number of cells queued on a circuit changes.
51  *
52  * See circuitmux.h for the circuitmux_policy_t data structure, which contains
53  * a table of function pointers implementing a circuit selection policy, and
54  * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux
55  * policies can be manipulated with:
56  *
57  * circuitmux_get_policy():
58  *
59  * Return the current policy for a circuitmux_t, if any.
60  *
61  * circuitmux_clear_policy():
62  *
63  * Remove a policy installed on a circuitmux_t, freeing all associated
64  * data. The circuitmux will revert to the built-in round-robin behavior.
65  *
66  * circuitmux_set_policy():
67  *
68  * Install a policy on a circuitmux_t; the appropriate callbacks will be
69  * made to attach all existing circuits to the new policy.
70  **/
71 
72 #define CIRCUITMUX_PRIVATE
73 
74 #include "core/or/or.h"
75 #include "core/or/channel.h"
76 #include "core/or/circuitlist.h"
77 #include "core/or/circuitmux.h"
78 #include "core/or/relay.h"
79 
80 #include "core/or/or_circuit_st.h"
81 
82 /*
83  * Private typedefs for circuitmux.c
84  */
85 
86 /*
87  * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
88  * break the hash table code).
89  */
91 
92 /*
93  * Anything the mux wants to store per-circuit in the map; right now just
94  * a count of queued cells.
95  */
96 
97 typedef struct circuit_muxinfo_s circuit_muxinfo_t;
98 
99 /*
100  * This struct holds whatever we want to store per attached circuit on a
101  * circuitmux_t; right now, just the count of queued cells and the direction.
102  */
103 
105  /* Count of cells on this circuit at last update */
106  unsigned int cell_count;
107  /* Direction of flow */
108  cell_direction_t direction;
109  /* Policy-specific data */
110  circuitmux_policy_circ_data_t *policy_data;
111  /* Mark bit for consistency checker */
112  unsigned int mark:1;
113 };
114 
115 /*
116  * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
117  * circuit.
118  */
119 
121  HT_ENTRY(chanid_circid_muxinfo_t) node;
122  uint64_t chan_id;
123  circid_t circ_id;
124  circuit_muxinfo_t muxinfo;
125 };
126 
127 /*
128  * Static function declarations
129  */
130 
131 static inline int
134 static inline unsigned int
137 circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
138 static void
139 circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ);
140 static void
141 circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ);
142 
143 /* Static global variables */
144 
145 /** Count the destroy balance to debug destroy queue logic */
146 static int64_t global_destroy_ctr = 0;
147 
148 /* Function definitions */
149 
150 /**
151  * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
152  * ID and circuit ID for a and b, and return less than, equal to, or greater
153  * than zero appropriately.
154  */
155 
156 static inline int
159 {
160  return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
161 }
162 
163 /**
164  * Helper: return a hash based on circuit ID and channel ID in a.
165  */
166 
167 static inline unsigned int
169 {
170  return (((unsigned int)(a->circ_id) << 8) ^
171  ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
172  ((unsigned int)(a->chan_id & 0xffffffff)));
173 }
174 
175 /* Emit a bunch of hash table stuff */
176 HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
178 HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
181 
182 /*
183  * Circuitmux alloc/free functions
184  */
185 
186 /**
187  * Allocate a new circuitmux_t
188  */
189 
190 circuitmux_t *
191 circuitmux_alloc(void)
192 {
193  circuitmux_t *rv = NULL;
194 
195  rv = tor_malloc_zero(sizeof(*rv));
196  rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
197  HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
198  destroy_cell_queue_init(&rv->destroy_cell_queue);
199 
200  return rv;
201 }
202 
203 /**
204  * Detach all circuits from a circuitmux (use before circuitmux_free())
205  *
206  * If <b>detached_out</b> is non-NULL, add every detached circuit_t to
207  * detached_out.
208  */
209 
210 void
211 circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
212 {
213  chanid_circid_muxinfo_t **i = NULL, *to_remove;
214  channel_t *chan = NULL;
215  circuit_t *circ = NULL;
216 
217  tor_assert(cmux);
218 
219  i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
220  while (i) {
221  to_remove = *i;
222 
223  if (! to_remove) {
224  log_warn(LD_BUG, "Somehow, an HT iterator gave us a NULL pointer.");
225  break;
226  } else {
227  /* Find a channel and circuit */
228  chan = channel_find_by_global_id(to_remove->chan_id);
229  if (chan) {
230  circ =
232  chan);
233  if (circ) {
234  /* Clear the circuit's mux for this direction */
235  if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
236  /*
237  * Update active_circuits et al.; this does policy notifies, so
238  * comes before freeing policy data
239  */
240 
241  if (to_remove->muxinfo.cell_count > 0) {
243  }
244 
245  if (detached_out)
246  smartlist_add(detached_out, circ);
247  } else if (circ->magic == OR_CIRCUIT_MAGIC) {
248  /*
249  * Update active_circuits et al.; this does policy notifies, so
250  * comes before freeing policy data
251  */
252 
253  if (to_remove->muxinfo.cell_count > 0) {
255  }
256 
257  if (detached_out)
258  smartlist_add(detached_out, circ);
259  } else {
260  /* Complain and move on */
261  log_warn(LD_CIRC,
262  "Circuit %u/channel %"PRIu64 " had direction == "
263  "CELL_DIRECTION_IN, but isn't an or_circuit_t",
264  (unsigned)to_remove->circ_id,
265  (to_remove->chan_id));
266  }
267 
268  /* Free policy-specific data if we have it */
269  if (to_remove->muxinfo.policy_data) {
270  /*
271  * If we have policy data, assert that we have the means to
272  * free it
273  */
274  tor_assert(cmux->policy);
275  tor_assert(cmux->policy->free_circ_data);
276  /* Call free_circ_data() */
277  cmux->policy->free_circ_data(cmux,
278  cmux->policy_data,
279  circ,
280  to_remove->muxinfo.policy_data);
281  to_remove->muxinfo.policy_data = NULL;
282  }
283  } else {
284  /* Complain and move on */
285  log_warn(LD_CIRC,
286  "Couldn't find circuit %u (for channel %"PRIu64 ")",
287  (unsigned)to_remove->circ_id,
288  (to_remove->chan_id));
289  }
290  } else {
291  /* Complain and move on */
292  log_warn(LD_CIRC,
293  "Couldn't find channel %"PRIu64 " (for circuit id %u)",
294  (to_remove->chan_id),
295  (unsigned)to_remove->circ_id);
296  }
297 
298  /* Assert that we don't have un-freed policy data for this circuit */
299  tor_assert(to_remove->muxinfo.policy_data == NULL);
300  }
301 
302  i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
303 
304  /* Free it */
305  tor_free(to_remove);
306  }
307 
308  cmux->n_circuits = 0;
309  cmux->n_active_circuits = 0;
310  cmux->n_cells = 0;
311 }
312 
313 /** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because
314  * of pending destroy cells in <b>cmux</b>.
315  *
316  * This function must be called AFTER circuits are unlinked from the (channel,
317  * circuid-id) map with circuit_unlink_all_from_channel(), but before calling
318  * circuitmux_free().
319  */
320 void
321 circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
322 {
323  destroy_cell_t *cell;
324  TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
325  channel_mark_circid_usable(chan, cell->circid);
326  }
327 }
328 
329 /**
330  * Free a circuitmux_t; the circuits must be detached first with
331  * circuitmux_detach_all_circuits().
332  */
333 
334 void
335 circuitmux_free_(circuitmux_t *cmux)
336 {
337  if (!cmux) return;
338 
339  tor_assert(cmux->n_circuits == 0);
340  tor_assert(cmux->n_active_circuits == 0);
341 
342  /*
343  * Free policy-specific data if we have any; we don't
344  * need to do circuitmux_set_policy(cmux, NULL) to cover
345  * the circuits because they would have been handled in
346  * circuitmux_detach_all_circuits() before this was
347  * called.
348  */
349  if (cmux->policy && cmux->policy->free_cmux_data) {
350  if (cmux->policy_data) {
351  cmux->policy->free_cmux_data(cmux, cmux->policy_data);
352  cmux->policy_data = NULL;
353  }
354  } else tor_assert(cmux->policy_data == NULL);
355 
356  if (cmux->chanid_circid_map) {
357  HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
358  tor_free(cmux->chanid_circid_map);
359  }
360 
361  /*
362  * We're throwing away some destroys; log the counter and
363  * adjust the global counter by the queue size.
364  */
365  if (cmux->destroy_cell_queue.n > 0) {
366  cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
367  global_destroy_ctr -= cmux->destroy_cell_queue.n;
368  log_debug(LD_CIRC,
369  "Freeing cmux at %p with %u queued destroys; the last cmux "
370  "destroy balance was %"PRId64", global is %"PRId64,
371  cmux, cmux->destroy_cell_queue.n,
372  (cmux->destroy_ctr),
374  } else {
375  log_debug(LD_CIRC,
376  "Freeing cmux at %p with no queued destroys, the cmux destroy "
377  "balance was %"PRId64", global is %"PRId64,
378  cmux,
379  (cmux->destroy_ctr),
381  }
382 
383  destroy_cell_queue_clear(&cmux->destroy_cell_queue);
384 
385  tor_free(cmux);
386 }
387 
388 /*
389  * Circuitmux policy control functions
390  */
391 
392 /**
393  * Remove any policy installed on cmux; all policy data will be freed and
394  * cmux behavior will revert to the built-in round-robin active_circuits
395  * mechanism.
396  */
397 
398 void
399 circuitmux_clear_policy(circuitmux_t *cmux)
400 {
401  tor_assert(cmux);
402 
403  /* Internally, this is just setting policy to NULL */
404  circuitmux_set_policy(cmux, NULL);
405 }
406 
407 /**
408  * Return the policy currently installed on a circuitmux_t
409  */
410 
411 MOCK_IMPL(const circuitmux_policy_t *,
412 circuitmux_get_policy, (circuitmux_t *cmux))
413 {
414  tor_assert(cmux);
415 
416  return cmux->policy;
417 }
418 
419 /**
420  * Set policy; allocate for new policy, detach all circuits from old policy
421  * if any, attach them to new policy, and free old policy data.
422  */
423 
424 void
425 circuitmux_set_policy(circuitmux_t *cmux,
426  const circuitmux_policy_t *pol)
427 {
428  const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL;
429  circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL;
430  chanid_circid_muxinfo_t **i = NULL;
431  channel_t *chan = NULL;
432  uint64_t last_chan_id_searched = 0;
433  circuit_t *circ = NULL;
434 
435  tor_assert(cmux);
436 
437  /* Set up variables */
438  old_pol = cmux->policy;
439  old_pol_data = cmux->policy_data;
440  new_pol = pol;
441 
442  /* Check if this is the trivial case */
443  if (old_pol == new_pol) return;
444 
445  /* Allocate data for new policy, if any */
446  if (new_pol && new_pol->alloc_cmux_data) {
447  /*
448  * If alloc_cmux_data is not null, then we expect to get some policy
449  * data. Assert that we also have free_cmux_data so we can free it
450  * when the time comes, and allocate it.
451  */
452  tor_assert(new_pol->free_cmux_data);
453  new_pol_data = new_pol->alloc_cmux_data(cmux);
454  tor_assert(new_pol_data);
455  }
456 
457  /* Install new policy and new policy data on cmux */
458  cmux->policy = new_pol;
459  cmux->policy_data = new_pol_data;
460 
461  /* Iterate over all circuits, attaching/detaching each one */
462  i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
463  while (i) {
464  /* Assert that this entry isn't NULL */
465  tor_assert(*i);
466 
467  /*
468  * Get the channel; since normal case is all circuits on the mux share a
469  * channel, we cache last_chan_id_searched
470  */
471  if (!chan || last_chan_id_searched != (*i)->chan_id) {
472  chan = channel_find_by_global_id((*i)->chan_id);
473  last_chan_id_searched = (*i)->chan_id;
474  }
475  tor_assert(chan);
476 
477  /* Get the circuit */
478  circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan);
479  tor_assert(circ);
480 
481  /* Need to tell old policy it becomes inactive (i.e., it is active) ? */
482  if (old_pol && old_pol->notify_circ_inactive &&
483  (*i)->muxinfo.cell_count > 0) {
484  old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
485  (*i)->muxinfo.policy_data);
486  }
487 
488  /* Need to free old policy data? */
489  if ((*i)->muxinfo.policy_data) {
490  /* Assert that we have the means to free it if we have policy data */
491  tor_assert(old_pol);
492  tor_assert(old_pol->free_circ_data);
493  /* Free it */
494  old_pol->free_circ_data(cmux, old_pol_data, circ,
495  (*i)->muxinfo.policy_data);
496  (*i)->muxinfo.policy_data = NULL;
497  }
498 
499  /* Need to allocate new policy data? */
500  if (new_pol && new_pol->alloc_circ_data) {
501  /*
502  * If alloc_circ_data is not null, we expect to get some per-circuit
503  * policy data. Assert that we also have free_circ_data so we can
504  * free it when the time comes, and allocate it.
505  */
506  tor_assert(new_pol->free_circ_data);
507  (*i)->muxinfo.policy_data =
508  new_pol->alloc_circ_data(cmux, new_pol_data, circ,
509  (*i)->muxinfo.direction,
510  (*i)->muxinfo.cell_count);
511  }
512 
513  /* Need to make active on new policy? */
514  if (new_pol && new_pol->notify_circ_active &&
515  (*i)->muxinfo.cell_count > 0) {
516  new_pol->notify_circ_active(cmux, new_pol_data, circ,
517  (*i)->muxinfo.policy_data);
518  }
519 
520  /* Advance to next circuit map entry */
521  i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
522  }
523 
524  /* Free data for old policy, if any */
525  if (old_pol_data) {
526  /*
527  * If we had old policy data, we should have an old policy and a free
528  * function for it.
529  */
530  tor_assert(old_pol);
531  tor_assert(old_pol->free_cmux_data);
532  old_pol->free_cmux_data(cmux, old_pol_data);
533  old_pol_data = NULL;
534  }
535 }
536 
537 /*
538  * Circuitmux/circuit attachment status inquiry functions
539  */
540 
541 /**
542  * Query the direction of an attached circuit
543  */
544 
547 {
548  chanid_circid_muxinfo_t *hashent = NULL;
549 
550  /* Try to find a map entry */
551  hashent = circuitmux_find_map_entry(cmux, circ);
552 
553  /*
554  * This function should only be called on attached circuits; assert that
555  * we had a map entry.
556  */
557  tor_assert(hashent);
558 
559  /* Return the direction from the map entry */
560  return hashent->muxinfo.direction;
561 }
562 
563 /**
564  * Find an entry in the cmux's map for this circuit or return NULL if there
565  * is none.
566  */
567 
569 circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
570 {
571  chanid_circid_muxinfo_t search, *hashent = NULL;
572 
573  /* Sanity-check parameters */
574  tor_assert(cmux);
575  tor_assert(cmux->chanid_circid_map);
576  tor_assert(circ);
577 
578  /* Check if we have n_chan */
579  if (circ->n_chan) {
580  /* Okay, let's see if it's attached for n_chan/n_circ_id */
581  search.chan_id = circ->n_chan->global_identifier;
582  search.circ_id = circ->n_circ_id;
583 
584  /* Query */
585  hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
586  &search);
587  }
588 
589  /* Found something? */
590  if (hashent) {
591  /*
592  * Assert that the direction makes sense for a hashent we found by
593  * n_chan/n_circ_id before we return it.
594  */
595  tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
596  } else {
597  /* Not there, have we got a p_chan/p_circ_id to try? */
598  if (circ->magic == OR_CIRCUIT_MAGIC) {
599  search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
600  /* Check for p_chan */
601  if (TO_OR_CIRCUIT(circ)->p_chan) {
602  search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
603  /* Okay, search for that */
604  hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
605  &search);
606  /* Find anything? */
607  if (hashent) {
608  /* Assert that the direction makes sense before we return it */
609  tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
610  }
611  }
612  }
613  }
614 
615  /* Okay, hashent is it if it was there */
616  return hashent;
617 }
618 
619 /**
620  * Query whether a circuit is attached to a circuitmux
621  */
622 
623 int
624 circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
625 {
626  chanid_circid_muxinfo_t *hashent = NULL;
627 
628  /* Look if it's in the circuit map */
629  hashent = circuitmux_find_map_entry(cmux, circ);
630 
631  return (hashent != NULL);
632 }
633 
634 /**
635  * Query whether a circuit is active on a circuitmux
636  */
637 
638 int
639 circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
640 {
641  chanid_circid_muxinfo_t *hashent = NULL;
642  int is_active = 0;
643 
644  tor_assert(cmux);
645  tor_assert(circ);
646 
647  /* Look if it's in the circuit map */
648  hashent = circuitmux_find_map_entry(cmux, circ);
649  if (hashent) {
650  /* Check the number of cells on this circuit */
651  is_active = (hashent->muxinfo.cell_count > 0);
652  }
653  /* else not attached, so not active */
654 
655  return is_active;
656 }
657 
658 /**
659  * Query number of available cells for a circuit on a circuitmux
660  */
661 
662 unsigned int
663 circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
664 {
665  chanid_circid_muxinfo_t *hashent = NULL;
666  unsigned int n_cells = 0;
667 
668  tor_assert(cmux);
669  tor_assert(circ);
670 
671  /* Look if it's in the circuit map */
672  hashent = circuitmux_find_map_entry(cmux, circ);
673  if (hashent) {
674  /* Just get the cell count for this circuit */
675  n_cells = hashent->muxinfo.cell_count;
676  }
677  /* else not attached, so 0 cells */
678 
679  return n_cells;
680 }
681 
682 /**
683  * Query total number of available cells on a circuitmux
684  */
685 
686 MOCK_IMPL(unsigned int,
687 circuitmux_num_cells, (circuitmux_t *cmux))
688 {
689  tor_assert(cmux);
690 
691  return cmux->n_cells + cmux->destroy_cell_queue.n;
692 }
693 
694 /**
695  * Query total number of circuits active on a circuitmux
696  */
697 
698 unsigned int
700 {
701  tor_assert(cmux);
702 
703  return cmux->n_active_circuits;
704 }
705 
706 /**
707  * Query total number of circuits attached to a circuitmux
708  */
709 
710 unsigned int
711 circuitmux_num_circuits(circuitmux_t *cmux)
712 {
713  tor_assert(cmux);
714 
715  return cmux->n_circuits;
716 }
717 
718 /*
719  * Functions for circuit code to call to update circuit status
720  */
721 
722 /**
723  * Attach a circuit to a circuitmux, for the specified direction.
724  */
725 
726 MOCK_IMPL(void,
727 circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
728  cell_direction_t direction))
729 {
730  channel_t *chan = NULL;
731  uint64_t channel_id;
732  circid_t circ_id;
733  chanid_circid_muxinfo_t search, *hashent = NULL;
734  unsigned int cell_count;
735 
736  tor_assert(cmux);
737  tor_assert(circ);
738  tor_assert(direction == CELL_DIRECTION_IN ||
739  direction == CELL_DIRECTION_OUT);
740 
741  /*
742  * Figure out which channel we're using, and get the circuit's current
743  * cell count and circuit ID; assert that the circuit is not already
744  * attached to another mux.
745  */
746  if (direction == CELL_DIRECTION_OUT) {
747  /* It's n_chan */
748  chan = circ->n_chan;
749  cell_count = circ->n_chan_cells.n;
750  circ_id = circ->n_circ_id;
751  } else {
752  /* We want p_chan */
753  chan = TO_OR_CIRCUIT(circ)->p_chan;
754  cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
755  circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
756  }
757  /* Assert that we did get a channel */
758  tor_assert(chan);
759  /* Assert that the circuit ID is sensible */
760  tor_assert(circ_id != 0);
761 
762  /* Get the channel ID */
763  channel_id = chan->global_identifier;
764 
765  /* See if we already have this one */
766  search.chan_id = channel_id;
767  search.circ_id = circ_id;
768  hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
769  &search);
770 
771  if (hashent) {
772  /*
773  * This circuit was already attached to this cmux; make sure the
774  * directions match and update the cell count and active circuit count.
775  */
776  log_info(LD_CIRC,
777  "Circuit %u on channel %"PRIu64 " was already attached to "
778  "(trying to attach to %p)",
779  (unsigned)circ_id, (channel_id),
780  cmux);
781 
782  /*
783  * The mux pointer on this circuit and the direction in result should
784  * match; otherwise assert.
785  */
786  tor_assert(hashent->muxinfo.direction == direction);
787 
788  /*
789  * Looks okay; just update the cell count and active circuits if we must
790  */
791  if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
792  --(cmux->n_active_circuits);
794  } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
795  ++(cmux->n_active_circuits);
796  circuitmux_make_circuit_active(cmux, circ);
797  }
798  cmux->n_cells -= hashent->muxinfo.cell_count;
799  cmux->n_cells += cell_count;
800  hashent->muxinfo.cell_count = cell_count;
801  } else {
802  /*
803  * New circuit; add an entry and update the circuit/active circuit
804  * counts.
805  */
806  log_debug(LD_CIRC,
807  "Attaching circuit %u on channel %"PRIu64 " to cmux %p",
808  (unsigned)circ_id, (channel_id), cmux);
809 
810  /* Insert it in the map */
811  hashent = tor_malloc_zero(sizeof(*hashent));
812  hashent->chan_id = channel_id;
813  hashent->circ_id = circ_id;
814  hashent->muxinfo.cell_count = cell_count;
815  hashent->muxinfo.direction = direction;
816  /* Allocate policy specific circuit data if we need it */
817  if (cmux->policy->alloc_circ_data) {
818  /* Assert that we have the means to free policy-specific data */
819  tor_assert(cmux->policy->free_circ_data);
820  /* Allocate it */
821  hashent->muxinfo.policy_data =
822  cmux->policy->alloc_circ_data(cmux,
823  cmux->policy_data,
824  circ,
825  direction,
826  cell_count);
827  /* If we wanted policy data, it's an error not to get any */
828  tor_assert(hashent->muxinfo.policy_data);
829  }
830  HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
831  hashent);
832 
833  /* Update counters */
834  ++(cmux->n_circuits);
835  if (cell_count > 0) {
836  ++(cmux->n_active_circuits);
837  circuitmux_make_circuit_active(cmux, circ);
838  }
839  cmux->n_cells += cell_count;
840  }
841 }
842 
843 /**
844  * Detach a circuit from a circuitmux and update all counters as needed;
845  * no-op if not attached.
846  */
847 
848 MOCK_IMPL(void,
849 circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
850 {
851  chanid_circid_muxinfo_t search, *hashent = NULL;
852  /*
853  * Use this to keep track of whether we found it for n_chan or
854  * p_chan for consistency checking.
855  *
856  * The 0 initializer is not a valid cell_direction_t value.
857  * We assert that it has been replaced with a valid value before it is used.
858  */
859  cell_direction_t last_searched_direction = 0;
860 
861  tor_assert(cmux);
862  tor_assert(cmux->chanid_circid_map);
863  tor_assert(circ);
864 
865  /* See if we have it for n_chan/n_circ_id */
866  if (circ->n_chan) {
867  search.chan_id = circ->n_chan->global_identifier;
868  search.circ_id = circ->n_circ_id;
869  hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
870  &search);
871  last_searched_direction = CELL_DIRECTION_OUT;
872  }
873 
874  /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
875  if (!hashent) {
876  if (circ->magic == OR_CIRCUIT_MAGIC) {
877  search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
878  if (TO_OR_CIRCUIT(circ)->p_chan) {
879  search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
880  hashent = HT_FIND(chanid_circid_muxinfo_map,
881  cmux->chanid_circid_map,
882  &search);
883  last_searched_direction = CELL_DIRECTION_IN;
884  }
885  }
886  }
887 
888  tor_assert(last_searched_direction == CELL_DIRECTION_OUT
889  || last_searched_direction == CELL_DIRECTION_IN);
890 
891  /*
892  * If hashent isn't NULL, we have a circuit to detach; don't remove it from
893  * the map until later of circuitmux_make_circuit_inactive() breaks.
894  */
895  if (hashent) {
896  /* Update counters */
897  --(cmux->n_circuits);
898  if (hashent->muxinfo.cell_count > 0) {
899  --(cmux->n_active_circuits);
900  /* This does policy notifies, so comes before freeing policy data */
902  }
903  cmux->n_cells -= hashent->muxinfo.cell_count;
904 
905  /* Free policy-specific data if we have it */
906  if (hashent->muxinfo.policy_data) {
907  /* If we have policy data, assert that we have the means to free it */
908  tor_assert(cmux->policy);
909  tor_assert(cmux->policy->free_circ_data);
910  /* Call free_circ_data() */
911  cmux->policy->free_circ_data(cmux,
912  cmux->policy_data,
913  circ,
914  hashent->muxinfo.policy_data);
915  hashent->muxinfo.policy_data = NULL;
916  }
917 
918  /* Consistency check: the direction must match the direction searched */
919  tor_assert(last_searched_direction == hashent->muxinfo.direction);
920 
921  /* Now remove it from the map */
922  HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
923 
924  /* Free the hash entry */
925  tor_free(hashent);
926  }
927 }
928 
929 /**
930  * Make a circuit active; update active list and policy-specific info, but
931  * we don't mess with the counters or hash table here.
932  */
933 
934 static void
935 circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
936 {
937  tor_assert(cmux);
938  tor_assert(cmux->policy);
939  tor_assert(circ);
940 
941  /* Policy-specific notification */
942  if (cmux->policy->notify_circ_active) {
943  /* Okay, we need to check the circuit for policy data now */
944  chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
945  /* We should have found something */
946  tor_assert(hashent);
947  /* Notify */
948  cmux->policy->notify_circ_active(cmux, cmux->policy_data,
949  circ, hashent->muxinfo.policy_data);
950  }
951 }
952 
953 /**
954  * Make a circuit inactive; update active list and policy-specific info, but
955  * we don't mess with the counters or hash table here.
956  */
957 
958 static void
959 circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
960 {
961  tor_assert(cmux);
962  tor_assert(cmux->policy);
963  tor_assert(circ);
964 
965  /* Policy-specific notification */
966  if (cmux->policy->notify_circ_inactive) {
967  /* Okay, we need to check the circuit for policy data now */
968  chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
969  /* We should have found something */
970  tor_assert(hashent);
971  /* Notify */
972  cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
973  circ, hashent->muxinfo.policy_data);
974  }
975 }
976 
977 /**
978  * Clear the cell counter for a circuit on a circuitmux
979  */
980 
981 void
982 circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
983 {
984  /* This is the same as setting the cell count to zero */
985  circuitmux_set_num_cells(cmux, circ, 0);
986 }
987 
988 /**
989  * Set the cell counter for a circuit on a circuitmux
990  */
991 
992 void
993 circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
994  unsigned int n_cells)
995 {
996  chanid_circid_muxinfo_t *hashent = NULL;
997 
998  tor_assert(cmux);
999  tor_assert(circ);
1000 
1001  /* Search for this circuit's entry */
1002  hashent = circuitmux_find_map_entry(cmux, circ);
1003  /* Assert that we found one */
1004  tor_assert(hashent);
1005 
1006  /* Update cmux cell counter */
1007  cmux->n_cells -= hashent->muxinfo.cell_count;
1008  cmux->n_cells += n_cells;
1009 
1010  /* Do we need to notify a cmux policy? */
1011  if (cmux->policy->notify_set_n_cells) {
1012  /* Call notify_set_n_cells */
1013  cmux->policy->notify_set_n_cells(cmux,
1014  cmux->policy_data,
1015  circ,
1016  hashent->muxinfo.policy_data,
1017  n_cells);
1018  }
1019 
1020  /*
1021  * Update cmux active circuit counter: is the old cell count > 0 and the
1022  * new cell count == 0 ?
1023  */
1024  if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
1025  --(cmux->n_active_circuits);
1026  hashent->muxinfo.cell_count = n_cells;
1028  /* Is the old cell count == 0 and the new cell count > 0 ? */
1029  } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
1030  ++(cmux->n_active_circuits);
1031  hashent->muxinfo.cell_count = n_cells;
1032  circuitmux_make_circuit_active(cmux, circ);
1033  } else {
1034  hashent->muxinfo.cell_count = n_cells;
1035  }
1036 }
1037 
1038 /*
1039  * Functions for channel code to call to get a circuit to transmit from or
1040  * notify that cells have been transmitted.
1041  */
1042 
1043 /**
1044  * Pick a circuit to send from, using the active circuits list or a
1045  * circuitmux policy if one is available. This is called from channel.c.
1046  *
1047  * If we would rather send a destroy cell, return NULL and set
1048  * *<b>destroy_queue_out</b> to the destroy queue.
1049  *
1050  * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and
1051  * return NULL.
1052  */
1053 
1054 circuit_t *
1056  destroy_cell_queue_t **destroy_queue_out)
1057 {
1058  circuit_t *circ = NULL;
1059 
1060  tor_assert(cmux);
1061  tor_assert(cmux->policy);
1062  /* This callback is mandatory. */
1063  tor_assert(cmux->policy->pick_active_circuit);
1064  tor_assert(destroy_queue_out);
1065 
1066  *destroy_queue_out = NULL;
1067 
1068  if (cmux->destroy_cell_queue.n &&
1069  (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) {
1070  /* We have destroy cells to send, and either we just sent a relay cell,
1071  * or we have no relay cells to send. */
1072 
1073  /* XXXX We should let the cmux policy have some say in this eventually. */
1074  /* XXXX Alternating is not a terribly brilliant approach here. */
1075  *destroy_queue_out = &cmux->destroy_cell_queue;
1076 
1077  cmux->last_cell_was_destroy = 1;
1078  } else if (cmux->n_active_circuits > 0) {
1079  /* We also must have a cell available for this to be the case */
1080  tor_assert(cmux->n_cells > 0);
1081  /* Do we have a policy-provided circuit selector? */
1082  circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
1083  cmux->last_cell_was_destroy = 0;
1084  } else {
1085  tor_assert(cmux->n_cells == 0);
1086  tor_assert(cmux->destroy_cell_queue.n == 0);
1087  }
1088 
1089  return circ;
1090 }
1091 
1092 /**
1093  * Notify the circuitmux that cells have been sent on a circuit; this
1094  * is called from channel.c.
1095  */
1096 
1097 void
1098 circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
1099  unsigned int n_cells)
1100 {
1101  chanid_circid_muxinfo_t *hashent = NULL;
1102  int becomes_inactive = 0;
1103 
1104  tor_assert(cmux);
1105  tor_assert(circ);
1106 
1107  if (n_cells == 0) return;
1108 
1109  /*
1110  * To handle this, we have to:
1111  *
1112  * 1.) Adjust the circuit's cell counter in the cmux hash table
1113  * 2.) Move the circuit to the tail of the active_circuits linked list
1114  * for this cmux, or make the circuit inactive if the cell count
1115  * went to zero.
1116  * 3.) Call cmux->policy->notify_xmit_cells(), if any
1117  */
1118 
1119  /* Find the hash entry */
1120  hashent = circuitmux_find_map_entry(cmux, circ);
1121  /* Assert that we found one */
1122  tor_assert(hashent);
1123 
1124  /* Adjust the cell counter and assert that we had that many cells to send */
1125  tor_assert(n_cells <= hashent->muxinfo.cell_count);
1126  hashent->muxinfo.cell_count -= n_cells;
1127  /* Do we need to make the circuit inactive? */
1128  if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
1129  /* Adjust the mux cell counter */
1130  cmux->n_cells -= n_cells;
1131 
1132  /*
1133  * We call notify_xmit_cells() before making the circuit inactive if needed,
1134  * so the policy can always count on this coming in on an active circuit.
1135  */
1136  if (cmux->policy->notify_xmit_cells) {
1137  cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
1138  hashent->muxinfo.policy_data,
1139  n_cells);
1140  }
1141 
1142  /*
1143  * Now make the circuit inactive if needed; this will call the policy's
1144  * notify_circ_inactive() if present.
1145  */
1146  if (becomes_inactive) {
1147  --(cmux->n_active_circuits);
1149  }
1150 }
1151 
1152 /**
1153  * Notify the circuitmux that a destroy was sent, so we can update
1154  * the counter.
1155  */
1156 
1157 void
1159 {
1160  tor_assert(cmux);
1161 
1162  --(cmux->destroy_ctr);
1163  --(global_destroy_ctr);
1164  log_debug(LD_CIRC,
1165  "Cmux at %p sent a destroy, cmux counter is now %"PRId64", "
1166  "global counter is now %"PRId64,
1167  cmux,
1168  (cmux->destroy_ctr),
1169  (global_destroy_ctr));
1170 }
1171 
1172 /*DOCDOC */
1173 void
1174 circuitmux_append_destroy_cell(channel_t *chan,
1175  circuitmux_t *cmux,
1176  circid_t circ_id,
1177  uint8_t reason)
1178 {
1179  destroy_cell_queue_append(&cmux->destroy_cell_queue, circ_id, reason);
1180 
1181  /* Destroy entering the queue, update counters */
1182  ++(cmux->destroy_ctr);
1184  log_debug(LD_CIRC,
1185  "Cmux at %p queued a destroy for circ %u, cmux counter is now "
1186  "%"PRId64", global counter is now %"PRId64,
1187  cmux, circ_id,
1188  (cmux->destroy_ctr),
1189  (global_destroy_ctr));
1190 
1191  /* XXXX Duplicate code from append_cell_to_circuit_queue */
1192  if (!channel_has_queued_writes(chan)) {
1193  /* There is no data at all waiting to be sent on the outbuf. Add a
1194  * cell, so that we can notice when it gets flushed, flushed_some can
1195  * get called, and we can start putting more data onto the buffer then.
1196  */
1197  log_debug(LD_GENERAL, "Primed a buffer.");
1199  }
1200 }
1201 
1202 /*DOCDOC; for debugging 12184. This runs slowly. */
1203 int64_t
1204 circuitmux_count_queued_destroy_cells(const channel_t *chan,
1205  const circuitmux_t *cmux)
1206 {
1207  int64_t n_destroy_cells = cmux->destroy_ctr;
1208  int64_t destroy_queue_size = cmux->destroy_cell_queue.n;
1209 
1210  int64_t manual_total = 0;
1211  int64_t manual_total_in_map = 0;
1212  destroy_cell_t *cell;
1213 
1214  TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
1215  circid_t id;
1216  ++manual_total;
1217 
1218  id = cell->circid;
1219  if (circuit_id_in_use_on_channel(id, (channel_t*)chan))
1220  ++manual_total_in_map;
1221  }
1222 
1223  if (n_destroy_cells != destroy_queue_size ||
1224  n_destroy_cells != manual_total ||
1225  n_destroy_cells != manual_total_in_map) {
1226  log_warn(LD_BUG, " Discrepancy in counts for queued destroy cells on "
1227  "circuitmux. n=%"PRId64". queue_size=%"PRId64". "
1228  "manual_total=%"PRId64". manual_total_in_map=%"PRId64".",
1229  (n_destroy_cells),
1230  (destroy_queue_size),
1231  (manual_total),
1232  (manual_total_in_map));
1233  }
1234 
1235  return n_destroy_cells;
1236 }
1237 
1238 /**
1239  * Compare cmuxes to see which is more preferred; return < 0 if
1240  * cmux_1 has higher priority (i.e., cmux_1 < cmux_2 in the scheduler's
1241  * sort order), > 0 if cmux_2 has higher priority, or 0 if they are
1242  * equally preferred.
1243  *
1244  * If the cmuxes have different cmux policies or the policy does not
1245  * support the cmp_cmux method, return 0.
1246  */
1247 
1248 MOCK_IMPL(int,
1249 circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2))
1250 {
1251  const circuitmux_policy_t *policy;
1252 
1253  tor_assert(cmux_1);
1254  tor_assert(cmux_2);
1255 
1256  if (cmux_1 == cmux_2) {
1257  /* Equivalent because they're the same cmux */
1258  return 0;
1259  }
1260 
1261  if (cmux_1->policy && cmux_2->policy) {
1262  if (cmux_1->policy == cmux_2->policy) {
1263  policy = cmux_1->policy;
1264 
1265  if (policy->cmp_cmux) {
1266  /* Okay, we can compare! */
1267  return policy->cmp_cmux(cmux_1, cmux_1->policy_data,
1268  cmux_2, cmux_2->policy_data);
1269  } else {
1270  /*
1271  * Equivalent because the policy doesn't know how to compare between
1272  * muxes.
1273  */
1274  return 0;
1275  }
1276  } else {
1277  /* Equivalent because they have different policies */
1278  return 0;
1279  }
1280  } else {
1281  /* Equivalent because one or both are missing a policy */
1282  return 0;
1283  }
1284 }
1285 
HT_PROTOTYPE(HT_GENERATE2(chanid_circid_muxinfo_map, HT_GENERATE2(chanid_circid_muxinfo_t, HT_GENERATE2(node, HT_GENERATE2(chanid_circid_entry_hash, HT_GENERATE2(chanid_circid_entries_eq)
Definition: circuitmux.c:176
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:982
circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan)
Definition: circuitlist.c:1532
static int chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, chanid_circid_muxinfo_t *b)
Definition: circuitmux.c:157
channel_t * n_chan
Definition: circuit_st.h:68
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, cell_direction_t direction)
Definition: circuitmux.c:728
uint32_t magic
Definition: circuit_st.h:61
#define LD_GENERAL
Definition: log.h:62
int channel_flush_from_first_active_circuit(channel_t *chan, int max)
Definition: relay.c:2890
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:663
void smartlist_add(smartlist_t *sl, void *element)
int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
Definition: circuitlist.c:1546
cell_direction_t circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:546
#define tor_assert(expr)
Definition: util_bug.h:102
static chanid_circid_muxinfo_t * circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:569
channel_t * channel_find_by_global_id(uint64_t global_identifier)
Definition: channel.c:650
void circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
Definition: circuitmux.c:211
#define tor_free(p)
Definition: malloc.h:52
void circuitmux_free_(circuitmux_t *cmux)
Definition: circuitmux.c:335
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:849
cell_direction_t
Definition: or.h:482
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
Definition: circuitmux.c:993
static void circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:935
void destroy_cell_queue_append(destroy_cell_queue_t *queue, circid_t circid, uint8_t reason)
Definition: relay.c:2643
Header file for channel.c.
unsigned int circuitmux_num_cells(circuitmux_t *cmux)
Definition: circuitmux.c:687
#define LD_CIRC
Definition: log.h:82
cell_queue_t p_chan_cells
Definition: or_circuit_st.h:35
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
Definition: circuitmux.c:1158
static unsigned int chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
Definition: circuitmux.c:168
Master header file for Tor-specific functionality.
HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq, 0.6, tor_reallocarray, tor_free_) static void cdm_diff_free_(cdm_diff_t *diff)
Definition: consdiffmgr.c:222
void destroy_cell_queue_clear(destroy_cell_queue_t *queue)
Definition: relay.c:2617
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
Definition: circuitmux.c:1098
void circuitmux_set_policy(circuitmux_t *cmux, const circuitmux_policy_t *pol)
Definition: circuitmux.c:425
void channel_mark_circid_usable(channel_t *chan, circid_t id)
Definition: circuitlist.c:386
circid_t p_circ_id
Definition: or_circuit_st.h:33
void tor_free_(void *mem)
Definition: malloc.c:227
Header file for circuitlist.c.
int circuitmux_compare_muxes(circuitmux_t *cmux_1, circuitmux_t *cmux_2)
Definition: circuitmux.c:1249
void circuitmux_clear_policy(circuitmux_t *cmux)
Definition: circuitmux.c:399
channel_t * p_chan
Definition: or_circuit_st.h:37
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:639
Header file for relay.c.
Header file for circuitmux.c.
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
Definition: circuitmux.c:321
const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux)
Definition: circuitmux.c:412
uint32_t circid_t
Definition: or.h:608
unsigned int circuitmux_num_circuits(circuitmux_t *cmux)
Definition: circuitmux.c:711
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:154
void destroy_cell_queue_init(destroy_cell_queue_t *queue)
Definition: relay.c:2609
int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:624
circid_t n_circ_id
Definition: circuit_st.h:77
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, destroy_cell_queue_t **destroy_queue_out)
Definition: circuitmux.c:1055
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux)
Definition: circuitmux.c:699
static void circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:959
#define OR_CIRCUIT_MAGIC
Definition: circuit_st.h:31
cell_queue_t n_chan_cells
Definition: circuit_st.h:80
int channel_has_queued_writes(channel_t *chan)
Definition: channel.c:2880
static int64_t global_destroy_ctr
Definition: circuitmux.c:146
#define LD_BUG
Definition: log.h:86