close idle tls conns early

This commit is contained in:
Roger Dingledine 2010-04-23 20:23:00 -04:00
parent b264192083
commit 67b38d5068
2 changed files with 59 additions and 46 deletions

View File

@ -0,0 +1,6 @@
o Major bugfixes:
- Make relays more aggressive about closing TLS connections that
have no circuits on them. Tens of thousands of them were piling
up at the fast relays, causing the relays to run out of sockets
and memory. Bugfix on 0.2.0.22-rc (where clients started tunneling
their directory fetches over TLS).

View File

@ -663,6 +663,15 @@ directory_info_has_arrived(time_t now, int from_cache)
consider_testing_reachability(1, 1); consider_testing_reachability(1, 1);
} }
/** How long do we wait before killing OR connections with no circuits?
* In Tor versions up to 0.2.1.25 and 0.2.2.12-alpha, we waited 15 minutes
* before cancelling these connections, which caused fast relays to accrue
* many many idle connections. Hopefully 3 minutes is low enough that
* it kills most idle connections, without being so low that we cause
* clients to bounce on and off.
*/
#define IDLE_OR_CONN_TIMEOUT 180
/** Perform regular maintenance tasks for a single connection. This /** Perform regular maintenance tasks for a single connection. This
* function gets run once per second per connection by run_scheduled_events. * function gets run once per second per connection by run_scheduled_events.
*/ */
@ -673,6 +682,8 @@ run_connection_housekeeping(int i, time_t now)
connection_t *conn = smartlist_get(connection_array, i); connection_t *conn = smartlist_get(connection_array, i);
or_options_t *options = get_options(); or_options_t *options = get_options();
or_connection_t *or_conn; or_connection_t *or_conn;
int past_keepalive =
now >= conn->timestamp_lastwritten + options->KeepalivePeriod;
if (conn->outbuf && !buf_datalen(conn->outbuf) && conn->type == CONN_TYPE_OR) if (conn->outbuf && !buf_datalen(conn->outbuf) && conn->type == CONN_TYPE_OR)
TO_OR_CONN(conn)->timestamp_lastempty = now; TO_OR_CONN(conn)->timestamp_lastempty = now;
@ -707,6 +718,9 @@ run_connection_housekeeping(int i, time_t now)
if (!connection_speaks_cells(conn)) if (!connection_speaks_cells(conn))
return; /* we're all done here, the rest is just for OR conns */ return; /* we're all done here, the rest is just for OR conns */
/* If we haven't written to an OR connection for a while, then either nuke
the connection or send a keepalive, depending. */
or_conn = TO_OR_CONN(conn); or_conn = TO_OR_CONN(conn);
if (or_conn->is_bad_for_new_circs && !or_conn->n_circuits) { if (or_conn->is_bad_for_new_circs && !or_conn->n_circuits) {
@ -721,52 +735,45 @@ run_connection_housekeeping(int i, time_t now)
"Tor gave up on the connection"); "Tor gave up on the connection");
connection_mark_for_close(conn); connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1; conn->hold_open_until_flushed = 1;
return; } else if (past_keepalive && !connection_state_is_open(conn)) {
} /* We never managed to actually get this connection open and happy. */
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
/* If we haven't written to an OR connection for a while, then either nuke conn->s,conn->address, conn->port);
the connection or send a keepalive, depending. */ connection_mark_for_close(conn);
if (now >= conn->timestamp_lastwritten + options->KeepalivePeriod) { conn->hold_open_until_flushed = 1;
int maxCircuitlessPeriod = options->MaxCircuitDirtiness*3/2; } else if (we_are_hibernating() && !or_conn->n_circuits &&
if (!connection_state_is_open(conn)) { !buf_datalen(conn->outbuf)) {
/* We never managed to actually get this connection open and happy. */ /* We're hibernating, there's no circuits, and nothing to flush.*/
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).", log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
conn->s,conn->address, conn->port); "[Hibernating or exiting].",
connection_mark_for_close(conn); conn->s,conn->address, conn->port);
conn->hold_open_until_flushed = 1; connection_mark_for_close(conn);
} else if (we_are_hibernating() && !or_conn->n_circuits && conn->hold_open_until_flushed = 1;
!buf_datalen(conn->outbuf)) { } else if (!or_conn->n_circuits &&
/* We're hibernating, there's no circuits, and nothing to flush.*/ now >= or_conn->timestamp_last_added_nonpadding +
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " IDLE_OR_CONN_TIMEOUT) {
"[Hibernating or exiting].", log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
conn->s,conn->address, conn->port); "[idle %d].", conn->s,conn->address, conn->port,
connection_mark_for_close(conn); (int)(now - or_conn->timestamp_last_added_nonpadding));
conn->hold_open_until_flushed = 1; connection_mark_for_close(conn);
} else if (!or_conn->n_circuits && conn->hold_open_until_flushed = 1;
now >= or_conn->timestamp_last_added_nonpadding + } else if (
maxCircuitlessPeriod) { now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
"[idle].", conn->s,conn->address, conn->port); log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
connection_mark_for_close(conn); "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to "
conn->hold_open_until_flushed = 1; "flush; %d seconds since last write)",
} else if ( conn->s, conn->address, conn->port,
now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 && (int)buf_datalen(conn->outbuf),
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) { (int)(now-conn->timestamp_lastwritten));
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, connection_mark_for_close(conn);
"Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " } else if (past_keepalive && !buf_datalen(conn->outbuf)) {
"flush; %d seconds since last write)", /* send a padding cell */
conn->s, conn->address, conn->port, log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
(int)buf_datalen(conn->outbuf), conn->address, conn->port);
(int)(now-conn->timestamp_lastwritten)); memset(&cell,0,sizeof(cell_t));
connection_mark_for_close(conn); cell.command = CELL_PADDING;
} else if (!buf_datalen(conn->outbuf)) { connection_or_write_cell_to_buf(&cell, or_conn);
/* either in clique mode, or we've got a circuit. send a padding cell. */
log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
conn->address, conn->port);
memset(&cell,0,sizeof(cell_t));
cell.command = CELL_PADDING;
connection_or_write_cell_to_buf(&cell, or_conn);
}
} }
} }