diff options
author | Andrea Shepard <andrea@torproject.org> | 2013-06-13 20:32:31 -0700 |
---|---|---|
committer | Andrea Shepard <andrea@torproject.org> | 2013-06-13 21:59:01 -0700 |
commit | 459aada4d0e2ca1c4538fb6f4ef4e275ae162600 (patch) | |
tree | 1c8242f0455b99a10792670977b3341ef7beb8e4 /src/or/relay.c | |
parent | 6fc3997307b1a2729dcc651102e79b195698b6af (diff) | |
download | tor-459aada4d0e2ca1c4538fb6f4ef4e275ae162600.tar.gz tor-459aada4d0e2ca1c4538fb6f4ef4e275ae162600.zip |
Don't queue more cells as a middle relay than the spec allows to be in flight
Diffstat (limited to 'src/or/relay.c')
-rw-r--r-- | src/or/relay.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/src/or/relay.c b/src/or/relay.c index cef138e721..f682d6a1c0 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -58,6 +58,7 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, entry_connection_t *conn, node_t *node, const tor_addr_t *addr); +static int get_max_middle_cells(void); /** Stop reading on edge connections when we have this many cells * waiting on the appropriate queue. */ @@ -2461,6 +2462,18 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) return n_flushed; } +/** Indicate the current preferred cap for middle circuits; zero disables + * the cap. Right now it's just a constant, ORCIRC_MAX_MIDDLE_CELLS, but + * the logic in append_cell_to_circuit_queue() is written to be correct + * if we want to base it on a consensus param or something that might change + * in the future. + */ +static int +get_max_middle_cells(void) +{ + return ORCIRC_MAX_MIDDLE_CELLS; +} + /** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b> * transmitting in <b>direction</b>. */ void @@ -2468,8 +2481,11 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, streamid_t fromstream) { + or_circuit_t *orcirc = NULL; cell_queue_t *queue; int streams_blocked; + uint32_t tgt_max_middle_cells, p_len, n_len, tmp, hard_max_middle_cells; + if (circ->marked_for_close) return; @@ -2477,11 +2493,88 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, queue = &circ->n_chan_cells; streams_blocked = circ->streams_blocked_on_n_chan; } else { - or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + orcirc = TO_OR_CIRCUIT(circ); queue = &orcirc->p_chan_cells; streams_blocked = circ->streams_blocked_on_p_chan; } + /* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */ + if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) { + orcirc = TO_OR_CIRCUIT(circ); + if (orcirc->p_chan) { + /* We are a middle circuit if we have both n_chan and p_chan */ + /* We'll need to know the current preferred maximum */ + tgt_max_middle_cells = get_max_middle_cells(); + if (tgt_max_middle_cells > 0) { + /* Do we need to initialize middle_max_cells? */ + if (orcirc->max_middle_cells == 0) { + orcirc->max_middle_cells = tgt_max_middle_cells; + } else { + if (tgt_max_middle_cells > orcirc->max_middle_cells) { + /* If we want to increase the cap, we can do so right away */ + orcirc->max_middle_cells = tgt_max_middle_cells; + } else if (tgt_max_middle_cells < orcirc->max_middle_cells) { + /* + * If we're shrinking the cap, we can't shrink past either queue; + * compare tgt_max_middle_cells rather than tgt_max_middle_cells * + * ORCIRC_MAX_MIDDLE_KILL_THRESH so the queues don't shrink enough + * to generate spurious warnings, either. + */ + n_len = circ->n_chan_cells.n; + p_len = orcirc->p_chan_cells.n; + tmp = tgt_max_middle_cells; + if (tmp < n_len) tmp = n_len; + if (tmp < p_len) tmp = p_len; + orcirc->max_middle_cells = tmp; + } + /* else no change */ + } + } else { + /* tgt_max_middle_cells == 0 indicates we should disable the cap */ + orcirc->max_middle_cells = 0; + } + + /* Now we know orcirc->max_middle_cells is set correctly */ + if (orcirc->max_middle_cells > 0) { + hard_max_middle_cells = + (uint32_t)(((double)orcirc->max_middle_cells) * + ORCIRC_MAX_MIDDLE_KILL_THRESH); + + if (queue->n + 1 >= hard_max_middle_cells) { + /* Queueing this cell would put queue over the kill theshold */ + log_warn(LD_CIRC, + "Got a cell exceeding the hard cap of %u in the " + "%s direction on middle circ ID %u on chan ID " + U64_FORMAT "; killing the circuit.", + hard_max_middle_cells, + (direction == CELL_DIRECTION_OUT) ? "n" : "p", + (direction == CELL_DIRECTION_OUT) ? + circ->n_circ_id : orcirc->p_circ_id, + U64_PRINTF_ARG( + (direction == CELL_DIRECTION_OUT) ? + circ->n_chan->global_identifier : + orcirc->p_chan->global_identifier)); + circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + return; + } else if (queue->n + 1 == orcirc->max_middle_cells) { + /* Only use ==, not >= for this test so we don't spam the log */ + log_warn(LD_CIRC, + "While trying to queue a cell, reached the soft cap of %u " + "in the %s direction on middle circ ID %u " + "on chan ID " U64_FORMAT ".", + orcirc->max_middle_cells, + (direction == CELL_DIRECTION_OUT) ? "n" : "p", + (direction == CELL_DIRECTION_OUT) ? + circ->n_circ_id : orcirc->p_circ_id, + U64_PRINTF_ARG( + (direction == CELL_DIRECTION_OUT) ? + circ->n_chan->global_identifier : + orcirc->p_chan->global_identifier)); + } + } + } + } + cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids); /* If we have too many cells on the circuit, we should stop reading from |