| 
					
				 | 
			
			
				@@ -74,6 +74,10 @@ static connection_t *connection_array[MAXCONNECTIONS+1] = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** List of connections that have been marked for close and need to be freed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * and removed from connection_array. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static smartlist_t *closeable_connection_lst = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** DOCDOC */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static smartlist_t *active_linked_connection_lst = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** DOCDOC */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int called_loop_once = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int n_conns=0; /**< Number of connections currently active. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -155,7 +159,7 @@ int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 connection_add(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  tor_assert(conn->s >= 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(conn->s >= 0 || conn->linked); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->conn_array_index == -1); /* can only connection_add once */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (n_conns == MAXCONNECTIONS) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -198,13 +202,12 @@ connection_remove(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->conn_array_index >= 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   current_index = conn->conn_array_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  connection_unregister_events(conn); /* This is redundant, but cheap. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (current_index == n_conns-1) { /* this is the end */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     n_conns--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  connection_unregister(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* replace this one with the one at the end */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   n_conns--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   connection_array[current_index] = connection_array[n_conns]; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -213,23 +216,31 @@ connection_remove(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** If it's an edge conn, remove it from the list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** If <b>conn</b> is an edge conn, remove it from the list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * of conn's on this circuit. If it's not on an edge, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * flush and send destroys for all circuits on this conn. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * If <b>remove</b> is non-zero, then remove it from the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * connection_array and closeable_connection_lst. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Remove it from connection_array (if applicable) and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * from closeable_connection_list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Then free it. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-connection_unlink(connection_t *conn, int remove) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+connection_unlink(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   connection_about_to_close_connection(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (remove) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->conn_array_index >= 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     connection_remove(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked_conn) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->linked_conn->linked_conn = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (! conn->linked_conn->marked_for_close && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conn->linked_conn->reading_from_linked_conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_start_reading(conn->linked_conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->linked_conn = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_remove(closeable_connection_lst, conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_remove(active_linked_connection_lst, conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (conn->type == CONN_TYPE_EXIT) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -286,16 +297,23 @@ get_connection_array(connection_t ***array, int *n) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 connection_watch_events(connection_t *conn, short events) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int r = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->read_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->write_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (events & EV_READ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    r = event_add(conn->read_event, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (events & EV_READ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_start_reading(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_stop_reading(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    r = event_del(conn->read_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (events & EV_READ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      r = event_add(conn->read_event, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      r = event_del(conn->read_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (r<0) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -305,10 +323,17 @@ connection_watch_events(connection_t *conn, short events) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              conn->s, (events & EV_READ)?"":"un", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (events & EV_WRITE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    r = event_add(conn->write_event, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (events & EV_WRITE) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_start_writing(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_stop_writing(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    r = event_del(conn->write_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (events & EV_WRITE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      r = event_add(conn->write_event, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      r = event_del(conn->write_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (r<0) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -325,7 +350,8 @@ connection_is_reading(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return conn->read_event && event_pending(conn->read_event, EV_READ, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return conn->reading_from_linked_conn || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (conn->read_event && event_pending(conn->read_event, EV_READ, NULL)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Tell the main loop to stop notifying <b>conn</b> of any read events. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -335,12 +361,16 @@ connection_stop_reading(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->read_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  log_debug(LD_NET,"entering."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (event_del(conn->read_event)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_NET, "Error from libevent setting read event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "to unwatched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->reading_from_linked_conn = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    connection_stop_reading_from_linked_conn(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (event_del(conn->read_event)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_NET, "Error from libevent setting read event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "to unwatched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Tell the main loop to start notifying <b>conn</b> of any read events. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -350,11 +380,17 @@ connection_start_reading(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->read_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (event_add(conn->read_event, NULL)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_NET, "Error from libevent setting read event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "to watched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->reading_from_linked_conn = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (connection_should_read_from_linked_conn(conn)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_start_reading_from_linked_conn(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (event_add(conn->read_event, NULL)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_NET, "Error from libevent setting read event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "to watched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Return true iff <b>conn</b> is listening for write events. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -363,7 +399,8 @@ connection_is_writing(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return conn->writing_to_linked_conn || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Tell the main loop to stop notifying <b>conn</b> of any write events. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -373,11 +410,17 @@ connection_stop_writing(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->write_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (event_del(conn->write_event)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_NET, "Error from libevent setting write event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "to unwatched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->writing_to_linked_conn = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (conn->linked_conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_stop_reading_from_linked_conn(conn->linked_conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (event_del(conn->write_event)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_NET, "Error from libevent setting write event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "to unwatched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Tell the main loop to start notifying <b>conn</b> of any write events. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -387,11 +430,58 @@ connection_start_writing(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn->write_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (event_add(conn->write_event, NULL)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_NET, "Error from libevent setting write event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "to watched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->linked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->writing_to_linked_conn = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (conn->linked_conn && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        connection_should_read_from_linked_conn(conn->linked_conn)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_start_reading_from_linked_conn(conn->linked_conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (event_add(conn->write_event, NULL)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_NET, "Error from libevent setting write event state for %d " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "to watched: %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               conn->s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               tor_socket_strerror(tor_socket_errno(conn->s))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** DOCDOC*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+connection_start_reading_from_linked_conn(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(conn->linked == 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!conn->active_on_link) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->active_on_link = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    smartlist_add(active_linked_connection_lst, conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!called_loop_once) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* This is the first event on the list; we won't be in LOOP_ONCE mode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * so we need to make sure that the event_loop() actually exits at the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * end of its run through the current connections and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * lets us activate read events for linked connections.  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      struct timeval tv = { 0, 0 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      event_loopexit(&tv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_assert(smartlist_isin(active_linked_connection_lst, conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** DOCDOC*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+connection_stop_reading_from_linked_conn(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(conn->linked == 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (conn->active_on_link) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->active_on_link = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* XXXX020 maybe we should keep an index here so we can smartlist_del 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * cleanly. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    smartlist_remove(active_linked_connection_lst, conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_assert(!smartlist_isin(active_linked_connection_lst, conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Close all connections that have been scheduled to get closed */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -402,7 +492,7 @@ close_closeable_connections(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (i = 0; i < smartlist_len(closeable_connection_lst); ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     connection_t *conn = smartlist_get(closeable_connection_lst, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (conn->conn_array_index < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      connection_unlink(conn, 0); /* blow it away right now */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      connection_unlink(conn); /* blow it away right now */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (!conn_close_if_marked(conn->conn_array_index)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ++i; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -500,7 +590,7 @@ conn_close_if_marked(int i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   assert_all_pending_dns_resolves_ok(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (conn->s >= 0 && connection_wants_to_flush(conn)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if ((conn->s >= 0 || conn->linked_conn) && connection_wants_to_flush(conn)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* s == -1 means it's an incomplete edge connection, or that the socket 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * has already been closed as unflushable. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int sz = connection_bucket_write_limit(conn); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -512,7 +602,21 @@ conn_close_if_marked(int i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                conn->s, conn_type_to_string(conn->type), conn->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                (int)conn->outbuf_flushlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 conn->marked_for_close_file, conn->marked_for_close); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (connection_speaks_cells(conn)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (conn->linked_conn) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      retval = move_buf_to_buf(conn->linked_conn->inbuf, conn->outbuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               &conn->outbuf_flushlen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (retval >= 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* The linked conn will notice that it has data when it notices that 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * we're gone. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        connection_start_reading_from_linked_conn(conn->linked_conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* XXXX020 Downgrade to debug. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_info(LD_GENERAL, "Flushed last %d bytes from a linked conn; " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "%d left; flushlen %d; wants-to-flush==%d", retval, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               (int)buf_datalen(conn->outbuf), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               (int)conn->outbuf_flushlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               connection_wants_to_flush(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (connection_speaks_cells(conn)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (conn->state == OR_CONN_STATE_OPEN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                &conn->outbuf_flushlen); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -553,7 +657,7 @@ conn_close_if_marked(int i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              conn->marked_for_close); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  connection_unlink(conn, 1); /* unlink, remove, free */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  connection_unlink(conn); /* unlink, remove, free */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1270,8 +1374,14 @@ do_main_loop(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* Make it easier to tell whether libevent failure is our fault or not. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     errno = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* poll until we have an event, or the second ends */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    loop_result = event_dispatch(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* All active linked conns should get their read events activated. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      event_active(conn->read_event, EV_READ, 1)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* poll until we have an event, or the second ends, or until we have 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * some active linked connections to triggger events for. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    loop_result = event_loop(called_loop_once ? EVLOOP_ONCE : 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* let catch() handle things like ^c, and otherwise don't worry about it */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (loop_result < 0) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1601,6 +1711,8 @@ tor_init(int argc, char *argv[]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   time_of_process_start = time(NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!closeable_connection_lst) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     closeable_connection_lst = smartlist_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!active_linked_connection_lst) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    active_linked_connection_lst = smartlist_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Initialize the history structures. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   rep_hist_init(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Initialize the service cache. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1673,6 +1785,7 @@ tor_free_all(int postfork) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_tls_free_all(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* stuff in main.c */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_free(closeable_connection_lst); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_free(active_linked_connection_lst); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_free(timeout_event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Stuff in util.c */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   escaped(NULL); 
			 |