summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-05-14 14:25:07 -0400
committerNick Mathewson <nickm@torproject.org>2018-05-14 14:25:07 -0400
commita394a2dd86579495797432114f62ea3265ed5ed0 (patch)
tree90da2ee5c31e850fb59ba978dcfaab1865f1945d
parenta9ef335c1b220ad632aad1d75f671a2fcd2b0863 (diff)
parentfd504587d56d4062bccb0d815f4fd925fb8eb33c (diff)
downloadtor-a394a2dd86579495797432114f62ea3265ed5ed0.tar.gz
tor-a394a2dd86579495797432114f62ea3265ed5ed0.zip
Merge branch 'bug25903_v5_squashed'
-rw-r--r--changes/ticket259036
-rw-r--r--src/or/circuituse.c38
-rw-r--r--src/or/circuituse.h2
-rw-r--r--src/or/connection_edge.c9
-rw-r--r--src/or/control.c15
-rw-r--r--src/or/or.h24
-rw-r--r--src/or/relay.c45
-rw-r--r--src/or/relay.h4
-rw-r--r--src/or/rendcommon.c6
-rw-r--r--src/test/test_relaycell.c239
10 files changed, 377 insertions, 11 deletions
diff --git a/changes/ticket25903 b/changes/ticket25903
new file mode 100644
index 0000000000..8d358c8a83
--- /dev/null
+++ b/changes/ticket25903
@@ -0,0 +1,6 @@
+ o Minor features (control port):
+ - Introduce new fields to the CIRC_BW event. There are two new fields in
+ each of the read and written directions. The DELIVERED fields report the
+ total valid data on the circuit, as measured by the payload sizes of
+ verified and error-checked relay command cells. The OVERHEAD fields
+ report the total unused bytes in each of these cells. Closes ticket 25903.
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index ec09658282..8e007ce920 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -3106,3 +3106,41 @@ mark_circuit_unusable_for_new_conns(origin_circuit_t *circ)
circ->unusable_for_new_conns = 1;
}
+/**
+ * Add relay_body_len and RELAY_PAYLOAD_SIZE-relay_body_len to
+ * the valid delivered written fields and the overhead field,
+ * respectively.
+ */
+void
+circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len)
+{
+ if (!circ) return;
+
+ tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE);
+
+ circ->n_delivered_written_circ_bw =
+ tor_add_u32_nowrap(circ->n_delivered_written_circ_bw, relay_body_len);
+ circ->n_overhead_written_circ_bw =
+ tor_add_u32_nowrap(circ->n_overhead_written_circ_bw,
+ RELAY_PAYLOAD_SIZE-relay_body_len);
+}
+
+/**
+ * Add relay_body_len and RELAY_PAYLOAD_SIZE-relay_body_len to
+ * the valid delivered read field and the overhead field,
+ * respectively.
+ */
+void
+circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len)
+{
+ if (!circ) return;
+
+ tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE);
+
+ circ->n_delivered_read_circ_bw =
+ tor_add_u32_nowrap(circ->n_delivered_read_circ_bw, relay_body_len);
+ circ->n_overhead_read_circ_bw =
+ tor_add_u32_nowrap(circ->n_overhead_read_circ_bw,
+ RELAY_PAYLOAD_SIZE-relay_body_len);
+}
+
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index 71c818b978..6458bd6908 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -65,6 +65,8 @@ void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
int circuit_purpose_is_hidden_service(uint8_t);
int circuit_should_use_vanguards(uint8_t);
+void circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
+void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
#ifdef TOR_UNIT_TESTS
/* Used only by circuituse.c and test_circuituse.c */
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 28e18aa853..046369af60 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -3527,10 +3527,17 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->deliver_window = STREAMWINDOW_START;
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
+ int ret;
tor_free(address);
/* We handle this circuit and stream in this function for all supported
* hidden service version. */
- return handle_hs_exit_conn(circ, n_stream);
+ ret = handle_hs_exit_conn(circ, n_stream);
+
+ if (ret == 0) {
+ /* This was a valid cell. Count it as delivered + overhead. */
+ circuit_read_valid_data(origin_circ, rh.length);
+ }
+ return ret;
}
tor_strlower(address);
n_stream->base_.address = address;
diff --git a/src/or/control.c b/src/or/control.c
index 9323173f5d..0d637dce7a 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -265,6 +265,8 @@ clear_circ_bw_fields(void)
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
+ ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0;
+ ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0;
}
SMARTLIST_FOREACH_END(circ);
}
@@ -5990,13 +5992,20 @@ control_event_circ_bandwidth_used(void)
tor_gettimeofday(&now);
format_iso_time_nospace_usec(tbuf, &now);
send_control_event(EVENT_CIRC_BANDWIDTH_USED,
- "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu "
- "TIME=%s\r\n",
+ "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu TIME=%s "
+ "DELIVERED_READ=%lu OVERHEAD_READ=%lu "
+ "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu\r\n",
ocirc->global_identifier,
(unsigned long)ocirc->n_read_circ_bw,
(unsigned long)ocirc->n_written_circ_bw,
- tbuf);
+ tbuf,
+ (unsigned long)ocirc->n_delivered_read_circ_bw,
+ (unsigned long)ocirc->n_overhead_read_circ_bw,
+ (unsigned long)ocirc->n_delivered_written_circ_bw,
+ (unsigned long)ocirc->n_overhead_written_circ_bw);
ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
+ ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0;
+ ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0;
}
SMARTLIST_FOREACH_END(circ);
diff --git a/src/or/or.h b/src/or/or.h
index cd77b21056..750c79fd4c 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3260,16 +3260,36 @@ typedef struct origin_circuit_t {
* associated with this circuit. */
edge_connection_t *p_streams;
- /** Bytes read from any attached stream since last call to
+ /** Bytes read on this circuit since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_read_circ_bw;
- /** Bytes written to any attached stream since last call to
+ /** Bytes written to on this circuit since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_written_circ_bw;
+ /** Total known-valid relay cell bytes since last call to
+ * control_event_circ_bandwidth_used(). Only used if we're configured
+ * to emit CIRC_BW events. */
+ uint32_t n_delivered_read_circ_bw;
+
+ /** Total written relay cell bytes since last call to
+ * control_event_circ_bandwidth_used(). Only used if we're configured
+ * to emit CIRC_BW events. */
+ uint32_t n_delivered_written_circ_bw;
+
+ /** Total overhead data in all known-valid relay data cells since last
+ * call to control_event_circ_bandwidth_used(). Only used if we're
+ * configured to emit CIRC_BW events. */
+ uint32_t n_overhead_read_circ_bw;
+
+ /** Total written overhead data in all relay data cells since last call to
+ * control_event_circ_bandwidth_used(). Only used if we're configured
+ * to emit CIRC_BW events. */
+ uint32_t n_overhead_written_circ_bw;
+
/** Build state for this circuit. It includes the intended path
* length, the chosen exit router, rendezvous information, etc.
*/
diff --git a/src/or/relay.c b/src/or/relay.c
index b0b1af4454..add5a04190 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -85,9 +85,6 @@ static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
crypt_path_t *layer_hint);
-static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
- edge_connection_t *conn,
- 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,
@@ -613,6 +610,10 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
tor_free(commands);
smartlist_free(commands_list);
}
+
+ /* Let's assume we're well-behaved: Anything that we decide to send is
+ * valid, delivered data. */
+ circuit_sent_valid_data(origin_circ, rh.length);
}
if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer,
@@ -742,6 +743,9 @@ connection_ap_process_end_not_open(
}
}
+ /* This end cell is now valid. */
+ circuit_read_valid_data(circ, rh->length);
+
if (rh->length == 0) {
reason = END_STREAM_REASON_MISC;
}
@@ -1232,6 +1236,12 @@ connection_edge_process_resolved_cell(edge_connection_t *conn,
}
}
+ /* This is valid data at this point. Count it */
+ if (conn->on_circuit && CIRCUIT_IS_ORIGIN(conn->on_circuit)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(conn->on_circuit),
+ rh->length);
+ }
+
connection_ap_handshake_socks_got_resolved_cell(entry_conn,
errcode,
resolved_addresses);
@@ -1328,6 +1338,9 @@ connection_edge_process_relay_cell_not_open(
entry_conn->chosen_exit_name, ttl);
remap_event_helper(entry_conn, &addr);
+
+ /* This is valid data at this point. Count it */
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
}
circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
/* don't send a socks reply to transparent conns */
@@ -1398,7 +1411,7 @@ connection_edge_process_relay_cell_not_open(
*
* Return -reason if you want to warn and tear down the circuit, else 0.
*/
-static int
+STATIC int
connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
edge_connection_t *conn,
crypt_path_t *layer_hint)
@@ -1498,7 +1511,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
circ->dirreq_id = ++next_id;
TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id;
}
-
return connection_exit_begin_conn(cell, circ);
case RELAY_COMMAND_DATA:
++stats_n_data_cells_received;
@@ -1534,6 +1546,10 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"(relay data) conn deliver_window below 0. Killing.");
return -END_CIRC_REASON_TORPROTOCOL;
}
+ /* Total all valid application bytes delivered */
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ }
stats_n_data_bytes_received += rh.length;
connection_buf_add((char*)(cell->payload + RELAY_HEADER_SIZE),
@@ -1586,6 +1602,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_mark_and_flush(TO_CONN(conn));
+
+ /* Total all valid application bytes delivered */
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ }
}
return 0;
case RELAY_COMMAND_EXTEND:
@@ -1651,6 +1672,10 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
log_info(domain,"circuit_send_next_onion_skin() failed.");
return reason;
}
+ /* Total all valid bytes delivered. */
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ }
return 0;
case RELAY_COMMAND_TRUNCATE:
if (layer_hint) {
@@ -1716,6 +1741,16 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
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. Note that we cannot count stream
+ * sendme's because the other end could send as many as they like.
+ */
+ 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) {
diff --git a/src/or/relay.h b/src/or/relay.h
index f304af684a..ce0969b46c 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -114,6 +114,10 @@ STATIC packed_cell_t *packed_cell_new(void);
STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue);
STATIC destroy_cell_t *destroy_cell_queue_pop(destroy_cell_queue_t *queue);
STATIC int cell_queues_check_size(void);
+STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
+ edge_connection_t *conn,
+ crypt_path_t *layer_hint);
+
#endif /* defined(RELAY_PRIVATE) */
#endif /* !defined(TOR_RELAY_H) */
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 3a7dfe28f8..f3fa2f64d1 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -12,6 +12,7 @@
#include "or.h"
#include "circuitbuild.h"
+#include "circuituse.h"
#include "config.h"
#include "control.h"
#include "crypto_rand.h"
@@ -809,6 +810,11 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
tor_fragile_assert();
}
+ if (r == 0 && origin_circ) {
+ /* This was a valid cell. Count it as delivered + overhead. */
+ circuit_read_valid_data(origin_circ, length);
+ }
+
if (r == -2)
log_info(LD_PROTOCOL, "Dropping cell (type %d) for wrong circuit type.",
command);
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index eea1f5dc80..1db5202739 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -4,9 +4,14 @@
/* Unit tests for handling different kinds of relay cell */
#define RELAY_PRIVATE
+#define CIRCUITLIST_PRIVATE
#include "or.h"
+#include "main.h"
#include "config.h"
#include "connection.h"
+#include "crypto.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
#include "connection_edge.h"
#include "relay.h"
#include "test.h"
@@ -20,6 +25,11 @@ static uint8_t srm_answer[512];
static int srm_ttl;
static time_t srm_expires;
+void connection_free_minimal(connection_t*);
+int connected_cell_format_payload(uint8_t *payload_out,
+ const tor_addr_t *addr,
+ uint32_t ttl);
+
/* Mock replacement for connection_ap_hannshake_socks_resolved() */
static void
socks_resolved_mock(entry_connection_t *conn,
@@ -60,6 +70,234 @@ mark_unattached_mock(entry_connection_t *conn, int endreason,
(void) file;
}
+/* Helper: Return a newly allocated and initialized origin circuit with
+ * purpose and flags. A default HS identifier is set to an ed25519
+ * authentication key for introduction point. */
+static origin_circuit_t *
+helper_create_origin_circuit(int purpose, int flags)
+{
+ origin_circuit_t *circ = NULL;
+
+ circ = origin_circuit_init(purpose, flags);
+ tor_assert(circ);
+ circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
+ circ->cpath->magic = CRYPT_PATH_MAGIC;
+ circ->cpath->state = CPATH_STATE_OPEN;
+ circ->cpath->package_window = circuit_initial_package_window();
+ circ->cpath->deliver_window = CIRCWINDOW_START;
+ circ->cpath->prev = circ->cpath;
+ /* Create a default HS identifier. */
+ circ->hs_ident = tor_malloc_zero(sizeof(hs_ident_circuit_t));
+
+ return circ;
+}
+
+static void
+mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
+ int line, const char *file)
+{
+ (void) line;
+ (void) file;
+ conn->edge_.end_reason = endreason;
+}
+
+static void
+mock_mark_for_close(connection_t *conn,
+ int line, const char *file)
+{
+ (void)line;
+ (void)file;
+
+ conn->marked_for_close = 1;
+ return;
+}
+
+static void
+mock_start_reading(connection_t *conn)
+{
+ (void)conn;
+ return;
+}
+
+static void
+test_circbw_relay(void *arg)
+{
+ cell_t cell;
+ relay_header_t rh;
+ tor_addr_t addr;
+ edge_connection_t *edgeconn;
+ entry_connection_t *entryconn;
+ origin_circuit_t *circ;
+ int delivered = 0;
+ int overhead = 0;
+
+ (void)arg;
+
+#define PACK_CELL(id, cmd, body_s) do { \
+ memset(&cell, 0, sizeof(cell)); \
+ memset(&rh, 0, sizeof(rh)); \
+ memcpy(cell.payload+RELAY_HEADER_SIZE, (body_s), sizeof((body_s))-1); \
+ rh.length = sizeof((body_s))-1; \
+ rh.command = (cmd); \
+ rh.stream_id = (id); \
+ relay_header_pack((uint8_t*)&cell.payload, &rh); \
+ } while (0)
+#define ASSERT_COUNTED_BW() do { \
+ tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+rh.length); \
+ tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, \
+ overhead+RELAY_PAYLOAD_SIZE-rh.length); \
+ delivered = circ->n_delivered_read_circ_bw; \
+ overhead = circ->n_overhead_read_circ_bw; \
+ } while (0)
+#define ASSERT_UNCOUNTED_BW() do { \
+ tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered); \
+ tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, overhead); \
+ } while (0)
+
+ MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_);
+ MOCK(connection_start_reading, mock_start_reading);
+ MOCK(connection_mark_for_close_internal_, mock_mark_for_close);
+
+ entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
+ edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
+ edgeconn->deliver_window = 1000;
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
+ edgeconn->cpath_layer = circ->cpath;
+ circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
+ circ->cpath->deliver_window = 1000;
+
+ /* Stream id 0: Not counted */
+ PACK_CELL(0, RELAY_COMMAND_END, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Stream id 1: Counted */
+ PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ /* Properly formatted connect cell: counted */
+ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
+ tor_addr_parse(&addr, "30.40.50.60");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 1024);
+ relay_header_pack((uint8_t*)&cell.payload, &rh); \
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ /* Properly formatted resolved cell in correct state: counted */
+ edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
+ entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ edgeconn->on_circuit = TO_CIRCUIT(circ);
+ PACK_CELL(1, RELAY_COMMAND_RESOLVED,
+ "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ edgeconn->base_.state = AP_CONN_STATE_OPEN;
+ entryconn->socks_request->has_finished = 1;
+
+ /* Connected cell after open: not counted */
+ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Resolved cell after open: not counted */
+ PACK_CELL(1, RELAY_COMMAND_RESOLVED, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Drop cell: not counted */
+ PACK_CELL(1, RELAY_COMMAND_DROP, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Data cell on stream 0: not counted */
+ PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Data cell on open connection: counted */
+ ENTRY_TO_CONN(entryconn)->marked_for_close = 0;
+ PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ /* Sendme on stream: not counted */
+ ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0;
+ PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Sendme on circuit with full window: not counted */
+ PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Sendme on circuit with non-full window: counted */
+ PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
+ circ->cpath->package_window = 900;
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ /* End cell on non-closed connection: counted */
+ PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ /* End cell on connection that already got one: not counted */
+ PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Invalid extended cell: not counted */
+ PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Invalid extended cell: not counted */
+ PACK_CELL(1, RELAY_COMMAND_EXTENDED, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* Invalid HS cell: not counted */
+ PACK_CELL(1, RELAY_COMMAND_ESTABLISH_INTRO, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
+ circ->cpath);
+ ASSERT_UNCOUNTED_BW();
+
+ /* "Valid" HS cell in expected state: counted */
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
+ PACK_CELL(1, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "Data1234");
+ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
+ circ->cpath);
+ ASSERT_COUNTED_BW();
+
+ done:
+ UNMOCK(connection_start_reading);
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(connection_mark_for_close_internal_);
+ circuit_free_(TO_CIRCUIT(circ));
+ connection_free_minimal(ENTRY_TO_CONN(entryconn));
+}
+
/* Tests for connection_edge_process_resolved_cell().
The point of ..process_resolved_cell() is to handle an incoming cell
@@ -244,6 +482,7 @@ test_relaycell_resolved(void *arg)
struct testcase_t relaycell_tests[] = {
{ "resolved", test_relaycell_resolved, TT_FORK, NULL, NULL },
+ { "circbw", test_circbw_relay, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};