📄 relay.c
字号:
log_debug(domain,"yes, at-origin. stopped.");
for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn;
conn=conn->next_stream)
if (conn->cpath_layer == layer_hint)
connection_stop_reading(TO_CONN(conn));
return 1;
}
return 0;
}
/** Check if the deliver_window for circuit <b>circ</b> (at hop
* <b>layer_hint</b> if it's defined) is low enough that we should
* send a circuit-level sendme back down the circuit. If so, send
* enough sendmes that the window would be overfull if we sent any
* more.
*/
static void
circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
{
// log_fn(LOG_INFO,"Considering: layer_hint is %s",
// layer_hint ? "defined" : "null");
while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <
CIRCWINDOW_START - CIRCWINDOW_INCREMENT) {
log_debug(LD_CIRC,"Queueing circuit sendme.");
if (layer_hint)
layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
else
circ->deliver_window += CIRCWINDOW_INCREMENT;
if (relay_send_command_from_edge(0, circ, RELAY_COMMAND_SENDME,
NULL, 0, layer_hint) < 0) {
log_warn(LD_CIRC,
"relay_send_command_from_edge failed. Circuit's closed.");
return; /* the circuit's closed, don't continue */
}
}
}
/** Stop reading on edge connections when we have this many cells
* waiting on the appropriate queue. */
#define CELL_QUEUE_HIGHWATER_SIZE 256
/** Start reading from edge connections again when we get down to this many
* cells. */
#define CELL_QUEUE_LOWWATER_SIZE 64
#ifdef ACTIVE_CIRCUITS_PARANOIA
#define assert_active_circuits_ok_paranoid(conn) \
assert_active_circuits_ok(conn)
#else
#define assert_active_circuits_ok_paranoid(conn)
#endif
/** The total number of cells we have allocated from the memory pool. */
static int total_cells_allocated = 0;
#ifdef ENABLE_CELL_POOL /* Defined in ./configure. True by default. */
/* XXX021 make cell pools the only option once we know they work and improve
* matters? -RD */
static mp_pool_t *cell_pool = NULL;
/** Allocate structures to hold cells. */
void
init_cell_pool(void)
{
tor_assert(!cell_pool);
cell_pool = mp_pool_new(sizeof(packed_cell_t), 128*1024);
}
/** Free all storage used to hold cells. */
void
free_cell_pool(void)
{
/* Maybe we haven't called init_cell_pool yet; need to check for it. */
if (cell_pool) {
mp_pool_destroy(cell_pool);
cell_pool = NULL;
}
}
/** Free excess storage in cell pool. */
void
clean_cell_pool(void)
{
tor_assert(cell_pool);
mp_pool_clean(cell_pool, 0, 1);
}
/** Release storage held by <b>cell</b>. */
static INLINE void
packed_cell_free(packed_cell_t *cell)
{
--total_cells_allocated;
mp_pool_release(cell);
}
/** Allocate and return a new packed_cell_t. */
static INLINE packed_cell_t *
packed_cell_alloc(void)
{
++total_cells_allocated;
return mp_pool_get(cell_pool);
}
void
dump_cell_pool_usage(int severity)
{
circuit_t *c;
int n_circs = 0;
int n_cells = 0;
for (c = _circuit_get_global_list(); c; c = c->next) {
n_cells += c->n_conn_cells.n;
if (!CIRCUIT_IS_ORIGIN(c))
n_cells += TO_OR_CIRCUIT(c)->p_conn_cells.n;
++n_circs;
}
log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.",
n_cells, n_circs, total_cells_allocated - n_cells);
mp_pool_log_status(cell_pool, severity);
}
#else
/* ENABLE_CELL_POOL isn't defined: here are some stubs to use tor_malloc()
* and tor_free() instead. */
void
init_cell_pool(void)
{
}
void
free_cell_pool(void)
{
}
void
clean_cell_pool(void)
{
}
static INLINE void
packed_cell_free(packed_cell_t *cell)
{
--total_cells_allocated;
tor_free(cell);
}
static INLINE packed_cell_t *
packed_cell_alloc(void)
{
++total_cells_allocated;
return tor_malloc(sizeof(packed_cell_t));
}
void
dump_cell_pool_usage(int severity)
{
(void) severity;
}
#endif
/** Allocate a new copy of packed <b>cell</b>. */
static INLINE packed_cell_t *
packed_cell_copy(const cell_t *cell)
{
packed_cell_t *c = packed_cell_alloc();
cell_pack(c, cell);
c->next = NULL;
return c;
}
/** Append <b>cell</b> to the end of <b>queue</b>. */
void
cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
{
if (queue->tail) {
tor_assert(!queue->tail->next);
queue->tail->next = cell;
} else {
queue->head = cell;
}
queue->tail = cell;
cell->next = NULL;
++queue->n;
}
/** Append a newly allocated copy of <b>cell</b> to the end of <b>queue</b> */
void
cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell)
{
cell_queue_append(queue, packed_cell_copy(cell));
}
/** Remove and free every cell in <b>queue</b>. */
void
cell_queue_clear(cell_queue_t *queue)
{
packed_cell_t *cell, *next;
cell = queue->head;
while (cell) {
next = cell->next;
packed_cell_free(cell);
cell = next;
}
queue->head = queue->tail = NULL;
queue->n = 0;
}
/** Extract and return the cell at the head of <b>queue</b>; return NULL if
* <b>queue</b> is empty. */
static INLINE packed_cell_t *
cell_queue_pop(cell_queue_t *queue)
{
packed_cell_t *cell = queue->head;
if (!cell)
return NULL;
queue->head = cell->next;
if (cell == queue->tail) {
tor_assert(!queue->head);
queue->tail = NULL;
}
--queue->n;
return cell;
}
/** Return a pointer to the "next_active_on_{n,p}_conn" pointer of <b>circ</b>,
* depending on whether <b>conn</b> matches n_conn or p_conn. */
static INLINE circuit_t **
next_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
{
tor_assert(circ);
tor_assert(conn);
if (conn == circ->n_conn) {
return &circ->next_active_on_n_conn;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
tor_assert(conn == orcirc->p_conn);
return &orcirc->next_active_on_p_conn;
}
}
/** Return a pointer to the "prev_active_on_{n,p}_conn" pointer of <b>circ</b>,
* depending on whether <b>conn</b> matches n_conn or p_conn. */
static INLINE circuit_t **
prev_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
{
tor_assert(circ);
tor_assert(conn);
if (conn == circ->n_conn) {
return &circ->prev_active_on_n_conn;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
tor_assert(conn == orcirc->p_conn);
return &orcirc->prev_active_on_p_conn;
}
}
/** Add <b>circ</b> to the list of circuits with pending cells on
* <b>conn</b>. No effect if <b>circ</b> is already unlinked. */
void
make_circuit_active_on_conn(circuit_t *circ, or_connection_t *conn)
{
circuit_t **nextp = next_circ_on_conn_p(circ, conn);
circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
if (*nextp && *prevp) {
/* Already active. */
return;
}
if (! conn->active_circuits) {
conn->active_circuits = circ;
*prevp = *nextp = circ;
} else {
circuit_t *head = conn->active_circuits;
circuit_t *old_tail = *prev_circ_on_conn_p(head, conn);
*next_circ_on_conn_p(old_tail, conn) = circ;
*nextp = head;
*prev_circ_on_conn_p(head, conn) = circ;
*prevp = old_tail;
}
assert_active_circuits_ok_paranoid(conn);
}
/** Remove <b>circ</b> to the list of circuits with pending cells on
* <b>conn</b>. No effect if <b>circ</b> is already unlinked. */
void
make_circuit_inactive_on_conn(circuit_t *circ, or_connection_t *conn)
{
circuit_t **nextp = next_circ_on_conn_p(circ, conn);
circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
circuit_t *next = *nextp, *prev = *prevp;
if (!next && !prev) {
/* Already inactive. */
return;
}
tor_assert(next && prev);
tor_assert(*prev_circ_on_conn_p(next, conn) == circ);
tor_assert(*next_circ_on_conn_p(prev, conn) == circ);
if (next == circ) {
conn->active_circuits = NULL;
} else {
*prev_circ_on_conn_p(next, conn) = prev;
*next_circ_on_conn_p(prev, conn) = next;
if (conn->active_circuits == circ)
conn->active_circuits = next;
}
*prevp = *nextp = NULL;
assert_active_circuits_ok_paranoid(conn);
}
/** Remove all circuits from the list of circuits with pending cells on
* <b>conn</b>. */
void
connection_or_unlink_all_active_circs(or_connection_t *orconn)
{
circuit_t *head = orconn->active_circuits;
circuit_t *cur = head;
if (! head)
return;
do {
circuit_t *next = *next_circ_on_conn_p(cur, orconn);
*prev_circ_on_conn_p(cur, orconn) = NULL;
*next_circ_on_conn_p(cur, orconn) = NULL;
cur = next;
} while (cur != head);
orconn->active_circuits = NULL;
}
/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
* every edge connection that is using <b>circ</b> to write to <b>orconn</b>,
* and start or stop reading as appropriate. */
static void
set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
int block)
{
edge_connection_t *edge = NULL;
if (circ->n_conn == orconn) {
circ->streams_blocked_on_n_conn = block;
if (CIRCUIT_IS_ORIGIN(circ))
edge = TO_ORIGIN_CIRCUIT(circ)->p_streams;
} else {
circ->streams_blocked_on_p_conn = block;
tor_assert(!CIRCUIT_IS_ORIGIN(circ));
edge = TO_OR_CIRCUIT(circ)->n_streams;
}
for (; edge; edge = edge->next_stream) {
connection_t *conn = TO_CONN(edge);
conn->edge_blocked_on_circ = block;
if (!conn->read_event) {
/* This connection is a placeholder for something; probably a DNS
* request. It can't actually stop or start reading.*/
continue;
}
if (block) {
if (connection_is_reading(conn))
connection_stop_reading(conn);
} else {
/* Is this right? */
if (!connection_is_reading(conn))
connection_start_reading(conn);
}
}
}
/** Pull as many cells as possible (but no more than <b>max</b>) from the
* queue of the first active circuit on <b>conn</b>, and write then to
* <b>conn</b>->outbuf. Return the number of cells written.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -