summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/channel.c24
-rw-r--r--src/or/channeltls.c11
-rw-r--r--src/or/relay.c24
-rw-r--r--src/test/test_channel.c2
4 files changed, 32 insertions, 29 deletions
diff --git a/src/or/channel.c b/src/or/channel.c
index 94d7af47b5..9e79fc1a3f 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -1431,8 +1431,11 @@ channel_clear_remote_end(channel_t *chan)
/**
* Write to a channel the given packed cell.
*
- * Return 0 on success and the cell is freed so the caller MUST discard any
- * reference to it. On error, -1 is returned and the cell is untouched.
+ * Return 0 on success or -1 on error.
+ *
+ * Two possible errors can happen. Either the channel is not opened or the
+ * lower layer (specialized channel) failed to write it. In both cases, it is
+ * the caller responsability to free the cell.
*/
static int
write_packed_cell(channel_t *chan, packed_cell_t *cell)
@@ -1483,10 +1486,15 @@ write_packed_cell(channel_t *chan, packed_cell_t *cell)
* Write a packed cell to a channel using the write_cell() method. This is
* called by the transport-independent code to deliver a packed cell to a
* channel for transmission.
+ *
+ * Return 0 on success else a negative value. In both cases, the caller should
+ * not access the cell anymore, it is freed both on success and error.
*/
int
channel_write_packed_cell(channel_t *chan, packed_cell_t *cell)
{
+ int ret = -1;
+
tor_assert(chan);
tor_assert(cell);
@@ -1494,14 +1502,20 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *cell)
log_debug(LD_CHANNEL, "Discarding %p on closing channel %p with "
"global ID "U64_FORMAT, cell, chan,
U64_PRINTF_ARG(chan->global_identifier));
- tor_free(cell);
- return -1;
+ goto end;
}
log_debug(LD_CHANNEL,
"Writing %p to channel %p with global ID "
U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier));
- return write_packed_cell(chan, cell);
+ ret = write_packed_cell(chan, cell);
+
+ end:
+ /* Whatever happens, we free the cell. Either an error occured or the cell
+ * was put on the connection outbuf, both cases we have ownership of the
+ * cell and we free it. */
+ packed_cell_free(cell);
+ return ret;
}
/**
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index e6ecc15381..023ccdefd3 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -832,6 +832,9 @@ channel_tls_write_cell_method(channel_t *chan, cell_t *cell)
*
* This implements the write_packed_cell method for channel_tls_t; given a
* channel_tls_t and a packed_cell_t, transmit the packed_cell_t.
+ *
+ * Return 0 on success or negative value on error. The caller must free the
+ * packed cell.
*/
static int
@@ -841,7 +844,6 @@ channel_tls_write_packed_cell_method(channel_t *chan,
tor_assert(chan);
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
size_t cell_network_size = get_cell_network_size(chan->wide_circ_ids);
- int written = 0;
tor_assert(tlschan);
tor_assert(packed_cell);
@@ -849,18 +851,15 @@ channel_tls_write_packed_cell_method(channel_t *chan,
if (tlschan->conn) {
connection_buf_add(packed_cell->body, cell_network_size,
TO_CONN(tlschan->conn));
-
- /* This is where the cell is finished; used to be done from relay.c */
- packed_cell_free(packed_cell);
- ++written;
} else {
log_info(LD_CHANNEL,
"something called write_packed_cell on a tlschan "
"(%p with ID " U64_FORMAT " but no conn",
chan, U64_PRINTF_ARG(chan->global_identifier));
+ return -1;
}
- return written;
+ return 0;
}
/**
diff --git a/src/or/relay.c b/src/or/relay.c
index f36fc78cda..ac91032844 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -2521,17 +2521,6 @@ cell_queue_pop(cell_queue_t *queue)
return cell;
}
-/** Insert <b>cell</b> as the head of the <b>queue</b>. */
-static void
-cell_insert_head(cell_queue_t *queue, packed_cell_t *cell)
-{
- tor_assert(queue);
- tor_assert(cell);
-
- TOR_SIMPLEQ_INSERT_HEAD(&queue->head, cell, next);
- ++queue->n;
-}
-
/** Return the total number of bytes used for each packed_cell in a queue.
* Approximate. */
size_t
@@ -2757,8 +2746,11 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
/* this code is duplicated from some of the logic below. Ugly! XXXX */
tor_assert(destroy_queue->n > 0);
cell = cell_queue_pop(destroy_queue);
+ /* Send the DESTROY cell. It is very unlikely that this fails but just
+ * in case, get rid of the channel. */
if (channel_write_packed_cell(chan, cell) < 0) {
- cell_insert_head(destroy_queue, cell);
+ /* The cell has been freed. */
+ channel_mark_for_close(chan);
continue;
}
/* Update the cmux destroy counter */
@@ -2836,11 +2828,11 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
DIRREQ_TUNNELED,
DIRREQ_CIRC_QUEUE_FLUSHED);
- /* Now send the cell */
+ /* Now send the cell. It is very unlikely that this fails but just in
+ * case, get rid of the channel. */
if (channel_write_packed_cell(chan, cell) < 0) {
- /* Unable to send the cell, put it back at the start of the circuit
- * queue so we can retry. */
- cell_insert_head(queue, cell);
+ /* The cell has been freed at this point. */
+ channel_mark_for_close(chan);
continue;
}
cell = NULL;
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index 88a13862bd..c3b99d87ac 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -199,7 +199,6 @@ chan_test_write_packed_cell(channel_t *ch,
if (test_chan_accept_cells) {
/* Free the cell and bump the counter */
- packed_cell_free(packed_cell);
++test_cells_written;
rv = 1;
}
@@ -846,7 +845,6 @@ test_channel_lifecycle(void *arg)
done:
free_fake_channel(ch1);
free_fake_channel(ch2);
- tor_free(p_cell);
UNMOCK(scheduler_channel_doesnt_want_writes);
UNMOCK(scheduler_release_channel);