From 39ac1db60e8b920e1e6b07e08f7f3343960ece79 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 10 Apr 2013 19:30:41 -0400 Subject: [PATCH] Avoid busy-looping on WANTREAD within connection_handle_write Fix for bug 5650. Also, if we get a WANTREAD while reading while writing, make sure we're reading. --- changes/bug5650 | 5 +++++ src/or/connection.c | 17 ++++++++++++++++- src/or/or.h | 3 +++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 changes/bug5650 diff --git a/changes/bug5650 b/changes/bug5650 new file mode 100644 index 0000000000..401e317074 --- /dev/null +++ b/changes/bug5650 @@ -0,0 +1,5 @@ + o Major bugfixes: + - Avoid a bug where our response to TLS renegotation under certain + network conditions could lead to a busy-loop, with 100% CPU + consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha. + diff --git a/src/or/connection.c b/src/or/connection.c index eac9c4f32b..e366e0e77f 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -2825,7 +2825,20 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, case TOR_TLS_WANTWRITE: connection_start_writing(conn); return 0; - case TOR_TLS_WANTREAD: /* we're already reading */ + case TOR_TLS_WANTREAD: + if (conn->in_connection_handle_write) { + /* We've been invoked from connection_handle_write, because we're + * waiting for a TLS renegotiation, the renegotiation started, and + * SSL_read returned WANTWRITE. But now SSL_read is saying WANTREAD + * again. Stop waiting for write events now, or else we'll + * busy-loop until data arrives for us to read. */ + connection_stop_writing(conn); + if (!connection_is_reading(conn)) + connection_start_reading(conn); + } + /* we're already reading, one hopes */ + result = 0; + break; case TOR_TLS_DONE: /* no data read, so nothing to process */ result = 0; break; /* so we call bucket_decrement below */ @@ -3337,7 +3350,9 @@ connection_handle_write(connection_t *conn, int force) { int res; tor_gettimeofday_cache_clear(); + conn->in_connection_handle_write = 1; res = connection_handle_write_impl(conn, force); + conn->in_connection_handle_write = 0; return res; } diff --git a/src/or/or.h b/src/or/or.h index 51c23d305d..6728b862b5 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -998,6 +998,9 @@ typedef struct connection_t { /** Set to 1 when we're inside connection_flushed_some to keep us from * calling connection_handle_write() recursively. */ unsigned int in_flushed_some:1; + /** True if connection_handle_write is currently running on this connection. + */ + unsigned int in_connection_handle_write:1; /* For linked connections: */