1 /* Copyright (c) 2007-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 * \file btrack_orconn_maps.c
6 * \brief Hash map implementation for btrack_orconn.c
8 * These functions manipulate the hash maps that contain bt_orconn
14 #include "core/or/or.h"
19 #define BTRACK_ORCONN_PRIVATE
21 #include "feature/control/btrack_orconn.h"
22 #include "feature/control/btrack_orconn_maps.h"
23 #include "lib/log/log.h"
25 static inline unsigned int
26 bto_gid_hash_(bt_orconn_t
*elm
)
28 return (unsigned)siphash24g(&elm
->gid
, sizeof(elm
->gid
));
32 bto_gid_eq_(bt_orconn_t
*a
, bt_orconn_t
*b
)
34 return a
->gid
== b
->gid
;
37 static inline unsigned int
38 bto_chan_hash_(bt_orconn_t
*elm
)
40 return (unsigned)siphash24g(&elm
->chan
, sizeof(elm
->chan
));
44 bto_chan_eq_(bt_orconn_t
*a
, bt_orconn_t
*b
)
46 return a
->chan
== b
->chan
;
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
;
56 HT_HEAD(bto_chan_ht
, bt_orconn_t
);
57 HT_PROTOTYPE(bto_chan_ht
, bt_orconn_t
, chan_node
, bto_chan_hash_
,
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
;
64 /** Clear the GID hash map, freeing any bt_orconn_t objects that become
67 bto_gid_clear_map(void)
69 bt_orconn_t
**elt
, **next
, *c
;
71 for (elt
= HT_START(bto_gid_ht
, bto_gid_map
);
75 next
= HT_NEXT_RMV(bto_gid_ht
, bto_gid_map
, elt
);
78 /* Don't delete if chan ID isn't zero: it's still in the chan hash map */
82 HT_CLEAR(bto_gid_ht
, bto_gid_map
);
83 tor_free(bto_gid_map
);
86 /** Clear the chan ID hash map, freeing any bt_orconn_t objects that
87 * become unreferenced */
89 bto_chan_clear_map(void)
91 bt_orconn_t
**elt
, **next
, *c
;
93 for (elt
= HT_START(bto_chan_ht
, bto_chan_map
);
97 next
= HT_NEXT_RMV(bto_chan_ht
, bto_chan_map
, elt
);
100 /* Don't delete if GID isn't zero, it's still in the GID hash map */
104 HT_CLEAR(bto_chan_ht
, bto_chan_map
);
105 tor_free(bto_chan_map
);
108 /** Delete a bt_orconn from the hash maps by GID */
110 bto_delete(uint64_t gid
)
112 bt_orconn_t key
, *bto
;
116 bto
= HT_FIND(bto_gid_ht
, bto_gid_map
, &key
);
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
,
123 HT_REMOVE(bto_gid_ht
, bto_gid_map
, &key
);
125 key
.chan
= bto
->chan
;
126 HT_REMOVE(bto_chan_ht
, bto_chan_map
, &key
);
132 * Helper for bto_find_or_new().
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().
138 bto_update(bt_orconn_t
*bto
, const bt_orconn_t
*key
)
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
,
147 HT_INSERT(bto_gid_ht
, bto_gid_map
, bto
);
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
);
161 /** Helper for bto_find_or_new() */
163 bto_new(const bt_orconn_t
*key
)
165 struct bt_orconn_t
*bto
= tor_malloc(sizeof(*bto
));
168 bto
->chan
= key
->chan
;
171 bto
->is_orig
= false;
172 bto
->is_onehop
= true;
175 HT_INSERT(bto_gid_ht
, bto_gid_map
, bto
);
177 HT_INSERT(bto_chan_ht
, bto_chan_map
, bto
);
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.
186 * Return the found or allocated bt_orconn.
189 bto_find_or_new(uint64_t gid
, uint64_t chan
)
191 bt_orconn_t key
, *bto
= NULL
;
193 tor_assert(gid
|| chan
);
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
);
203 return bto_update(bto
, &key
);
205 return bto_new(&key
);
208 /** Initialize the hash maps */
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
);
218 /** Clear the hash maps, freeing all associated storage */
223 bto_chan_clear_map();