Przeglądaj źródła

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.
Nick Mathewson 11 lat temu
rodzic
commit
39ac1db60e
3 zmienionych plików z 24 dodań i 1 usunięć
  1. 5 0
      changes/bug5650
  2. 16 1
      src/or/connection.c
  3. 3 0
      src/or/or.h

+ 5 - 0
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.
+

+ 16 - 1
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;
 }
 

+ 3 - 0
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:
    */