Browse Source

Send END cells on bufferevent tunneled directory conns

Our old code correctly called bufferevent_flush() on linked
connections to make sure that the other side got an EOF event... but
it didn't call bufferevent_flush() when the connection wasn't
hold_open_until_flushed.  Directory connections don't use
hold_open_until_flushed, so the linked exit connection never got an
EOF, so they never sent a RELAY_END cell to the client, and the
client never concluded that data had arrived.

The solution is to make the bufferevent_flush() code apply to _all_
closing linked conns whose partner is not already marked for close.
Nick Mathewson 13 years ago
parent
commit
cbda016bc5
1 changed files with 9 additions and 4 deletions
  1. 9 4
      src/or/main.c

+ 9 - 4
src/or/main.c

@@ -231,6 +231,8 @@ connection_add_impl(connection_t *conn, int is_connecting)
         conn->linked_conn->bufev = pair[1];
       } /* else the other side already was added, and got a bufferevent_pair */
       connection_configure_bufferevent_callbacks(conn);
+    } else {
+      tor_assert(!conn->linked);
     }
 
     if (conn->bufev && conn->inbuf) {
@@ -722,14 +724,17 @@ conn_close_if_marked(int i)
   /* assert_all_pending_dns_resolves_ok(); */
 
 #ifdef USE_BUFFEREVENTS
-  if (conn->bufev && conn->hold_open_until_flushed) {
-    if (conn->linked) {
+  if (conn->bufev) {
+    if (conn->hold_open_until_flushed &&
+        evbuffer_get_length(bufferevent_get_output(conn->bufev))) {
+      /* don't close yet. */
+      return 0;
+    }
+    if (conn->linked_conn && ! conn->linked_conn->marked_for_close) {
       /* We need to do this explicitly so that the linked connection
        * notices that there was an EOF. */
       bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED);
     }
-    if (evbuffer_get_length(bufferevent_get_output(conn->bufev)))
-      return 0;
   }
 #endif