diff options
Diffstat (limited to 'src/or/relay.c')
-rw-r--r-- | src/or/relay.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/src/or/relay.c b/src/or/relay.c index df6d0a8a5..3fa31a3f3 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -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 */ |