aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2013-04-10 19:30:41 -0400
committerNick Mathewson <nickm@torproject.org>2013-04-12 01:11:31 -0400
commit39ac1db60e8b920e1e6b07e08f7f3343960ece79 (patch)
tree9d934519662d30f52baaa84d844236910ffc8170
parent9630fb917f3549b3fcbd4a3885e0c47f4be9be36 (diff)
downloadtor-39ac1db60e8b920e1e6b07e08f7f3343960ece79.tar.gz
tor-39ac1db60e8b920e1e6b07e08f7f3343960ece79.zip
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.
-rw-r--r--changes/bug56505
-rw-r--r--src/or/connection.c17
-rw-r--r--src/or/or.h3
3 files changed, 24 insertions, 1 deletions
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:
*/