|  | @@ -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 */
 |