LCOV - code coverage report
Current view: top level - core/or - circuitmux.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 382 395 96.7 %
Date: 2021-11-24 03:28:48 Functions: 39 40 97.5 %

          Line data    Source code
       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             : 
      82             : #include "lib/crypt_ops/crypto_util.h"
      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             :  */
      92             : typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;
      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             : 
      99             : typedef struct circuit_muxinfo_t circuit_muxinfo_t;
     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             : 
     106             : struct circuit_muxinfo_t {
     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             : 
     122             : struct chanid_circid_muxinfo_t {
     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
     134             : chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
     135             :                          chanid_circid_muxinfo_t *b);
     136             : static inline unsigned int
     137             : chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
     138             : static chanid_circid_muxinfo_t *
     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
     159         116 : chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
     160             :                          chanid_circid_muxinfo_t *b)
     161             : {
     162         116 :     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
     170         273 : chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
     171             : {
     172         273 :     return (((unsigned int)(a->circ_id) << 8) ^
     173         273 :             ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
     174         273 :             ((unsigned int)(a->chan_id & 0xffffffff)));
     175             : }
     176             : 
     177             : /* Emit a bunch of hash table stuff */
     178        1522 : HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
     179             :              chanid_circid_entry_hash, chanid_circid_entries_eq);
     180         214 : HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
     181             :              chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
     182             :              tor_reallocarray_, tor_free_);
     183             : 
     184             : /*
     185             :  * Circuitmux alloc/free functions
     186             :  */
     187             : 
     188             : /**
     189             :  * Allocate a new circuitmux_t
     190             :  */
     191             : 
     192             : circuitmux_t *
     193         200 : circuitmux_alloc(void)
     194             : {
     195         200 :   circuitmux_t *rv = NULL;
     196             : 
     197         200 :   rv = tor_malloc_zero(sizeof(*rv));
     198         200 :   rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
     199         200 :   HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
     200         200 :   destroy_cell_queue_init(&rv->destroy_cell_queue);
     201             : 
     202         200 :   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          61 : circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
     214             : {
     215          61 :   chanid_circid_muxinfo_t **i = NULL, *to_remove;
     216          61 :   channel_t *chan = NULL;
     217          61 :   circuit_t *circ = NULL;
     218             : 
     219          61 :   tor_assert(cmux);
     220             : 
     221          61 :   i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
     222          63 :   while (i) {
     223           2 :     to_remove = *i;
     224             : 
     225           2 :     if (! to_remove) {
     226           0 :       log_warn(LD_BUG, "Somehow, an HT iterator gave us a NULL pointer.");
     227           0 :       break;
     228             :     } else {
     229             :       /* Find a channel and circuit */
     230           2 :       chan = channel_find_by_global_id(to_remove->chan_id);
     231           2 :       if (chan) {
     232           2 :         circ =
     233           2 :           circuit_get_by_circid_channel_even_if_marked(to_remove->circ_id,
     234             :                                                        chan);
     235           2 :         if (circ) {
     236             :           /* Clear the circuit's mux for this direction */
     237           2 :           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           1 :             if (to_remove->muxinfo.cell_count > 0) {
     244           1 :               circuitmux_make_circuit_inactive(cmux, circ);
     245             :             }
     246             : 
     247           1 :             if (detached_out)
     248           0 :               smartlist_add(detached_out, circ);
     249           1 :           } 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           1 :             if (to_remove->muxinfo.cell_count > 0) {
     256           1 :               circuitmux_make_circuit_inactive(cmux, circ);
     257             :             }
     258             : 
     259           1 :             if (detached_out)
     260           1 :               smartlist_add(detached_out, circ);
     261             :           } else {
     262             :             /* Complain and move on */
     263           0 :             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           2 :           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           2 :             tor_assert(cmux->policy);
     277           2 :             tor_assert(cmux->policy->free_circ_data);
     278             :             /* Call free_circ_data() */
     279           2 :             cmux->policy->free_circ_data(cmux,
     280             :                                          cmux->policy_data,
     281             :                                          circ,
     282             :                                          to_remove->muxinfo.policy_data);
     283           2 :             to_remove->muxinfo.policy_data = NULL;
     284             :           }
     285             :         } else {
     286             :           /* Complain and move on */
     287           0 :           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           0 :         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           2 :       tor_assert(to_remove->muxinfo.policy_data == NULL);
     302             :     }
     303             : 
     304           2 :     i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
     305             : 
     306             :     /* Free it */
     307           2 :     tor_free(to_remove);
     308             :   }
     309             : 
     310          61 :   cmux->n_circuits = 0;
     311          61 :   cmux->n_active_circuits = 0;
     312          61 :   cmux->n_cells = 0;
     313          61 : }
     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
     323          21 : circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
     324             : {
     325          21 :   destroy_cell_t *cell;
     326          21 :   TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
     327           0 :     channel_mark_circid_usable(chan, cell->circid);
     328             :   }
     329          21 : }
     330             : 
     331             : /**
     332             :  * Free a circuitmux_t; the circuits must be detached first with
     333             :  * circuitmux_detach_all_circuits().
     334             :  */
     335             : 
     336             : void
     337         255 : circuitmux_free_(circuitmux_t *cmux)
     338             : {
     339         255 :   if (!cmux) return;
     340             : 
     341         199 :   tor_assert(cmux->n_circuits == 0);
     342         199 :   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         199 :   if (cmux->policy && cmux->policy->free_cmux_data) {
     352         163 :     if (cmux->policy_data) {
     353         163 :       cmux->policy->free_cmux_data(cmux, cmux->policy_data);
     354         163 :       cmux->policy_data = NULL;
     355             :     }
     356          36 :   } else tor_assert(cmux->policy_data == NULL);
     357             : 
     358         199 :   if (cmux->chanid_circid_map) {
     359         199 :     HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
     360         199 :     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         199 :   if (cmux->destroy_cell_queue.n > 0) {
     368           2 :     cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
     369           2 :     global_destroy_ctr -= cmux->destroy_cell_queue.n;
     370           2 :     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),
     375             :               (global_destroy_ctr));
     376             :   } else {
     377         197 :     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),
     382             :               (global_destroy_ctr));
     383             :   }
     384             : 
     385         199 :   destroy_cell_queue_clear(&cmux->destroy_cell_queue);
     386             : 
     387         199 :   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           2 : circuitmux_clear_policy(circuitmux_t *cmux)
     402             : {
     403           2 :   tor_assert(cmux);
     404             : 
     405             :   /* Internally, this is just setting policy to NULL */
     406           2 :   circuitmux_set_policy(cmux, NULL);
     407           2 : }
     408             : 
     409             : /**
     410             :  * Return the policy currently installed on a circuitmux_t
     411             :  */
     412             : 
     413          43 : MOCK_IMPL(const circuitmux_policy_t *,
     414             : circuitmux_get_policy, (circuitmux_t *cmux))
     415             : {
     416          43 :   tor_assert(cmux);
     417             : 
     418          43 :   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         215 : circuitmux_set_policy(circuitmux_t *cmux,
     428             :                       const circuitmux_policy_t *pol)
     429             : {
     430         215 :   const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL;
     431         215 :   circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL;
     432         215 :   chanid_circid_muxinfo_t **i = NULL;
     433         215 :   channel_t *chan = NULL;
     434         215 :   uint64_t last_chan_id_searched = 0;
     435         215 :   circuit_t *circ = NULL;
     436             : 
     437         215 :   tor_assert(cmux);
     438             : 
     439             :   /* Set up variables */
     440         215 :   old_pol = cmux->policy;
     441         215 :   old_pol_data = cmux->policy_data;
     442         215 :   new_pol = pol;
     443             : 
     444             :   /* Check if this is the trivial case */
     445         215 :   if (old_pol == new_pol) return;
     446             : 
     447             :   /* Allocate data for new policy, if any */
     448         213 :   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         188 :     tor_assert(new_pol->free_cmux_data);
     455         188 :     new_pol_data = new_pol->alloc_cmux_data(cmux);
     456         188 :     tor_assert(new_pol_data);
     457             :   }
     458             : 
     459             :   /* Install new policy and new policy data on cmux */
     460         213 :   cmux->policy = new_pol;
     461         213 :   cmux->policy_data = new_pol_data;
     462             : 
     463             :   /* Iterate over all circuits, attaching/detaching each one */
     464         213 :   i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
     465         215 :   while (i) {
     466             :     /* Assert that this entry isn't NULL */
     467           2 :     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           2 :     if (!chan || last_chan_id_searched != (*i)->chan_id) {
     474           2 :       chan = channel_find_by_global_id((*i)->chan_id);
     475           2 :       last_chan_id_searched = (*i)->chan_id;
     476             :     }
     477           2 :     tor_assert(chan);
     478             : 
     479             :     /* Get the circuit */
     480           2 :     circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan);
     481           2 :     tor_assert(circ);
     482             : 
     483             :     /* Need to tell old policy it becomes inactive (i.e., it is active) ? */
     484           2 :     if (old_pol && old_pol->notify_circ_inactive &&
     485           1 :         (*i)->muxinfo.cell_count > 0) {
     486           1 :       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           2 :     if ((*i)->muxinfo.policy_data) {
     492             :       /* Assert that we have the means to free it if we have policy data */
     493           1 :       tor_assert(old_pol);
     494           1 :       tor_assert(old_pol->free_circ_data);
     495             :       /* Free it */
     496           1 :       old_pol->free_circ_data(cmux, old_pol_data, circ,
     497             :                              (*i)->muxinfo.policy_data);
     498           1 :       (*i)->muxinfo.policy_data = NULL;
     499             :     }
     500             : 
     501             :     /* Need to allocate new policy data? */
     502           2 :     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           1 :       tor_assert(new_pol->free_circ_data);
     509           1 :       (*i)->muxinfo.policy_data =
     510           1 :         new_pol->alloc_circ_data(cmux, new_pol_data, circ,
     511             :                                  (*i)->muxinfo.direction,
     512           1 :                                  (*i)->muxinfo.cell_count);
     513             :     }
     514             : 
     515             :     /* Need to make active on new policy? */
     516           2 :     if (new_pol && new_pol->notify_circ_active &&
     517           1 :         (*i)->muxinfo.cell_count > 0) {
     518           1 :       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           2 :     i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
     524             :   }
     525             : 
     526             :   /* Free data for old policy, if any */
     527         213 :   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          25 :     tor_assert(old_pol);
     533          25 :     tor_assert(old_pol->free_cmux_data);
     534          25 :     old_pol->free_cmux_data(cmux, old_pol_data);
     535          25 :     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             : 
     547             : cell_direction_t
     548           7 : circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
     549             : {
     550           7 :   chanid_circid_muxinfo_t *hashent = NULL;
     551             : 
     552             :   /* Try to find a map entry */
     553           7 :   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           7 :   tor_assert(hashent);
     560             : 
     561             :   /* Return the direction from the map entry */
     562           7 :   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             : 
     570             : static chanid_circid_muxinfo_t *
     571          90 : circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
     572             : {
     573          90 :   chanid_circid_muxinfo_t search, *hashent = NULL;
     574             : 
     575             :   /* Sanity-check parameters */
     576          90 :   tor_assert(cmux);
     577          90 :   tor_assert(cmux->chanid_circid_map);
     578          90 :   tor_assert(circ);
     579             : 
     580             :   /* Check if we have n_chan */
     581          90 :   if (circ->n_chan) {
     582             :     /* Okay, let's see if it's attached for n_chan/n_circ_id */
     583          90 :     search.chan_id = circ->n_chan->global_identifier;
     584          90 :     search.circ_id = circ->n_circ_id;
     585             : 
     586             :     /* Query */
     587          90 :     hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
     588             :                       &search);
     589             :   }
     590             : 
     591             :   /* Found something? */
     592          90 :   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          35 :     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          55 :     if (circ->magic == OR_CIRCUIT_MAGIC) {
     601          55 :       search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
     602             :       /* Check for p_chan */
     603          55 :       if (TO_OR_CIRCUIT(circ)->p_chan) {
     604          55 :         search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
     605             :         /* Okay, search for that */
     606          55 :         hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
     607             :                           &search);
     608             :         /* Find anything? */
     609          55 :         if (hashent) {
     610             :           /* Assert that the direction makes sense before we return it */
     611          49 :           tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
     612             :         }
     613             :       }
     614             :     }
     615             :   }
     616             : 
     617             :   /* Okay, hashent is it if it was there */
     618          90 :   return hashent;
     619             : }
     620             : 
     621             : /**
     622             :  * Query whether a circuit is attached to a circuitmux
     623             :  */
     624             : 
     625             : int
     626          18 : circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
     627             : {
     628          18 :   chanid_circid_muxinfo_t *hashent = NULL;
     629             : 
     630             :   /* Look if it's in the circuit map */
     631          18 :   hashent = circuitmux_find_map_entry(cmux, circ);
     632             : 
     633          18 :   return (hashent != NULL);
     634             : }
     635             : 
     636             : /**
     637             :  * Query whether a circuit is active on a circuitmux
     638             :  */
     639             : 
     640             : int
     641          16 : circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
     642             : {
     643          16 :   chanid_circid_muxinfo_t *hashent = NULL;
     644          16 :   int is_active = 0;
     645             : 
     646          16 :   tor_assert(cmux);
     647          16 :   tor_assert(circ);
     648             : 
     649             :   /* Look if it's in the circuit map */
     650          16 :   hashent = circuitmux_find_map_entry(cmux, circ);
     651          16 :   if (hashent) {
     652             :     /* Check the number of cells on this circuit */
     653          14 :     is_active = (hashent->muxinfo.cell_count > 0);
     654             :   }
     655             :   /* else not attached, so not active */
     656             : 
     657          16 :   return is_active;
     658             : }
     659             : 
     660             : /**
     661             :  * Query number of available cells for a circuit on a circuitmux
     662             :  */
     663             : 
     664             : unsigned int
     665           7 : circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
     666             : {
     667           7 :   chanid_circid_muxinfo_t *hashent = NULL;
     668           7 :   unsigned int n_cells = 0;
     669             : 
     670           7 :   tor_assert(cmux);
     671           7 :   tor_assert(circ);
     672             : 
     673             :   /* Look if it's in the circuit map */
     674           7 :   hashent = circuitmux_find_map_entry(cmux, circ);
     675           7 :   if (hashent) {
     676             :     /* Just get the cell count for this circuit */
     677           7 :     n_cells = hashent->muxinfo.cell_count;
     678             :   }
     679             :   /* else not attached, so 0 cells */
     680             : 
     681           7 :   return n_cells;
     682             : }
     683             : 
     684             : /**
     685             :  * Query total number of available cells on a circuitmux
     686             :  */
     687             : 
     688         450 : MOCK_IMPL(unsigned int,
     689             : circuitmux_num_cells, (circuitmux_t *cmux))
     690             : {
     691         450 :   tor_assert(cmux);
     692             : 
     693         450 :   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
     701          10 : circuitmux_num_active_circuits(circuitmux_t *cmux)
     702             : {
     703          10 :   tor_assert(cmux);
     704             : 
     705          10 :   return cmux->n_active_circuits;
     706             : }
     707             : 
     708             : /**
     709             :  * Query total number of circuits attached to a circuitmux
     710             :  */
     711             : 
     712             : unsigned int
     713          12 : circuitmux_num_circuits(circuitmux_t *cmux)
     714             : {
     715          12 :   tor_assert(cmux);
     716             : 
     717          12 :   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          21 : MOCK_IMPL(void,
     729             : circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
     730             :                            cell_direction_t direction))
     731             : {
     732          21 :   channel_t *chan = NULL;
     733          21 :   uint64_t channel_id;
     734          21 :   circid_t circ_id;
     735          21 :   chanid_circid_muxinfo_t search, *hashent = NULL;
     736          21 :   unsigned int cell_count;
     737             : 
     738          21 :   tor_assert(cmux);
     739          21 :   tor_assert(circ);
     740          21 :   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          21 :   if (direction == CELL_DIRECTION_OUT) {
     749             :     /* It's n_chan */
     750          10 :     chan = circ->n_chan;
     751          10 :     cell_count = circ->n_chan_cells.n;
     752          10 :     circ_id = circ->n_circ_id;
     753             :   } else {
     754             :     /* We want p_chan */
     755          11 :     chan = TO_OR_CIRCUIT(circ)->p_chan;
     756          11 :     cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
     757          11 :     circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
     758             :   }
     759             :   /* Assert that we did get a channel */
     760          21 :   tor_assert(chan);
     761             :   /* Assert that the circuit ID is sensible */
     762          21 :   tor_assert(circ_id != 0);
     763             : 
     764             :   /* Get the channel ID */
     765          21 :   channel_id = chan->global_identifier;
     766             : 
     767             :   /* See if we already have this one */
     768          21 :   search.chan_id = channel_id;
     769          21 :   search.circ_id = circ_id;
     770          21 :   hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
     771             :                     &search);
     772             : 
     773          21 :   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           6 :     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           6 :     tor_assert(hashent->muxinfo.direction == direction);
     789             : 
     790             :     /*
     791             :      * Looks okay; just update the cell count and active circuits if we must
     792             :      */
     793           6 :     if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
     794           1 :       --(cmux->n_active_circuits);
     795           1 :       circuitmux_make_circuit_inactive(cmux, circ);
     796           5 :     } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
     797           1 :       ++(cmux->n_active_circuits);
     798           1 :       circuitmux_make_circuit_active(cmux, circ);
     799             :     }
     800           6 :     cmux->n_cells -= hashent->muxinfo.cell_count;
     801           6 :     cmux->n_cells += cell_count;
     802           6 :     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          15 :     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          15 :     hashent = tor_malloc_zero(sizeof(*hashent));
     814          15 :     hashent->chan_id = channel_id;
     815          15 :     hashent->circ_id = circ_id;
     816          15 :     hashent->muxinfo.cell_count = cell_count;
     817          15 :     hashent->muxinfo.direction = direction;
     818             :     /* Allocate policy specific circuit data if we need it */
     819          15 :     if (cmux->policy->alloc_circ_data) {
     820             :       /* Assert that we have the means to free policy-specific data */
     821          15 :       tor_assert(cmux->policy->free_circ_data);
     822             :       /* Allocate it */
     823          30 :       hashent->muxinfo.policy_data =
     824          15 :         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          15 :       tor_assert(hashent->muxinfo.policy_data);
     831             :     }
     832          15 :     HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
     833             :               hashent);
     834             : 
     835             :     /* Update counters */
     836          15 :     ++(cmux->n_circuits);
     837          15 :     if (cell_count > 0) {
     838           0 :       ++(cmux->n_active_circuits);
     839           0 :       circuitmux_make_circuit_active(cmux, circ);
     840             :     }
     841          15 :     cmux->n_cells += cell_count;
     842             :   }
     843          21 : }
     844             : 
     845             : /**
     846             :  * Detach a circuit from a circuitmux and update all counters as needed;
     847             :  * no-op if not attached.
     848             :  */
     849             : 
     850          43 : MOCK_IMPL(void,
     851             : circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
     852             : {
     853          43 :   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          43 :   cell_direction_t last_searched_direction = 0;
     862             : 
     863          43 :   tor_assert(cmux);
     864          43 :   tor_assert(cmux->chanid_circid_map);
     865          43 :   tor_assert(circ);
     866             : 
     867             :   /* See if we have it for n_chan/n_circ_id */
     868          43 :   if (circ->n_chan) {
     869          43 :     search.chan_id = circ->n_chan->global_identifier;
     870          43 :     search.circ_id = circ->n_circ_id;
     871          43 :     hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
     872             :                         &search);
     873          43 :     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          43 :   if (!hashent) {
     878          36 :     if (circ->magic == OR_CIRCUIT_MAGIC) {
     879          36 :       search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
     880          36 :       if (TO_OR_CIRCUIT(circ)->p_chan) {
     881          36 :         search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
     882          36 :         hashent = HT_FIND(chanid_circid_muxinfo_map,
     883             :                             cmux->chanid_circid_map,
     884             :                             &search);
     885          36 :         last_searched_direction = CELL_DIRECTION_IN;
     886             :       }
     887             :     }
     888             :   }
     889             : 
     890          43 :   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          43 :   if (hashent) {
     898             :     /* Update counters */
     899          13 :     --(cmux->n_circuits);
     900          13 :     if (hashent->muxinfo.cell_count > 0) {
     901           6 :       --(cmux->n_active_circuits);
     902             :       /* This does policy notifies, so comes before freeing policy data */
     903           6 :       circuitmux_make_circuit_inactive(cmux, circ);
     904             :     }
     905          13 :     cmux->n_cells -= hashent->muxinfo.cell_count;
     906             : 
     907             :     /* Free policy-specific data if we have it */
     908          13 :     if (hashent->muxinfo.policy_data) {
     909             :       /* If we have policy data, assert that we have the means to free it */
     910          13 :       tor_assert(cmux->policy);
     911          13 :       tor_assert(cmux->policy->free_circ_data);
     912             :       /* Call free_circ_data() */
     913          13 :       cmux->policy->free_circ_data(cmux,
     914             :                                    cmux->policy_data,
     915             :                                    circ,
     916             :                                    hashent->muxinfo.policy_data);
     917          13 :       hashent->muxinfo.policy_data = NULL;
     918             :     }
     919             : 
     920             :     /* Consistency check: the direction must match the direction searched */
     921          13 :     tor_assert(last_searched_direction == hashent->muxinfo.direction);
     922             : 
     923             :     /* Now remove it from the map */
     924          13 :     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          13 :     memwipe(hashent, 0xef, sizeof(*hashent));
     930          13 :     tor_free(hashent);
     931             :   }
     932          43 : }
     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          12 : circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
     941             : {
     942          12 :   tor_assert(cmux);
     943          12 :   tor_assert(cmux->policy);
     944          12 :   tor_assert(circ);
     945             : 
     946             :   /* Policy-specific notification */
     947          12 :   if (cmux->policy->notify_circ_active) {
     948             :     /* Okay, we need to check the circuit for policy data now */
     949          12 :     chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
     950             :     /* We should have found something */
     951          12 :     tor_assert(hashent);
     952             :     /* Notify */
     953          12 :     cmux->policy->notify_circ_active(cmux, cmux->policy_data,
     954             :                                      circ, hashent->muxinfo.policy_data);
     955             :   }
     956          12 : }
     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          12 : circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
     965             : {
     966          12 :   tor_assert(cmux);
     967          12 :   tor_assert(cmux->policy);
     968          12 :   tor_assert(circ);
     969             : 
     970             :   /* Policy-specific notification */
     971          12 :   if (cmux->policy->notify_circ_inactive) {
     972             :     /* Okay, we need to check the circuit for policy data now */
     973          12 :     chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
     974             :     /* We should have found something */
     975          12 :     tor_assert(hashent);
     976             :     /* Notify */
     977          12 :     cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
     978             :                                        circ, hashent->muxinfo.policy_data);
     979             :   }
     980          12 : }
     981             : 
     982             : /**
     983             :  * Clear the cell counter for a circuit on a circuitmux
     984             :  */
     985             : 
     986             : void
     987           1 : circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
     988             : {
     989             :   /* This is the same as setting the cell count to zero */
     990           1 :   circuitmux_set_num_cells(cmux, circ, 0);
     991           1 : }
     992             : 
     993             : /**
     994             :  * Set the cell counter for a circuit on a circuitmux
     995             :  */
     996             : 
     997             : void
     998          14 : circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
     999             :                          unsigned int n_cells)
    1000             : {
    1001          14 :   chanid_circid_muxinfo_t *hashent = NULL;
    1002             : 
    1003          14 :   tor_assert(cmux);
    1004          14 :   tor_assert(circ);
    1005             : 
    1006             :   /* Search for this circuit's entry */
    1007          14 :   hashent = circuitmux_find_map_entry(cmux, circ);
    1008             :   /* Assert that we found one */
    1009          14 :   tor_assert(hashent);
    1010             : 
    1011             :   /* Update cmux cell counter */
    1012          14 :   cmux->n_cells -= hashent->muxinfo.cell_count;
    1013          14 :   cmux->n_cells += n_cells;
    1014             : 
    1015             :   /* Do we need to notify a cmux policy? */
    1016          14 :   if (cmux->policy->notify_set_n_cells) {
    1017             :     /* Call notify_set_n_cells */
    1018           0 :     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          14 :   if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
    1030           1 :     --(cmux->n_active_circuits);
    1031           1 :     hashent->muxinfo.cell_count = n_cells;
    1032           1 :     circuitmux_make_circuit_inactive(cmux, circ);
    1033             :   /* Is the old cell count == 0 and the new cell count > 0 ? */
    1034          13 :   } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
    1035          11 :     ++(cmux->n_active_circuits);
    1036          11 :     hashent->muxinfo.cell_count = n_cells;
    1037          11 :     circuitmux_make_circuit_active(cmux, circ);
    1038             :   } else {
    1039           2 :     hashent->muxinfo.cell_count = n_cells;
    1040             :   }
    1041          14 : }
    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 *
    1060           4 : circuitmux_get_first_active_circuit(circuitmux_t *cmux,
    1061             :                                     destroy_cell_queue_t **destroy_queue_out)
    1062             : {
    1063           4 :   circuit_t *circ = NULL;
    1064             : 
    1065           4 :   tor_assert(cmux);
    1066           4 :   tor_assert(cmux->policy);
    1067             :   /* This callback is mandatory. */
    1068           4 :   tor_assert(cmux->policy->pick_active_circuit);
    1069           4 :   tor_assert(destroy_queue_out);
    1070             : 
    1071           4 :   *destroy_queue_out = NULL;
    1072             : 
    1073           4 :   if (cmux->destroy_cell_queue.n &&
    1074           1 :         (!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           1 :     *destroy_queue_out = &cmux->destroy_cell_queue;
    1081             : 
    1082           1 :     cmux->last_cell_was_destroy = 1;
    1083           3 :   } else if (cmux->n_active_circuits > 0) {
    1084             :     /* We also must have a cell available for this to be the case */
    1085           2 :     tor_assert(cmux->n_cells > 0);
    1086             :     /* Do we have a policy-provided circuit selector? */
    1087           2 :     circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
    1088           2 :     cmux->last_cell_was_destroy = 0;
    1089             :   } else {
    1090           1 :     tor_assert(cmux->n_cells == 0);
    1091           1 :     tor_assert(cmux->destroy_cell_queue.n == 0);
    1092             :   }
    1093             : 
    1094           4 :   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           4 : circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
    1104             :                              unsigned int n_cells)
    1105             : {
    1106           4 :   chanid_circid_muxinfo_t *hashent = NULL;
    1107           4 :   int becomes_inactive = 0;
    1108             : 
    1109           4 :   tor_assert(cmux);
    1110           4 :   tor_assert(circ);
    1111             : 
    1112           4 :   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           4 :   hashent = circuitmux_find_map_entry(cmux, circ);
    1126             :   /* Assert that we found one */
    1127           4 :   tor_assert(hashent);
    1128             : 
    1129             :   /* Adjust the cell counter and assert that we had that many cells to send */
    1130           4 :   tor_assert(n_cells <= hashent->muxinfo.cell_count);
    1131           4 :   hashent->muxinfo.cell_count -= n_cells;
    1132             :   /* Do we need to make the circuit inactive? */
    1133           4 :   if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
    1134             :   /* Adjust the mux cell counter */
    1135           4 :   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           4 :   if (cmux->policy->notify_xmit_cells) {
    1142           4 :     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           4 :   if (becomes_inactive) {
    1152           2 :     --(cmux->n_active_circuits);
    1153           2 :     circuitmux_make_circuit_inactive(cmux, circ);
    1154             :   }
    1155             : }
    1156             : 
    1157             : /**
    1158             :  * Notify the circuitmux that a destroy was sent, so we can update
    1159             :  * the counter.
    1160             :  */
    1161             : 
    1162             : void
    1163           1 : circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
    1164             : {
    1165           1 :   tor_assert(cmux);
    1166             : 
    1167           1 :   --(cmux->destroy_ctr);
    1168           1 :   --(global_destroy_ctr);
    1169           1 :   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           1 : }
    1176             : 
    1177             : /*DOCDOC */
    1178             : void
    1179           4 : circuitmux_append_destroy_cell(channel_t *chan,
    1180             :                                circuitmux_t *cmux,
    1181             :                                circid_t circ_id,
    1182             :                                uint8_t reason)
    1183             : {
    1184           4 :   destroy_cell_queue_append(&cmux->destroy_cell_queue, circ_id, reason);
    1185             : 
    1186             :   /* Destroy entering the queue, update counters */
    1187           4 :   ++(cmux->destroy_ctr);
    1188           4 :   ++global_destroy_ctr;
    1189           4 :   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           4 :   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           0 :     log_debug(LD_GENERAL, "Primed a buffer.");
    1203           0 :     channel_flush_from_first_active_circuit(chan, 1);
    1204             :   }
    1205           4 : }
    1206             : 
    1207             : /*DOCDOC; for debugging 12184.  This runs slowly. */
    1208             : int64_t
    1209           2 : circuitmux_count_queued_destroy_cells(const channel_t *chan,
    1210             :                                       const circuitmux_t *cmux)
    1211             : {
    1212           2 :   int64_t n_destroy_cells = cmux->destroy_ctr;
    1213           2 :   int64_t destroy_queue_size = cmux->destroy_cell_queue.n;
    1214             : 
    1215           2 :   int64_t manual_total = 0;
    1216           2 :   int64_t manual_total_in_map = 0;
    1217           2 :   destroy_cell_t *cell;
    1218             : 
    1219           3 :   TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
    1220           1 :     circid_t id;
    1221           1 :     ++manual_total;
    1222             : 
    1223           1 :     id = cell->circid;
    1224           1 :     if (circuit_id_in_use_on_channel(id, (channel_t*)chan))
    1225           1 :       ++manual_total_in_map;
    1226             :   }
    1227             : 
    1228           2 :   if (n_destroy_cells != destroy_queue_size ||
    1229           2 :       n_destroy_cells != manual_total ||
    1230             :       n_destroy_cells != manual_total_in_map) {
    1231           0 :     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           2 :   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          20 : MOCK_IMPL(int,
    1254             : circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2))
    1255             : {
    1256          20 :   const circuitmux_policy_t *policy;
    1257             : 
    1258          20 :   tor_assert(cmux_1);
    1259          20 :   tor_assert(cmux_2);
    1260             : 
    1261          20 :   if (cmux_1 == cmux_2) {
    1262             :     /* Equivalent because they're the same cmux */
    1263             :     return 0;
    1264             :   }
    1265             : 
    1266          20 :   if (cmux_1->policy && cmux_2->policy) {
    1267          20 :     if (cmux_1->policy == cmux_2->policy) {
    1268          20 :       policy = cmux_1->policy;
    1269             : 
    1270          20 :       if (policy->cmp_cmux) {
    1271             :         /* Okay, we can compare! */
    1272          20 :         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             : }

Generated by: LCOV version 1.14