Commit b2c2cb92 authored by George Kadianakis's avatar George Kadianakis
Browse files

Merge branch 'tor-github/pr/986'

parents 4d461e20 562bcbcf
o Major features (flow control):
- Implement authenticated SENDMEs detailed in proposal 289. A SENDME cell
now includes the digest of the last cell received so once the end point
receives the SENDME, it can confirm the other side's knowledge of the
previous cells that were sent. This behavior is controlled by two new
consensus parameters, see proposal for more details. Fixes ticket 26288.
......@@ -85,7 +85,7 @@ problem function-size /src/core/or/circuitbuild.c:circuit_extend() 147
problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 206
problem include-count /src/core/or/circuitlist.c 54
problem function-size /src/core/or/circuitlist.c:HT_PROTOTYPE() 128
problem function-size /src/core/or/circuitlist.c:circuit_free_() 137
problem function-size /src/core/or/circuitlist.c:circuit_free_() 143
problem function-size /src/core/or/circuitlist.c:circuit_find_to_cannibalize() 102
problem function-size /src/core/or/circuitlist.c:circuit_about_to_free() 120
problem function-size /src/core/or/circuitlist.c:circuits_handle_oom() 117
......@@ -102,8 +102,8 @@ problem function-size /src/core/or/circuituse.c:circuit_get_open_circ_or_launch(
problem function-size /src/core/or/circuituse.c:connection_ap_handshake_attach_circuit() 244
problem function-size /src/core/or/command.c:command_process_create_cell() 156
problem function-size /src/core/or/command.c:command_process_relay_cell() 132
problem file-size /src/core/or/connection_edge.c 4575
problem include-count /src/core/or/connection_edge.c 64
problem file-size /src/core/or/connection_edge.c 4595
problem include-count /src/core/or/connection_edge.c 65
problem function-size /src/core/or/connection_edge.c:connection_ap_expire_beginning() 117
problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_rewrite() 192
problem function-size /src/core/or/connection_edge.c:connection_ap_handle_onion() 188
......@@ -122,11 +122,11 @@ problem function-size /src/core/or/policies.c:policy_summarize() 107
problem function-size /src/core/or/protover.c:protover_all_supported() 117
problem file-size /src/core/or/relay.c 3173
problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 123
problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 101
problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 112
problem function-size /src/core/or/relay.c:connection_ap_process_end_not_open() 194
problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell_not_open() 139
problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell() 520
problem function-size /src/core/or/relay.c:connection_edge_package_raw_inbuf() 130
problem function-size /src/core/or/relay.c:connection_edge_package_raw_inbuf() 132
problem function-size /src/core/or/relay.c:circuit_resume_edge_reading_helper() 148
problem function-size /src/core/or/scheduler_kist.c:kist_scheduler_run() 171
problem function-size /src/core/or/scheduler_vanilla.c:vanilla_scheduler_run() 109
......
......@@ -12,6 +12,7 @@
#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
#include "core/or/relay.h"
#include "core/crypto/relay_crypto.h"
#include "core/or/sendme.h"
#include "core/or/cell_st.h"
#include "core/or/or_circuit_st.h"
......@@ -90,6 +91,23 @@ relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
}
/** Return the sendme_digest within the <b>crypto</b> object. */
uint8_t *
relay_crypto_get_sendme_digest(relay_crypto_t *crypto)
{
tor_assert(crypto);
return crypto->sendme_digest;
}
/** Record the b_digest from <b>crypto</b> and put it in the sendme_digest. */
void
relay_crypto_record_sendme_digest(relay_crypto_t *crypto)
{
tor_assert(crypto);
crypto_digest_get_digest(crypto->b_digest, (char *) crypto->sendme_digest,
sizeof(crypto->sendme_digest));
}
/** Do the appropriate en/decryptions for <b>cell</b> arriving on
* <b>circ</b> in direction <b>cell_direction</b>.
*
......@@ -142,6 +160,11 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell,
if (relay_digest_matches(thishop->crypto.b_digest, cell)) {
*recognized = 1;
*layer_hint = thishop;
/* This cell is for us. Keep a record of this cell because we will
* use it in the next SENDME cell. */
if (sendme_circuit_cell_is_next(thishop->deliver_window)) {
sendme_circuit_record_inbound_cell(thishop);
}
return 0;
}
}
......@@ -212,6 +235,13 @@ relay_encrypt_cell_inbound(cell_t *cell,
or_circuit_t *or_circ)
{
relay_set_digest(or_circ->crypto.b_digest, cell);
/* We are about to send this cell outbound on the circuit. Keep a record of
* this cell if we are expecting that the next cell is a SENDME. */
if (sendme_circuit_cell_is_next(TO_CIRCUIT(or_circ)->package_window)) {
sendme_circuit_record_outbound_cell(or_circ);
}
/* encrypt one layer */
relay_crypt_one_payload(or_circ->crypto.b_crypto, cell->payload);
}
......
......@@ -27,5 +27,8 @@ void relay_crypto_clear(relay_crypto_t *crypto);
void relay_crypto_assert_ok(const relay_crypto_t *crypto);
uint8_t *relay_crypto_get_sendme_digest(relay_crypto_t *crypto);
void relay_crypto_record_sendme_digest(relay_crypto_t *crypto);
#endif /* !defined(TOR_RELAY_CRYPTO_H) */
......@@ -54,6 +54,7 @@ LIBTOR_APP_A_SOURCES = \
src/core/or/scheduler.c \
src/core/or/scheduler_kist.c \
src/core/or/scheduler_vanilla.c \
src/core/or/sendme.c \
src/core/or/status.c \
src/core/or/versions.c \
src/core/proto/proto_cell.c \
......@@ -274,6 +275,7 @@ noinst_HEADERS += \
src/core/or/relay.h \
src/core/or/relay_crypto_st.h \
src/core/or/scheduler.h \
src/core/or/sendme.h \
src/core/or/server_port_cfg_st.h \
src/core/or/socks_request_st.h \
src/core/or/status.h \
......
......@@ -104,6 +104,26 @@ struct circuit_t {
* circuit-level sendme cells to indicate that we're willing to accept
* more. */
int deliver_window;
/** FIFO containing the digest of the cells that are just before a SENDME is
* sent by the client. It is done at the last cell before our package_window
* goes down to 0 which is when we expect a SENDME.
*
* Our current circuit package window is capped to 1000
* (CIRCWINDOW_START_MAX) which is also the start value. The increment is
* set to 100 (CIRCWINDOW_INCREMENT) which means we don't allow more than
* 1000/100 = 10 outstanding SENDME cells worth of data. Meaning that this
* list can not contain more than 10 digests of DIGEST_LEN bytes (20).
*
* At position i in the list, the digest corresponds to the
* ((CIRCWINDOW_INCREMENT * i) - 1)-nth cell received since we expect the
* (CIRCWINDOW_INCREMENT * i)-nth cell to be the SENDME and thus containing
* the previous cell digest.
*
* For example, position 2 (starting at 0) means that we've received 299
* cells and the 299th cell digest is kept at index 2.
*
* At maximum, this list contains 200 bytes plus the smartlist overhead. */
smartlist_t *sendme_last_digests;
/** Temporary field used during circuits_handle_oom. */
uint32_t age_tmp;
......
......@@ -1227,6 +1227,12 @@ circuit_free_(circuit_t *circ)
* "active" checks will be violated. */
cell_queue_clear(&circ->n_chan_cells);
/* Cleanup possible SENDME state. */
if (circ->sendme_last_digests) {
SMARTLIST_FOREACH(circ->sendme_last_digests, uint8_t *, d, tor_free(d));
smartlist_free(circ->sendme_last_digests);
}
log_info(LD_CIRC, "Circuit %u (id: %" PRIu32 ") has been freed.",
n_circ_id,
CIRCUIT_IS_ORIGIN(circ) ?
......
......@@ -73,6 +73,7 @@
#include "core/or/policies.h"
#include "core/or/reasons.h"
#include "core/or/relay.h"
#include "core/or/sendme.h"
#include "core/proto/proto_http.h"
#include "core/proto/proto_socks.h"
#include "feature/client/addressmap.h"
......@@ -767,7 +768,7 @@ connection_edge_flushed_some(edge_connection_t *conn)
/* falls through. */
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
sendme_connection_edge_consider_sending(conn);
break;
}
return 0;
......@@ -791,7 +792,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
switch (conn->base_.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
sendme_connection_edge_consider_sending(conn);
return 0;
case AP_CONN_STATE_SOCKS_WAIT:
case AP_CONN_STATE_NATD_WAIT:
......@@ -4564,6 +4565,25 @@ circuit_clear_isolation(origin_circuit_t *circ)
circ->socks_username_len = circ->socks_password_len = 0;
}
/** Send an END and mark for close the given edge connection conn using the
* given reason that has to be a stream reason.
*
* Note: We don't unattached the AP connection (if applicable) because we
* don't want to flush the remaining data. This function aims at ending
* everything quickly regardless of the connection state.
*
* This function can't fail and does nothing if conn is NULL. */
void
connection_edge_end_close(edge_connection_t *conn, uint8_t reason)
{
if (!conn) {
return;
}
connection_edge_end(conn, reason);
connection_mark_for_close(TO_CONN(conn));
}
/** Free all storage held in module-scoped variables for connection_edge.c */
void
connection_edge_free_all(void)
......
......@@ -80,6 +80,7 @@ int connection_edge_process_inbuf(edge_connection_t *conn,
int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn);
int connection_edge_end(edge_connection_t *conn, uint8_t reason);
int connection_edge_end_errno(edge_connection_t *conn);
void connection_edge_end_close(edge_connection_t *conn, uint8_t reason);
int connection_edge_flushed_some(edge_connection_t *conn);
int connection_edge_finished_flushing(edge_connection_t *conn);
int connection_edge_finished_connecting(edge_connection_t *conn);
......
......@@ -93,13 +93,12 @@
#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "core/or/socks_request_st.h"
#include "core/or/sendme.h"
static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
crypt_path_t *layer_hint);
static void circuit_consider_sending_sendme(circuit_t *circ,
crypt_path_t *layer_hint);
static void circuit_resume_edge_reading(circuit_t *circ,
crypt_path_t *layer_hint);
static int circuit_resume_edge_reading_helper(edge_connection_t *conn,
......@@ -530,6 +529,60 @@ relay_command_to_string(uint8_t command)
}
}
/** Return the offset where the padding should start. The <b>data_len</b> is
* the relay payload length expected to be put in the cell. It can not be
* bigger than RELAY_PAYLOAD_SIZE else this function assert().
*
* Value will always be smaller than CELL_PAYLOAD_SIZE because this offset is
* for the entire cell length not just the data payload length. Zero is
* returned if there is no room for padding.
*
* This function always skips the first 4 bytes after the payload because
* having some unused zero bytes has saved us a lot of times in the past. */
STATIC size_t
get_pad_cell_offset(size_t data_len)
{
/* This is never suppose to happen but in case it does, stop right away
* because if tor is tricked somehow into not adding random bytes to the
* payload with this function returning 0 for a bad data_len, the entire
* authenticated SENDME design can be bypassed leading to bad denial of
* service attacks. */
tor_assert(data_len <= RELAY_PAYLOAD_SIZE);
/* If the offset is larger than the cell payload size, we return an offset
* of zero indicating that no padding needs to be added. */
size_t offset = RELAY_HEADER_SIZE + data_len + 4;
if (offset >= CELL_PAYLOAD_SIZE) {
return 0;
}
return offset;
}
/* Add random bytes to the unused portion of the payload, to foil attacks
* where the other side can predict all of the bytes in the payload and thus
* compute the authenticated SENDME cells without seeing the traffic. See
* proposal 289. */
static void
pad_cell_payload(uint8_t *cell_payload, size_t data_len)
{
size_t pad_offset, pad_len;
tor_assert(cell_payload);
pad_offset = get_pad_cell_offset(data_len);
if (pad_offset == 0) {
/* We can't add padding so we are done. */
return;
}
/* Remember here that the cell_payload is the length of the header and
* payload size so we offset it using the full lenght of the cell. */
pad_len = CELL_PAYLOAD_SIZE - pad_offset;
crypto_fast_rng_getbytes(get_thread_fast_rng(),
cell_payload + pad_offset, pad_len);
}
/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and send
* it onto the open circuit <b>circ</b>. <b>stream_id</b> is the ID on
* <b>circ</b> for the stream that's sending the relay cell, or 0 if it's a
......@@ -573,6 +626,9 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
if (payload_len)
memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len);
/* Add random padding to the cell if we can. */
pad_cell_payload(cell.payload, payload_len);
log_debug(LD_OR,"delivering %d cell %s.", relay_command,
cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
......@@ -640,6 +696,14 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
return -1;
}
/* If applicable, note the cell digest for the SENDME version 1 purpose if
* we need to. This call needs to be after the circuit_package_relay_cell()
* because the cell digest is set within that function. */
if (relay_command == RELAY_COMMAND_DATA) {
sendme_record_cell_digest(circ);
}
return 0;
}
......@@ -1429,6 +1493,81 @@ connection_edge_process_relay_cell_not_open(
// return -1;
}
/** Process a SENDME cell that arrived on <b>circ</b>. If it is a stream level
* cell, it is destined for the given <b>conn</b>. If it is a circuit level
* cell, it is destined for the <b>layer_hint</b>. The <b>domain</b> is the
* logging domain that should be used.
*
* Return 0 if everything went well or a negative value representing a circuit
* end reason on error for which the caller is responsible for closing it. */
static int
process_sendme_cell(const relay_header_t *rh, const cell_t *cell,
circuit_t *circ, edge_connection_t *conn,
crypt_path_t *layer_hint, int domain)
{
int ret;
tor_assert(rh);
if (!rh->stream_id) {
/* Circuit level SENDME cell. */
ret = sendme_process_circuit_level(layer_hint, circ,
cell->payload + RELAY_HEADER_SIZE,
rh->length);
if (ret < 0) {
return ret;
}
/* Resume reading on any streams now that we've processed a valid
* SENDME cell that updated our package window. */
circuit_resume_edge_reading(circ, layer_hint);
/* We are done, the rest of the code is for the stream level. */
return 0;
}
/* No connection, might be half edge state. We are done if so. */
if (!conn) {
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_sendme(ocirc->half_streams,
rh->stream_id)) {
circuit_read_valid_data(ocirc, rh->length);
log_info(domain, "Sendme cell on circ %u valid on half-closed "
"stream id %d",
ocirc->global_identifier, rh->stream_id);
}
}
log_info(domain, "SENDME cell dropped, unknown stream (streamid %d).",
rh->stream_id);
return 0;
}
/* Stream level SENDME cell. */
ret = sendme_process_stream_level(conn, circ, rh->length);
if (ret < 0) {
/* Means we need to close the circuit with reason ret. */
return ret;
}
/* We've now processed properly a SENDME cell, all windows have been
* properly updated, we'll read on the edge connection to see if we can
* get data out towards the end point (Exit or client) since we are now
* allowed to deliver more cells. */
if (circuit_queue_streams_are_blocked(circ)) {
/* Still waiting for queue to flush; don't touch conn */
return 0;
}
connection_start_reading(TO_CONN(conn));
/* handle whatever might still be on the inbuf */
if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) {
/* (We already sent an end cell if possible) */
connection_mark_for_close(TO_CONN(conn));
return 0;
}
return 0;
}
/** An incoming relay cell has arrived on circuit <b>circ</b>. If
* <b>conn</b> is NULL this is a control cell, else <b>cell</b> is
* destined for <b>conn</b>.
......@@ -1549,22 +1688,19 @@ 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 circuit and stream 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) {
/* XXXX Do we actually need to do this? Will killing the circuit
* not send an END and mark the stream for close as appropriate? */
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
connection_mark_for_close(TO_CONN(conn));
}
connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL);
return -END_CIRC_REASON_TORPROTOCOL;
}
log_debug(domain,"circ deliver_window now %d.", layer_hint ?
layer_hint->deliver_window : circ->deliver_window);
circuit_consider_sending_sendme(circ, layer_hint);
/* Consider sending a circuit-level SENDME cell. */
sendme_circuit_consider_sending(circ, layer_hint);
if (rh.stream_id == 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero "
......@@ -1587,9 +1723,14 @@ 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
* stream and circuit are closed. */
if (sendme_stream_data_received(conn) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"(relay data) conn deliver_window below 0. Killing.");
connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL);
return -END_CIRC_REASON_TORPROTOCOL;
}
/* Total all valid application bytes delivered */
......@@ -1615,7 +1756,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* Only send a SENDME if we're not getting optimistic data; otherwise
* a SENDME could arrive before the CONNECTED.
*/
connection_edge_consider_sending_sendme(conn);
sendme_connection_edge_consider_sending(conn);
}
return 0;
......@@ -1808,99 +1949,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
(unsigned)circ->n_circ_id, rh.stream_id);
return 0;
case RELAY_COMMAND_SENDME:
if (!rh.stream_id) {
if (layer_hint) {
if (layer_hint->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600);
log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL,
"Unexpected sendme cell from exit relay. "
"Closing circ.");
return -END_CIRC_REASON_TORPROTOCOL;
}
layer_hint->package_window += CIRCWINDOW_INCREMENT;
log_debug(LD_APP,"circ-level sendme at origin, packagewindow %d.",
layer_hint->package_window);
circuit_resume_edge_reading(circ, layer_hint);
/* We count circuit-level sendme's as valid delivered data because
* they are rate limited.
*/
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ),
rh.length);
}
} else {
if (circ->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600);
log_fn_ratelim(&client_warn_ratelim,LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Unexpected sendme cell from client. "
"Closing circ (window %d).",
circ->package_window);
return -END_CIRC_REASON_TORPROTOCOL;
}
circ->package_window += CIRCWINDOW_INCREMENT;
log_debug(LD_APP,
"circ-level sendme at non-origin, packagewindow %d.",
circ->package_window);
circuit_resume_edge_reading(circ, layer_hint);
}
return 0;
}
if (!conn) {
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_sendme(ocirc->half_streams,
rh.stream_id)) {
circuit_read_valid_data(ocirc, rh.length);
log_info(domain,
"sendme cell on circ %u valid on half-closed "
"stream id %d", ocirc->global_identifier, rh.stream_id);
}
}
log_info(domain,"sendme cell dropped, unknown stream (streamid %d).",
rh.stream_id);
return 0;
}
/* Don't allow the other endpoint to request more than our maximum
* (i.e. initial) stream SENDME window worth of data. Well-behaved
* stock clients will not request more than this max (as per the check
* in the while loop of connection_edge_consider_sending_sendme()).
*/
if (conn->package_window + STREAMWINDOW_INCREMENT >
STREAMWINDOW_START_MAX) {
static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600);
log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Unexpected stream sendme cell. Closing circ (window %d).",
conn->package_window);
return -END_CIRC_REASON_TORPROTOCOL;
}
/* At this point, the stream sendme is valid */
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ),
rh.length);
}
conn->package_window += STREAMWINDOW_INCREMENT;
log_debug(domain,"stream-level sendme, packagewindow now %d.",
conn->package_window);
if (circuit_queue_streams_are_blocked(circ)) {
/* Still waiting for queue to flush; don't touch conn */
return 0;
}
connection_start_reading(TO_CONN(conn));
/* handle whatever might still be on the inbuf */
if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) {
/* (We already sent an end cell if possible) */
connection_mark_for_close(TO_CONN(conn));
return 0;
}
return 0;
return process_sendme_cell(&rh, cell, circ, conn, layer_hint, domain);
case RELAY_COMMAND_RESOLVE:
if (layer_hint) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
......@@ -2091,15 +2140,17 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
return 0;
}
if (!cpath_layer) { /* non-rendezvous exit */
tor_assert(circ->package_window > 0);
circ->package_window--;
} else { /* we're an AP, or an exit on a rendezvous circ */
tor_assert(cpath_layer->package_window > 0);
cpath_layer->package_window--;
/* Handle the circuit-level SENDME package window. */
if (sendme_note_circuit_data_packaged(circ, cpath_layer) < 0) {
/* Package window has gone under 0. Protocol issue. */
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Circuit package window is below 0. Closing circuit.");
conn->end_reason = END_STREAM_REASON_TORPROTOCOL;
return -1;
}
if (--conn->package_window <= 0) { /* is it 0 after decrement? */
/* Handle the stream-level SENDME package window. */
if (sendme_note_stream_data_packaged(conn) < 0) {
connection_stop_reading(TO_CONN(conn));
log_debug(domain,"conn->package_window reached 0.");
circuit_consider_stop_edge_reading(circ, cpath_layer);
......@@ -2117,42 +2168,6 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
goto repeat_connection_edge_package_raw_inbuf;
}
/** Called when we've just received a relay data cell, when
* we've just finished flushing all bytes to stream <b>conn</b>,
* or when we've flushed *some* bytes to the stream <b>conn</b>.
*
* If conn->outbuf is not too full, and our deliver window is
* low, send back a suitable number of stream-level sendme cells.
*/
void
connection_edge_consider_sending_sendme(edge_connection_t *conn)
{
circuit_t *circ;
if (connection_outbuf_too_full(TO_CONN(conn)))
return;
circ = circuit_get_by_edge_conn(conn);
if (!circ) {
/* this can legitimately happen if the destroy has already
* arrived and torn down the circuit */
log_info(LD_APP,"No circuit associated with conn. Skipping.");
return;
}
while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
"Outbuf %d, Queuing stream sendme.",
(int)conn->base_.outbuf_flushlen);
conn->deliver_window += STREAMWINDOW_INCREMENT;
if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
NULL, 0) < 0) {
log_warn(LD_APP,"connection_edge_send_command failed. Skipping.");
return; /* the circuit's closed, don't continue */
}
}
}