diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 132da21466..0eb2ba3f67 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -1548,8 +1548,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return connection_exit_begin_conn(cell, circ); case RELAY_COMMAND_DATA: ++stats_n_data_cells_received; - if (( layer_hint && --layer_hint->deliver_window < 0) || - (!layer_hint && --circ->deliver_window < 0)) { + + /* Update our circuit-level deliver window that we received a DATA cell. + * If the deliver window goes below 0, we end the connection due to a + * protocol failure. */ + if (sendme_circuit_data_received(circ, layer_hint) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) circ deliver_window below 0. Killing."); if (conn) { @@ -1560,9 +1563,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } return -END_CIRC_REASON_TORPROTOCOL; } - log_debug(domain,"circ deliver_window now %d.", layer_hint ? - layer_hint->deliver_window : circ->deliver_window); + /* Consider sending a circuit-level SENDME cell. */ sendme_circuit_consider_sending(circ, layer_hint); if (rh.stream_id == 0) { @@ -1586,7 +1588,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } - if (--conn->deliver_window < 0) { /* is it below 0 after decrement? */ + /* Update our stream-level deliver window that we just received a DATA + * cell. Going below 0 means we have a protocol level error so the + * circuit is closed. */ + + if (sendme_stream_data_received(conn) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) conn deliver_window below 0. Killing."); return -END_CIRC_REASON_TORPROTOCOL; diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index df9fc57bd6..6d9f6f7d05 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -180,3 +180,36 @@ sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, conn->package_window); return 0; } + +/* Called when a relay DATA cell is received on the given circuit. If + * layer_hint is NULL, this means we are the Exit end point else we are the + * Client. Update the deliver window and return its new value. */ +int +sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint) +{ + int deliver_window, domain; + + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert(layer_hint); + --layer_hint->deliver_window; + deliver_window = layer_hint->deliver_window; + domain = LD_APP; + } else { + tor_assert(!layer_hint); + --circ->deliver_window; + deliver_window = circ->deliver_window; + domain = LD_EXIT; + } + + log_debug(domain, "Circuit deliver_window now %d.", deliver_window); + return deliver_window; +} + +/* Called when a relay DATA cell is received for the given edge connection + * conn. Update the deliver window and return its new value. */ +int +sendme_stream_data_received(edge_connection_t *conn) +{ + tor_assert(conn); + return --conn->deliver_window; +} diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h index 97748cf65e..6313e91216 100644 --- a/src/core/or/sendme.h +++ b/src/core/or/sendme.h @@ -13,13 +13,19 @@ #include "core/or/crypt_path_st.h" #include "core/or/circuit_st.h" +/* Sending SENDME cell. */ void sendme_connection_edge_consider_sending(edge_connection_t *edge_conn); void sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint); +/* Processing SENDME cell. */ int sendme_process_circuit_level(crypt_path_t *layer_hint, circuit_t *circ, uint16_t cell_body_len); int sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, uint16_t cell_body_len); +/* Update deliver window functions. */ +int sendme_stream_data_received(edge_connection_t *conn); +int sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint); + #endif /* !defined(TOR_SENDME_H) */