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