| 
					
				 | 
			
			
				@@ -944,6 +944,12 @@ connection_edge_process_relay_cell_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* This is definitely a success, so forget about any pending data we 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * had sent. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (conn->pending_optimistic_data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      generic_buffer_free(conn->pending_optimistic_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      conn->pending_optimistic_data = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* handle anything that might have queued */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1343,6 +1349,10 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char payload[CELL_PAYLOAD_SIZE]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circuit_t *circ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int sending_from_optimistic = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const int sending_optimistically = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->_base.type == CONN_TYPE_AP && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    conn->_base.state != AP_CONN_STATE_OPEN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1375,7 +1385,18 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  amount_to_process = connection_get_inbuf_len(TO_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  sending_from_optimistic = conn->sending_optimistic_data != NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (PREDICT_UNLIKELY(sending_from_optimistic)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    amount_to_process = generic_buffer_len(conn->sending_optimistic_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (PREDICT_UNLIKELY(!amount_to_process)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_BUG, "sending_optimistic_data was non-NULL but empty"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      amount_to_process = connection_get_inbuf_len(TO_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      sending_from_optimistic = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    amount_to_process = connection_get_inbuf_len(TO_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!amount_to_process) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1391,11 +1412,30 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   stats_n_data_bytes_packaged += length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   stats_n_data_cells_packaged += 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  connection_fetch_from_buf(payload, length, TO_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (PREDICT_UNLIKELY(sending_from_optimistic)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* XXX023 We could be more efficient here by sometimes packing 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * previously-sent optimistic data in the same cell with data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * from the inbuf. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    generic_buffer_get(conn->sending_optimistic_data, payload, length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!generic_buffer_len(conn->sending_optimistic_data)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        generic_buffer_free(conn->sending_optimistic_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conn->sending_optimistic_data = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    connection_fetch_from_buf(payload, length, TO_CONN(conn)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             (int)length, (int)connection_get_inbuf_len(TO_CONN(conn))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (sending_optimistically && !sending_from_optimistic) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* This is new optimistic data; remember it in case we need to detach and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       retry */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!conn->pending_optimistic_data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      conn->pending_optimistic_data = generic_buffer_new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    generic_buffer_add(conn->pending_optimistic_data, payload, length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (connection_edge_send_command(conn, RELAY_COMMAND_DATA, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    payload, length) < 0 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* circuit got marked for close, don't continue, don't need to mark conn */ 
			 |