tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

btrack_orconn_maps.c (5607B)


      1 /* Copyright (c) 2007-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file btrack_orconn_maps.c
      6 * \brief Hash map implementation for btrack_orconn.c
      7 *
      8 * These functions manipulate the hash maps that contain bt_orconn
      9 * objects.
     10 **/
     11 
     12 #include <stdbool.h>
     13 
     14 #include "core/or/or.h"
     15 
     16 #include "ht.h"
     17 #include "siphash.h"
     18 
     19 #define BTRACK_ORCONN_PRIVATE
     20 
     21 #include "feature/control/btrack_orconn.h"
     22 #include "feature/control/btrack_orconn_maps.h"
     23 #include "lib/log/log.h"
     24 
     25 static inline unsigned int
     26 bto_gid_hash_(bt_orconn_t *elm)
     27 {
     28  return (unsigned)siphash24g(&elm->gid, sizeof(elm->gid));
     29 }
     30 
     31 static inline int
     32 bto_gid_eq_(bt_orconn_t *a, bt_orconn_t *b)
     33 {
     34  return a->gid == b->gid;
     35 }
     36 
     37 static inline unsigned int
     38 bto_chan_hash_(bt_orconn_t *elm)
     39 {
     40  return (unsigned)siphash24g(&elm->chan, sizeof(elm->chan));
     41 }
     42 
     43 static inline int
     44 bto_chan_eq_(bt_orconn_t *a, bt_orconn_t *b)
     45 {
     46  return a->chan == b->chan;
     47 }
     48 
     49 HT_HEAD(bto_gid_ht, bt_orconn_t);
     50 HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_);
     51 HT_GENERATE2(bto_gid_ht, bt_orconn_t, node,
     52             bto_gid_hash_, bto_gid_eq_, 0.6,
     53             tor_reallocarray_, tor_free_);
     54 static struct bto_gid_ht *bto_gid_map;
     55 
     56 HT_HEAD(bto_chan_ht, bt_orconn_t);
     57 HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_,
     58             bto_chan_eq_);
     59 HT_GENERATE2(bto_chan_ht, bt_orconn_t, chan_node,
     60             bto_chan_hash_, bto_chan_eq_, 0.6,
     61             tor_reallocarray_, tor_free_);
     62 static struct bto_chan_ht *bto_chan_map;
     63 
     64 /** Clear the GID hash map, freeing any bt_orconn_t objects that become
     65 * unreferenced */
     66 static void
     67 bto_gid_clear_map(void)
     68 {
     69  bt_orconn_t **elt, **next, *c;
     70 
     71  for (elt = HT_START(bto_gid_ht, bto_gid_map);
     72       elt;
     73       elt = next) {
     74    c = *elt;
     75    next = HT_NEXT_RMV(bto_gid_ht, bto_gid_map, elt);
     76 
     77    c->gid = 0;
     78    /* Don't delete if chan ID isn't zero: it's still in the chan hash map */
     79    if (!c->chan)
     80      tor_free(c);
     81  }
     82  HT_CLEAR(bto_gid_ht, bto_gid_map);
     83  tor_free(bto_gid_map);
     84 }
     85 
     86 /** Clear the chan ID hash map, freeing any bt_orconn_t objects that
     87 * become unreferenced */
     88 static void
     89 bto_chan_clear_map(void)
     90 {
     91  bt_orconn_t **elt, **next, *c;
     92 
     93  for (elt = HT_START(bto_chan_ht, bto_chan_map);
     94       elt;
     95       elt = next) {
     96    c = *elt;
     97    next = HT_NEXT_RMV(bto_chan_ht, bto_chan_map, elt);
     98 
     99    c->chan = 0;
    100    /* Don't delete if GID isn't zero, it's still in the GID hash map */
    101    if (!c->gid)
    102      tor_free(c);
    103  }
    104  HT_CLEAR(bto_chan_ht, bto_chan_map);
    105  tor_free(bto_chan_map);
    106 }
    107 
    108 /** Delete a bt_orconn from the hash maps by GID */
    109 void
    110 bto_delete(uint64_t gid)
    111 {
    112  bt_orconn_t key, *bto;
    113 
    114  key.gid = gid;
    115  key.chan = 0;
    116  bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
    117  if (!bto) {
    118    /* The orconn might be unregistered because it's an EXT_OR_CONN? */
    119    log_debug(LD_BTRACK, "tried to delete unregistered ORCONN gid=%"PRIu64,
    120              gid);
    121    return;
    122  }
    123  HT_REMOVE(bto_gid_ht, bto_gid_map, &key);
    124  if (bto->chan) {
    125    key.chan = bto->chan;
    126    HT_REMOVE(bto_chan_ht, bto_chan_map, &key);
    127  }
    128  tor_free(bto);
    129 }
    130 
    131 /**
    132 * Helper for bto_find_or_new().
    133 *
    134 * Update GID and chan ID of an existing bt_orconn object if needed,
    135 * given a search key previously used within bto_find_or_new().
    136 **/
    137 static bt_orconn_t *
    138 bto_update(bt_orconn_t *bto, const bt_orconn_t *key)
    139 {
    140  /* ORCONN GIDs shouldn't change once assigned */
    141  tor_assert(!bto->gid || !key->gid || bto->gid == key->gid);
    142  if (!bto->gid && key->gid) {
    143    /* Got a gid when we didn't already have one; insert into gid map */
    144    log_debug(LD_BTRACK, "ORCONN chan=%"PRIu64" newgid=%"PRIu64, key->chan,
    145              key->gid);
    146    bto->gid = key->gid;
    147    HT_INSERT(bto_gid_ht, bto_gid_map, bto);
    148  }
    149  /* association of ORCONN with channel shouldn't change */
    150  tor_assert(!bto->chan || !key->chan || bto->chan == key->chan);
    151  if (!bto->chan && key->chan) {
    152    /* Got a chan when we didn't already have one; insert into chan map */
    153    log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" newchan=%"PRIu64,
    154              bto->gid, key->chan);
    155    bto->chan = key->chan;
    156    HT_INSERT(bto_chan_ht, bto_chan_map, bto);
    157  }
    158  return bto;
    159 }
    160 
    161 /** Helper for bto_find_or_new() */
    162 static bt_orconn_t *
    163 bto_new(const bt_orconn_t *key)
    164 {
    165  struct bt_orconn_t *bto = tor_malloc(sizeof(*bto));
    166 
    167  bto->gid = key->gid;
    168  bto->chan = key->chan;
    169  bto->state = 0;
    170  bto->proxy_type = 0;
    171  bto->is_orig = false;
    172  bto->is_onehop = true;
    173 
    174  if (bto->gid)
    175    HT_INSERT(bto_gid_ht, bto_gid_map, bto);
    176  if (bto->chan)
    177    HT_INSERT(bto_chan_ht, bto_chan_map, bto);
    178 
    179  return bto;
    180 }
    181 
    182 /**
    183 * Insert a new bt_orconn with the given GID and chan ID, or update
    184 * the GID and chan ID if one already exists.
    185 *
    186 * Return the found or allocated bt_orconn.
    187 **/
    188 bt_orconn_t *
    189 bto_find_or_new(uint64_t gid, uint64_t chan)
    190 {
    191  bt_orconn_t key, *bto = NULL;
    192 
    193  tor_assert(gid || chan);
    194  key.gid = gid;
    195  key.chan = chan;
    196  if (key.gid)
    197    bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
    198  if (!bto && key.chan) {
    199    /* Not found by GID; look up by chan ID */
    200    bto = HT_FIND(bto_chan_ht, bto_chan_map, &key);
    201  }
    202  if (bto)
    203    return bto_update(bto, &key);
    204  else
    205    return bto_new(&key);
    206 }
    207 
    208 /** Initialize the hash maps  */
    209 void
    210 bto_init_maps(void)
    211 {
    212  bto_gid_map = tor_malloc(sizeof(*bto_gid_map));
    213  HT_INIT(bto_gid_ht, bto_gid_map);
    214  bto_chan_map = tor_malloc(sizeof(*bto_chan_map));
    215  HT_INIT(bto_chan_ht, bto_chan_map);
    216 }
    217 
    218 /** Clear the hash maps, freeing all associated storage */
    219 void
    220 bto_clear_maps(void)
    221 {
    222  bto_gid_clear_map();
    223  bto_chan_clear_map();
    224 }