* If more than one channel exists, follow the next_with_same_id pointer
* as a linked list.
*/
- static digestmap_t *channel_identity_map = NULL;
+ HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map =
+ HT_INITIALIZER();
+
+ typedef struct channel_idmap_entry_s {
+ HT_ENTRY(channel_idmap_entry_s) node;
+ uint8_t digest[DIGEST_LEN];
+ LIST_HEAD(channel_list_s, channel_s) channel_list;
+ } channel_idmap_entry_t;
+
+ static INLINE unsigned
+ channel_idmap_hash(const channel_idmap_entry_t *ent)
+ {
+ const unsigned *a = (const unsigned *)ent->digest;
+ #if SIZEOF_INT == 4
+ return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4];
+ #elif SIZEOF_INT == 8
+ return a[0] ^ a[1];
+ #endif
+ }
+
+ static INLINE int
+ channel_idmap_eq(const channel_idmap_entry_t *a,
+ const channel_idmap_entry_t *b)
+ {
+ return tor_memeq(a->digest, b->digest, DIGEST_LEN);
+ }
+
+ HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq);
+ HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
- channel_idmap_eq, 0.5, tor_malloc, tor_realloc, _tor_free);
++ channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_);
static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q);
static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
static void
channel_force_free(channel_t *chan)
{
+ cell_queue_entry_t *cell, *cell_tmp;
tor_assert(chan);
+ log_debug(LD_CHANNEL,
+ "Force-freeing channel " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
+ /*
+ * Get rid of cmux policy before we do anything, so cmux policies don't
+ * see channels in weird half-freed states.
+ */
+ if (chan->cmux) {
+ circuitmux_set_policy(chan->cmux, NULL);
+ }
+
/* Call a free method if there is one */
if (chan->free) chan->free(chan);
channel_clear_remote_end(chan);
+ /* Get rid of cmux */
+ if (chan->cmux) {
+ circuitmux_free(chan->cmux);
+ chan->cmux = NULL;
+ }
+
/* We might still have a cell queue; kill it */
- if (chan->incoming_queue) {
- SMARTLIST_FOREACH_BEGIN(chan->incoming_queue,
- cell_queue_entry_t *, q) {
- cell_queue_entry_free(q, 0);
- } SMARTLIST_FOREACH_END(q);
-
- smartlist_free(chan->incoming_queue);
- chan->incoming_queue = NULL;
+ SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
}
+ SIMPLEQ_INIT(&chan->incoming_queue);
/* Outgoing cell queue is similar, but we can have to free packed cells */
- if (chan->outgoing_queue) {
- SMARTLIST_FOREACH_BEGIN(chan->outgoing_queue,
- cell_queue_entry_t *, q) {
- cell_queue_entry_free(q, 0);
- } SMARTLIST_FOREACH_END(q);
-
- smartlist_free(chan->outgoing_queue);
- chan->outgoing_queue = NULL;
+ SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
}
+ SIMPLEQ_INIT(&chan->outgoing_queue);
tor_free(chan);
}