summaryrefslogtreecommitdiff
path: root/src/or/channel.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2013-03-21 14:51:27 -0400
committerNick Mathewson <nickm@torproject.org>2013-06-13 10:14:00 -0400
commit43d53e6d86acaf7555c31730a8230fa0cdf31306 (patch)
treec12b3285f417aad70b913662006e8572edf708b6 /src/or/channel.c
parent801eea03ad71dafd31cc6bfa06fa5e421aa95cd6 (diff)
downloadtor-43d53e6d86acaf7555c31730a8230fa0cdf31306.tar.gz
tor-43d53e6d86acaf7555c31730a8230fa0cdf31306.zip
Implementation of a fix for bug 7912
I added the code to pass a destroy cell to a queueing function rather than writing it immediately, and the code to remember that we shouldn't reuse the circuit id until the destroy is actually sent, and the code to release the circuit id once the destroy has been sent... and then I finished by hooking destroy_cell_queue into the rest of Tor.
Diffstat (limited to 'src/or/channel.c')
-rw-r--r--src/or/channel.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/src/or/channel.c b/src/or/channel.c
index 4e9086f2e6..e327bda518 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -122,6 +122,8 @@ static cell_queue_entry_t *
cell_queue_entry_new_fixed(cell_t *cell);
static cell_queue_entry_t *
cell_queue_entry_new_var(var_cell_t *var_cell);
+static int is_destroy_cell(channel_t *chan,
+ const cell_queue_entry_t *q, circid_t *circid_out);
/* Functions to maintain the digest map */
static void channel_add_to_digest_map(channel_t *chan);
@@ -1685,6 +1687,13 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
chan->timestamp_last_added_nonpadding = approx_time();
}
+ {
+ circid_t circ_id;
+ if (is_destroy_cell(chan, q, &circ_id)) {
+ channel_note_destroy_not_pending(chan, circ_id);
+ }
+ }
+
/* Can we send it right out? If so, try */
if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
chan->state == CHANNEL_STATE_OPEN) {
@@ -2607,6 +2616,43 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
}
}
+/** DOCDOC */
+static int
+is_destroy_cell(channel_t *chan,
+ const cell_queue_entry_t *q, circid_t *circid_out)
+{
+ *circid_out = 0;
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell->command == CELL_DESTROY) {
+ *circid_out = q->u.fixed.cell->circ_id;
+ return 1;
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell->command == CELL_DESTROY) {
+ *circid_out = q->u.var.var_cell->circ_id;
+ return 1;
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ if (chan->wide_circ_ids) {
+ if (q->u.packed.packed_cell->body[4] == CELL_DESTROY) {
+ *circid_out = ntohl(get_uint32(q->u.packed.packed_cell->body));
+ return 1;
+ }
+ } else {
+ if (q->u.packed.packed_cell->body[2] == CELL_DESTROY) {
+ *circid_out = ntohs(get_uint16(q->u.packed.packed_cell->body));
+ return 1;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+
/**
* Send destroy cell on a channel
*
@@ -2618,25 +2664,20 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
int
channel_send_destroy(circid_t circ_id, channel_t *chan, int reason)
{
- cell_t cell;
-
tor_assert(chan);
/* Check to make sure we can send on this channel first */
if (!(chan->state == CHANNEL_STATE_CLOSING ||
chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
- memset(&cell, 0, sizeof(cell_t));
- cell.circ_id = circ_id;
- cell.command = CELL_DESTROY;
- cell.payload[0] = (uint8_t) reason;
+ chan->state == CHANNEL_STATE_ERROR) &&
+ chan->cmux) {
+ channel_note_destroy_pending(chan, circ_id);
+ circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason);
log_debug(LD_OR,
"Sending destroy (circID %u) on channel %p "
"(global ID " U64_FORMAT ")",
(unsigned)circ_id, chan,
U64_PRINTF_ARG(chan->global_identifier));
-
- channel_write_cell(chan, &cell);
} else {
log_warn(LD_BUG,
"Someone called channel_send_destroy() for circID %u "