|
@@ -207,18 +207,123 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/** Mark that circuit id <b>id</b> shouldn't be used on channel <b>chan</b>,
|
|
|
+ * even if there is no circuit on the channel. We use this to keep the
|
|
|
+ * circuit id from getting re-used while we have queued but not yet sent
|
|
|
+ * a destroy cell. */
|
|
|
+void
|
|
|
+channel_mark_circid_unusable(channel_t *chan, circid_t id)
|
|
|
+{
|
|
|
+ chan_circid_circuit_map_t search;
|
|
|
+ chan_circid_circuit_map_t *ent;
|
|
|
+
|
|
|
+ /* See if there's an entry there. That wouldn't be good. */
|
|
|
+ memset(&search, 0, sizeof(search));
|
|
|
+ search.chan = chan;
|
|
|
+ search.circ_id = id;
|
|
|
+ ent = HT_FIND(chan_circid_map, &chan_circid_map, &search);
|
|
|
+
|
|
|
+ if (ent && ent->circuit) {
|
|
|
+ /* we have a problem. */
|
|
|
+ log_warn(LD_BUG, "Tried to mark %u unusable on %p, but there was already "
|
|
|
+ "a circuit there.", (unsigned)id, chan);
|
|
|
+ } else if (ent) {
|
|
|
+ /* It's already marked. */
|
|
|
+ } else {
|
|
|
+ ent = tor_malloc_zero(sizeof(chan_circid_circuit_map_t));
|
|
|
+ ent->chan = chan;
|
|
|
+ ent->circ_id = id;
|
|
|
+ /* leave circuit at NULL */
|
|
|
+ HT_INSERT(chan_circid_map, &chan_circid_map, ent);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** Mark that a circuit id <b>id</b> can be used again on <b>chan</b>.
|
|
|
+ * We use this to re-enable the circuit ID after we've sent a destroy cell.
|
|
|
+ */
|
|
|
+void
|
|
|
+channel_mark_circid_usable(channel_t *chan, circid_t id)
|
|
|
+{
|
|
|
+ chan_circid_circuit_map_t search;
|
|
|
+ chan_circid_circuit_map_t *ent;
|
|
|
+
|
|
|
+ /* See if there's an entry there. That wouldn't be good. */
|
|
|
+ memset(&search, 0, sizeof(search));
|
|
|
+ search.chan = chan;
|
|
|
+ search.circ_id = id;
|
|
|
+ ent = HT_REMOVE(chan_circid_map, &chan_circid_map, &search);
|
|
|
+ if (ent && ent->circuit) {
|
|
|
+ log_warn(LD_BUG, "Tried to mark %u usable on %p, but there was already "
|
|
|
+ "a circuit there.", (unsigned)id, chan);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (_last_circid_chan_ent == ent)
|
|
|
+ _last_circid_chan_ent = NULL;
|
|
|
+ tor_free(ent);
|
|
|
+}
|
|
|
+
|
|
|
+/** Called to indicate that a DESTROY is pending on <b>chan</b> with
|
|
|
+ * circuit ID <b>id</b>, but hasn't been sent yet. */
|
|
|
+void
|
|
|
+channel_note_destroy_pending(channel_t *chan, circid_t id)
|
|
|
+{
|
|
|
+ circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan);
|
|
|
+ if (circ) {
|
|
|
+ if (circ->n_chan == chan && circ->n_circ_id == id) {
|
|
|
+ circ->n_delete_pending = 1;
|
|
|
+ } else {
|
|
|
+ or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
|
|
|
+ if (orcirc->p_chan == chan && orcirc->p_circ_id == id) {
|
|
|
+ circ->p_delete_pending = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ channel_mark_circid_unusable(chan, id);
|
|
|
+}
|
|
|
+
|
|
|
+/** Called to indicate that a DESTROY is no longer pending on <b>chan</b> with
|
|
|
+ * circuit ID <b>id</b> -- typically, because it has been sent. */
|
|
|
+void
|
|
|
+channel_note_destroy_not_pending(channel_t *chan, circid_t id)
|
|
|
+{
|
|
|
+ circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan);
|
|
|
+ if (circ) {
|
|
|
+ if (circ->n_chan == chan && circ->n_circ_id == id) {
|
|
|
+ circ->n_delete_pending = 0;
|
|
|
+ } else {
|
|
|
+ or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
|
|
|
+ if (orcirc->p_chan == chan && orcirc->p_circ_id == id) {
|
|
|
+ circ->p_delete_pending = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* XXXX this shouldn't happen; log a bug here. */
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ channel_mark_circid_usable(chan, id);
|
|
|
+}
|
|
|
+
|
|
|
/** Set the p_conn field of a circuit <b>circ</b>, along
|
|
|
* with the corresponding circuit ID, and add the circuit as appropriate
|
|
|
* to the (chan,id)-\>circuit map. */
|
|
|
void
|
|
|
-circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
|
|
|
+circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id,
|
|
|
channel_t *chan)
|
|
|
{
|
|
|
- circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
|
|
|
- id, chan);
|
|
|
+ circuit_t *circ = TO_CIRCUIT(or_circ);
|
|
|
+ channel_t *old_chan = or_circ->p_chan;
|
|
|
+ circid_t old_id = or_circ->p_circ_id;
|
|
|
+
|
|
|
+ circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan);
|
|
|
|
|
|
if (chan)
|
|
|
- tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan));
|
|
|
+ tor_assert(bool_eq(or_circ->p_chan_cells.n,
|
|
|
+ or_circ->next_active_on_p_chan));
|
|
|
+
|
|
|
+ if (circ->p_delete_pending && old_chan) {
|
|
|
+ channel_mark_circid_unusable(old_chan, old_id);
|
|
|
+ circ->p_delete_pending = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** Set the n_conn field of a circuit <b>circ</b>, along
|
|
@@ -228,10 +333,18 @@ void
|
|
|
circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
|
|
|
channel_t *chan)
|
|
|
{
|
|
|
+ channel_t *old_chan = circ->n_chan;
|
|
|
+ circid_t old_id = circ->n_circ_id;
|
|
|
+
|
|
|
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
|
|
|
|
|
|
if (chan)
|
|
|
tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
|
|
|
+
|
|
|
+ if (circ->n_delete_pending && old_chan) {
|
|
|
+ channel_mark_circid_unusable(old_chan, old_id);
|
|
|
+ circ->n_delete_pending = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
|
|
@@ -928,9 +1041,13 @@ circuit_get_by_global_id(uint32_t id)
|
|
|
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
|
|
|
* - circ is attached to <b>chan</b>, either as p_chan or n_chan.
|
|
|
* Return NULL if no such circuit exists.
|
|
|
+ *
|
|
|
+ * If <b>found_entry_out</b> is provided, set it to true if we have a
|
|
|
+ * placeholder entry for circid/chan, and leave it unset otherwise.
|
|
|
*/
|
|
|
static INLINE circuit_t *
|
|
|
-circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
|
|
|
+circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan,
|
|
|
+ int *found_entry_out)
|
|
|
{
|
|
|
chan_circid_circuit_map_t search;
|
|
|
chan_circid_circuit_map_t *found;
|
|
@@ -951,15 +1068,21 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
|
|
|
" circ_id %u, channel ID " U64_FORMAT " (%p)",
|
|
|
found->circuit, (unsigned)circ_id,
|
|
|
U64_PRINTF_ARG(chan->global_identifier), chan);
|
|
|
+ if (found_entry_out)
|
|
|
+ *found_entry_out = 1;
|
|
|
return found->circuit;
|
|
|
}
|
|
|
|
|
|
log_debug(LD_CIRC,
|
|
|
- "circuit_get_by_circid_channel_impl() found nothing for"
|
|
|
+ "circuit_get_by_circid_channel_impl() found %s for"
|
|
|
" circ_id %u, channel ID " U64_FORMAT " (%p)",
|
|
|
+ found ? "placeholder" : "nothing",
|
|
|
(unsigned)circ_id,
|
|
|
U64_PRINTF_ARG(chan->global_identifier), chan);
|
|
|
|
|
|
+ if (found_entry_out)
|
|
|
+ *found_entry_out = found ? 1 : 0;
|
|
|
+
|
|
|
return NULL;
|
|
|
/* The rest of this checks for bugs. Disabled by default. */
|
|
|
/* We comment it out because coverity complains otherwise.
|
|
@@ -993,7 +1116,7 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
|
|
|
circuit_t *
|
|
|
circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan)
|
|
|
{
|
|
|
- circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan);
|
|
|
+ circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan, NULL);
|
|
|
if (!circ || circ->marked_for_close)
|
|
|
return NULL;
|
|
|
else
|
|
@@ -1009,7 +1132,7 @@ circuit_t *
|
|
|
circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
|
|
|
channel_t *chan)
|
|
|
{
|
|
|
- return circuit_get_by_circid_channel_impl(circ_id, chan);
|
|
|
+ return circuit_get_by_circid_channel_impl(circ_id, chan, NULL);
|
|
|
}
|
|
|
|
|
|
/** Return true iff the circuit ID <b>circ_id</b> is currently used by a
|
|
@@ -1017,7 +1140,9 @@ circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
|
|
|
int
|
|
|
circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
|
|
|
{
|
|
|
- return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL;
|
|
|
+ int found = 0;
|
|
|
+ return circuit_get_by_circid_channel_impl(circ_id, chan, &found) != NULL
|
|
|
+ || found;
|
|
|
}
|
|
|
|
|
|
/** Return the circuit that a given edge connection is using. */
|
|
@@ -1585,15 +1710,16 @@ assert_circuit_ok(const circuit_t *c)
|
|
|
/* We use the _impl variant here to make sure we don't fail on marked
|
|
|
* circuits, which would not be returned by the regular function. */
|
|
|
circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id,
|
|
|
- c->n_chan);
|
|
|
+ c->n_chan, NULL);
|
|
|
tor_assert(c == c2);
|
|
|
}
|
|
|
}
|
|
|
if (or_circ && or_circ->p_chan) {
|
|
|
if (or_circ->p_circ_id) {
|
|
|
/* ibid */
|
|
|
- circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
|
|
|
- or_circ->p_chan);
|
|
|
+ circuit_t *c2 =
|
|
|
+ circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
|
|
|
+ or_circ->p_chan, NULL);
|
|
|
tor_assert(c == c2);
|
|
|
}
|
|
|
}
|