diff --git a/src/or/buffers.c b/src/or/buffers.c index 071edad89d..40d6b04d87 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -132,6 +132,10 @@ buf_t *buf_new() return buf_new_with_capacity(INITIAL_BUF_SIZE); } +void buf_clear(buf_t *buf) +{ + buf->datalen = 0; +} size_t buf_datalen(const buf_t *buf) { diff --git a/src/or/connection.c b/src/or/connection.c index e4b99a4bfa..9c0ac58e14 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -141,6 +141,22 @@ void connection_free_all(void) { connection_free(carray[i]); } +/* Close the underlying socket for conn, so we don't try to flush it. + * Must be used in conjunction with connection_mark_for_close + */ +void connection_close_immediate(connection_t *conn) +{ + assert_connection_ok(conn,0); + if (conn->s < 0) { + log_fn(LOG_WARN,"Attempt to close already-closed connection."); + return; + } + close(conn->s); + conn->s = -1; + buf_clear(conn->outbuf); + conn->outbuf_flushlen = 0; +} + int _connection_mark_for_close(connection_t *conn, char reason) { @@ -355,8 +371,7 @@ static void listener_close_if_present(int type) { type == CONN_TYPE_DIR_LISTENER); conn = connection_get_by_type(type); if (conn) { - close(conn->s); - conn->s = -1; + connection_close_immediate(conn); connection_mark_for_close(conn,0); } } @@ -414,9 +429,7 @@ int connection_handle_read(connection_t *conn) { router_mark_as_down(conn->nickname); } /* There's a read error; kill the connection.*/ - /* XXX This is the place. We need to somehow indicate to - * conn that it should never try to flush, or do anything - * with conn->s but close it. */ + connection_close_immediate(conn); /* Don't flush; connection is dead. */ connection_mark_for_close(conn, END_STREAM_REASON_MISC); return -1; } diff --git a/src/or/main.c b/src/or/main.c index 8e701341d3..2dacb013d9 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -221,10 +221,10 @@ static void conn_close_if_marked(int i) { assert_connection_ok(conn, time(NULL)); if(conn->marked_for_close) { log_fn(LOG_INFO,"Cleaning up connection (fd %d).",conn->s); - if(conn->s >= 0) { /* -1 means it's an incomplete edge connection */ + if(conn->s >= 0) { + /* -1 means it's an incomplete edge connection, or that the socket + * has already been closed as unflushable. */ /* FIXME there's got to be a better way to check for this -- and make other checks? */ -/* XXX the below two calls to flush_buf should not happen if the - * conn got hung up on. */ if(connection_speaks_cells(conn)) { if(conn->state == OR_CONN_STATE_OPEN) flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen); diff --git a/src/or/or.h b/src/or/or.h index 369d0da8b3..0231cbf606 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -549,6 +549,7 @@ int find_on_inbuf(char *string, int string_len, buf_t *buf); buf_t *buf_new(); buf_t *buf_new_with_capacity(size_t size); void buf_free(buf_t *buf); +void buf_clear(buf_t *buf); size_t buf_datalen(const buf_t *buf); size_t buf_capacity(const buf_t *buf); @@ -637,7 +638,7 @@ int getconfig(int argc, char **argv, or_options_t *options); connection_t *connection_new(int type); void connection_free(connection_t *conn); void connection_free_all(void); - +void connection_close_immediate(connection_t *conn); int _connection_mark_for_close(connection_t *conn, char reason); #define connection_mark_for_close(c,r) \