tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
October 2013
- 17 participants
- 1284 discussions
commit c386d2d6ce4c4f58163acb385c7a5de1da8c5e30
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Feb 6 14:37:38 2013 +0100
Add new CELL_STATS event.
Jointly authored with Rob Jansen <jansen(a)cs.umn.edu>.
---
src/or/control.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/or/control.h | 1 +
src/or/main.c | 1 +
src/or/or.h | 36 ++++++++++++
src/or/relay.c | 97 ++++++++++++++++++++++++++++----
src/or/relay.h | 3 +-
6 files changed, 290 insertions(+), 13 deletions(-)
diff --git a/src/or/control.c b/src/or/control.c
index 0a49c29..6625877 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -83,7 +83,8 @@
#define EVENT_SIGNAL 0x0018
#define EVENT_CONF_CHANGED 0x0019
#define EVENT_CONN_BW 0x001A
-#define EVENT_MAX_ 0x001A
+#define EVENT_CELL_STATS 0x001B
+#define EVENT_MAX_ 0x001B
/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
@@ -960,6 +961,7 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_SIGNAL, "SIGNAL" },
{ EVENT_CONF_CHANGED, "CONF_CHANGED"},
{ EVENT_CONN_BW, "CONN_BW" },
+ { EVENT_CELL_STATS, "CELL_STATS" },
{ 0, NULL },
};
@@ -3956,6 +3958,167 @@ control_event_conn_bandwidth_used(void)
return 0;
}
+extern circuit_t *global_circuitlist;
+
+/** Convert the cell <b>command</b> into a lower-case, human-readable
+ * string. */
+static const char *
+cell_command_to_string(uint8_t command)
+{
+ switch (command) {
+ case CELL_PADDING: return "padding";
+ case CELL_CREATE: return "create";
+ case CELL_CREATED: return "created";
+ case CELL_RELAY: return "relay";
+ case CELL_DESTROY: return "destroy";
+ case CELL_CREATE_FAST: return "create_fast";
+ case CELL_CREATED_FAST: return "created_fast";
+ case CELL_VERSIONS: return "versions";
+ case CELL_NETINFO: return "netinfo";
+ case CELL_RELAY_EARLY: return "relay_early";
+ case CELL_CREATE2: return "create2";
+ case CELL_CREATED2: return "created2";
+ case CELL_VPADDING: return "vpadding";
+ case CELL_CERTS: return "certs";
+ case CELL_AUTH_CHALLENGE: return "auth_challenge";
+ case CELL_AUTHENTICATE: return "authenticate";
+ case CELL_AUTHORIZE: return "authorize";
+ default: return "unrecognized";
+ }
+}
+
+/** Helper: append a cell statistics string to <code>event_parts</code>,
+ * prefixed with <code>key</code>=. Statistics consist of comma-separated
+ * key:value pairs with lower-case command strings as keys and cell
+ * numbers or total waiting times as values. A key:value pair is included
+ * if the entry in <code>include_if_positive</code> is positive, but with
+ * the (possibly zero) entry from <code>number_to_include</code>. If no
+ * entry in <code>include_if_positive</code> is positive, no string will
+ * be added to <code>event_parts</code>. */
+static void
+append_cell_stats_by_command(smartlist_t *event_parts, const char *key,
+ uint64_t *include_if_positive,
+ uint64_t *number_to_include)
+{
+ smartlist_t *key_value_strings = smartlist_new();
+ int i;
+ for (i = 0; i <= CELL_MAX_; i++) {
+ if (include_if_positive[i] > 0) {
+ smartlist_add_asprintf(key_value_strings, "%s:"U64_FORMAT,
+ cell_command_to_string(i),
+ U64_PRINTF_ARG(number_to_include[i]));
+ }
+ }
+ if (key_value_strings->num_used > 0) {
+ char *joined = smartlist_join_strings(key_value_strings, ",", 0, NULL);
+ char *result;
+ tor_asprintf(&result, "%s=%s", key, joined);
+ smartlist_add(event_parts, result);
+ SMARTLIST_FOREACH(key_value_strings, char *, cp, tor_free(cp));
+ tor_free(joined);
+ }
+ smartlist_free(key_value_strings);
+}
+
+/** A second or more has elapsed: tell any interested control connection
+ * how many cells have been processed for a given circuit. */
+int
+control_event_circuit_cell_stats(void)
+{
+ /* These arrays temporarily consume slightly over 6 KiB on the stack
+ * every second, most of which are wasted for the non-existant commands
+ * between CELL_RELAY_EARLY (9) and CELL_VPADDING (128). But nothing
+ * beats the stack when it comes to performance. */
+ uint64_t added_cells_appward[CELL_MAX_ + 1],
+ added_cells_exitward[CELL_MAX_ + 1],
+ removed_cells_appward[CELL_MAX_ + 1],
+ removed_cells_exitward[CELL_MAX_ + 1],
+ total_time_appward[CELL_MAX_ + 1],
+ total_time_exitward[CELL_MAX_ + 1];
+ circuit_t *circ;
+ if (!get_options()->TestingTorNetwork ||
+ !EVENT_IS_INTERESTING(EVENT_CELL_STATS))
+ return 0;
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ smartlist_t *event_parts;
+ char *event_string;
+
+ if (!circ->testing_cell_stats)
+ continue;
+
+ memset(added_cells_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ memset(added_cells_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ memset(removed_cells_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ memset(removed_cells_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ memset(total_time_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ memset(total_time_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
+ SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats,
+ testing_cell_stats_entry_t *, ent) {
+ tor_assert(ent->command <= CELL_MAX_);
+ if (!ent->removed && !ent->exit_ward) {
+ added_cells_appward[ent->command] += 1;
+ } else if (!ent->removed && ent->exit_ward) {
+ added_cells_exitward[ent->command] += 1;
+ } else if (!ent->exit_ward) {
+ removed_cells_appward[ent->command] += 1;
+ total_time_appward[ent->command] += ent->waiting_time * 10;
+ } else {
+ removed_cells_exitward[ent->command] += 1;
+ total_time_exitward[ent->command] += ent->waiting_time * 10;
+ }
+ tor_free(ent);
+ } SMARTLIST_FOREACH_END(ent);
+ smartlist_free(circ->testing_cell_stats);
+ circ->testing_cell_stats = NULL;
+
+ event_parts = smartlist_new();
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ char *id_string;
+ tor_asprintf(&id_string, "ID=%lu",
+ (unsigned long)ocirc->global_identifier);
+ smartlist_add(event_parts, id_string);
+ } else {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ char *queue_string, *conn_string;
+ tor_asprintf(&queue_string, "InboundQueue=%lu",
+ (unsigned long)or_circ->p_circ_id);
+ tor_asprintf(&conn_string, "InboundConn="U64_FORMAT,
+ U64_PRINTF_ARG(or_circ->p_chan->global_identifier));
+ smartlist_add(event_parts, queue_string);
+ smartlist_add(event_parts, conn_string);
+ append_cell_stats_by_command(event_parts, "InboundAdded",
+ added_cells_appward, added_cells_appward);
+ append_cell_stats_by_command(event_parts, "InboundRemoved",
+ removed_cells_appward, removed_cells_appward);
+ append_cell_stats_by_command(event_parts, "InboundTime",
+ removed_cells_appward, total_time_appward);
+ }
+ if (circ->n_chan) {
+ char *queue_string, *conn_string;
+ tor_asprintf(&queue_string, "OutboundQueue=%lu",
+ (unsigned long)circ->n_circ_id);
+ tor_asprintf(&conn_string, "OutboundConn="U64_FORMAT,
+ U64_PRINTF_ARG(circ->n_chan->global_identifier));
+ smartlist_add(event_parts, queue_string);
+ smartlist_add(event_parts, conn_string);
+ append_cell_stats_by_command(event_parts, "OutboundAdded",
+ added_cells_exitward, added_cells_exitward);
+ append_cell_stats_by_command(event_parts, "OutboundRemoved",
+ removed_cells_exitward, removed_cells_exitward);
+ append_cell_stats_by_command(event_parts, "OutboundTime",
+ removed_cells_exitward, total_time_exitward);
+ }
+ event_string = smartlist_join_strings(event_parts, " ", 0, NULL);
+ send_control_event(EVENT_CELL_STATS, ALL_FORMATS,
+ "650 CELL_STATS %s\r\n", event_string);
+ SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp));
+ smartlist_free(event_parts);
+ tor_free(event_string);
+ }
+ return 0;
+}
+
/** A second or more has elapsed: tell any interested control
* connections how much bandwidth we used. */
int
diff --git a/src/or/control.h b/src/or/control.h
index fe5c0ef..4d950bf 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -52,6 +52,7 @@ int control_event_stream_bandwidth(edge_connection_t *edge_conn);
int control_event_stream_bandwidth_used(void);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
+int control_event_circuit_cell_stats(void);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
diff --git a/src/or/main.c b/src/or/main.c
index c145f9d..ae60548 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1641,6 +1641,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written);
control_event_stream_bandwidth_used();
control_event_conn_bandwidth_used();
+ control_event_circuit_cell_stats();
if (server_mode(options) &&
!net_is_disabled() &&
diff --git a/src/or/or.h b/src/or/or.h
index 08a94aa..22e4b96 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -839,6 +839,7 @@ typedef enum {
#define CELL_AUTH_CHALLENGE 130
#define CELL_AUTHENTICATE 131
#define CELL_AUTHORIZE 132
+#define CELL_MAX_ 132
/** How long to test reachability before complaining to the user. */
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
@@ -1087,6 +1088,21 @@ typedef struct insertion_time_queue_t {
struct insertion_time_elem_t *last; /**< Last element in queue. */
} insertion_time_queue_t;
+/** Number of cells with the same command consecutively added to a circuit
+ * queue; used for cell statistics only in TestingTorNetwork mode. */
+typedef struct insertion_command_elem_t {
+ struct insertion_command_elem_t *next; /**< Next element in queue. */
+ /** Which command did these consecutively added cells have? */
+ uint8_t command;
+ unsigned counter; /**< How many cells were inserted? */
+} insertion_command_elem_t;
+
+/** Queue of insertion commands. */
+typedef struct insertion_command_queue_t {
+ struct insertion_command_elem_t *first; /**< First element in queue. */
+ struct insertion_command_elem_t *last; /**< Last element in queue. */
+} insertion_command_queue_t;
+
/** A queue of cells on a circuit, waiting to be added to the
* or_connection_t's outbuf. */
typedef struct cell_queue_t {
@@ -1094,6 +1110,8 @@ typedef struct cell_queue_t {
packed_cell_t *tail; /**< The last cell, or NULL if the queue is empty. */
int n; /**< The number of cells in the queue. */
insertion_time_queue_t *insertion_times; /**< Insertion times of cells. */
+ /** Commands of inserted cells. */
+ insertion_command_queue_t *insertion_commands;
} cell_queue_t;
/** Beginning of a RELAY cell payload. */
@@ -2730,6 +2748,19 @@ typedef struct {
struct create_cell_t;
+/** Entry in the cell stats list of a circuit; used only when
+ * TestingTorNetwork is set. */
+typedef struct testing_cell_stats_entry_t {
+ uint8_t command; /**< cell command number. */
+ /** Waiting time in centiseconds if this event is for a removed cell,
+ * or 0 if this event is for adding a cell to the queue. 22 bits can
+ * store more than 11 hours, enough to assume that a circuit with this
+ * delay would long have been closed. */
+ unsigned int waiting_time:22;
+ unsigned int removed:1; /**< 0 for added to, 1 for removed from queue. */
+ unsigned int exit_ward:1; /**< 0 for app-ward, 1 for exit-ward. */
+} testing_cell_stats_entry_t;
+
/**
* A circuit is a path over the onion routing
* network. Applications can connect to one end of the circuit, and can
@@ -2855,6 +2886,11 @@ typedef struct circuit_t {
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
struct circuit_t *prev_active_on_n_chan;
+
+ /** Various statistics about cells being added to or removed from this
+ * circuit's queues; used only when TestingTorNetwork is set and cleared
+ * after being sent to control port. */
+ smartlist_t *testing_cell_stats;
} circuit_t;
/** Largest number of relay_early cells that we can send on a given
diff --git a/src/or/relay.c b/src/or/relay.c
index 52ff32f..02b3b1c 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -2045,6 +2045,10 @@ static mp_pool_t *cell_pool = NULL;
* statistics. */
static mp_pool_t *it_pool = NULL;
+/** Memory pool to allocate insertion_command_elem_t objects used for cell
+ * statistics in TestingTorNetwork mode. */
+static mp_pool_t *ic_pool = NULL;
+
/** Allocate structures to hold cells. */
void
init_cell_pool(void)
@@ -2053,8 +2057,8 @@ init_cell_pool(void)
cell_pool = mp_pool_new(sizeof(packed_cell_t), 128*1024);
}
-/** Free all storage used to hold cells (and insertion times if we measure
- * cell statistics). */
+/** Free all storage used to hold cells (and insertion times/commands if we
+ * measure cell statistics and/or are in TestingTorNetwork mode). */
void
free_cell_pool(void)
{
@@ -2067,6 +2071,10 @@ free_cell_pool(void)
mp_pool_destroy(it_pool);
it_pool = NULL;
}
+ if (ic_pool) {
+ mp_pool_destroy(ic_pool);
+ ic_pool = NULL;
+ }
}
/** Free excess storage in cell pool. */
@@ -2145,14 +2153,16 @@ cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
++queue->n;
}
-/** Append a newly allocated copy of <b>cell</b> to the end of <b>queue</b> */
+/** Append a newly allocated copy of <b>cell</b> to the end of the
+ * <b>exit_ward</b> (or app-ward) <b>queue</b> of <b>circ</b>. */
void
-cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
+cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
+ int exit_ward, const cell_t *cell,
int wide_circ_ids)
{
packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
/* Remember the time when this cell was put in the queue. */
- if (get_options()->CellStatistics) {
+ if (get_options()->CellStatistics || get_options()->TestingTorNetwork) {
struct timeval now;
uint32_t added;
insertion_time_queue_t *it_queue = queue->insertion_times;
@@ -2181,6 +2191,38 @@ cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
}
}
}
+ /* Remember that we added a cell to the queue, and remember the cell
+ * command. */
+ if (get_options()->TestingTorNetwork) {
+ insertion_command_queue_t *ic_queue = queue->insertion_commands;
+ testing_cell_stats_entry_t *ent =
+ tor_malloc_zero(sizeof(testing_cell_stats_entry_t));
+ ent->command = cell->command;
+ ent->exit_ward = exit_ward;
+ if (!circ->testing_cell_stats)
+ circ->testing_cell_stats = smartlist_new();
+ smartlist_add(circ->testing_cell_stats, ent);
+ if (!ic_pool)
+ ic_pool = mp_pool_new(sizeof(insertion_command_elem_t), 1024);
+ if (!ic_queue) {
+ ic_queue = tor_malloc_zero(sizeof(insertion_command_queue_t));
+ queue->insertion_commands = ic_queue;
+ }
+ if (ic_queue->last && ic_queue->last->command == cell->command) {
+ ic_queue->last->counter++;
+ } else {
+ insertion_command_elem_t *elem = mp_pool_get(ic_pool);
+ elem->next = NULL;
+ elem->command = cell->command;
+ elem->counter = 1;
+ if (ic_queue->last) {
+ ic_queue->last->next = elem;
+ ic_queue->last = elem;
+ } else {
+ ic_queue->first = ic_queue->last = elem;
+ }
+ }
+ }
cell_queue_append(queue, copy);
}
@@ -2386,7 +2428,8 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
cell = cell_queue_pop(queue);
/* Calculate the exact time that this cell has spent in the queue. */
- if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
+ if (get_options()->CellStatistics ||
+ get_options()->TestingTorNetwork) {
struct timeval tvnow;
uint32_t flushed;
uint32_t cell_waiting_time;
@@ -2400,7 +2443,6 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
"recently enabled.");
} else {
insertion_time_elem_t *elem = it_queue->first;
- or_circ = TO_OR_CIRCUIT(circ);
cell_waiting_time =
(uint32_t)((flushed * 10L + SECONDS_IN_A_DAY * 1000L -
elem->insertion_time * 10L) %
@@ -2413,8 +2455,38 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
it_queue->last = NULL;
mp_pool_release(elem);
}
- or_circ->total_cell_waiting_time += cell_waiting_time;
- or_circ->processed_cells++;
+ if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
+ or_circ = TO_OR_CIRCUIT(circ);
+ or_circ->total_cell_waiting_time += cell_waiting_time;
+ or_circ->processed_cells++;
+ }
+ if (get_options()->TestingTorNetwork) {
+ insertion_command_queue_t *ic_queue = queue->insertion_commands;
+ if (!ic_queue || !ic_queue->first) {
+ log_info(LD_BUG, "Cannot determine command of cell, which "
+ "is a bug, because TestingTorNetwork cannot "
+ "be enabled while running.");
+ } else {
+ testing_cell_stats_entry_t *ent =
+ tor_malloc_zero(sizeof(testing_cell_stats_entry_t));
+ insertion_command_elem_t *ic_elem = ic_queue->first;
+ ent->command = ic_elem->command;
+ ic_elem->counter--;
+ if (ic_elem->counter < 1) {
+ ic_queue->first = ic_elem->next;
+ if (ic_elem == ic_queue->last)
+ ic_queue->last = NULL;
+ mp_pool_release(ic_elem);
+ }
+ ent->waiting_time = (unsigned int)cell_waiting_time / 10;
+ ent->removed = 1;
+ if (circ->n_chan == chan)
+ ent->exit_ward = 1;
+ if (!circ->testing_cell_stats)
+ circ->testing_cell_stats = smartlist_new();
+ smartlist_add(circ->testing_cell_stats, ent);
+ }
+ }
}
}
@@ -2470,10 +2542,12 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
{
cell_queue_t *queue;
int streams_blocked;
+ int exit_ward;
if (circ->marked_for_close)
return;
- if (direction == CELL_DIRECTION_OUT) {
+ exit_ward = (direction == CELL_DIRECTION_OUT);
+ if (exit_ward) {
queue = &circ->n_chan_cells;
streams_blocked = circ->streams_blocked_on_n_chan;
} else {
@@ -2482,7 +2556,8 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
streams_blocked = circ->streams_blocked_on_p_chan;
}
- cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids);
+ cell_queue_append_packed_copy(circ, queue, exit_ward, cell,
+ chan->wide_circ_ids);
/* If we have too many cells on the circuit, we should stop reading from
* the edge streams for a while. */
diff --git a/src/or/relay.h b/src/or/relay.h
index 229fb4f..e3b392c 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -52,7 +52,8 @@ void packed_cell_free(packed_cell_t *cell);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
-void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
+void cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
+ int exit_ward, const cell_t *cell,
int wide_circ_ids);
void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
1
0
commit dd5ce2157d8c47ffa3686b0579813e7b1aae8069
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Feb 6 14:26:11 2013 +0100
Add new TB_EMPTY event.
Jointly authored with Rob Jansen <jansen(a)cs.umn.edu>.
---
src/or/connection.c | 64 ++++++++++++++++++++++++++++++++
src/or/control.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/or/control.h | 12 ++++++
src/or/or.h | 6 +++
4 files changed, 183 insertions(+), 1 deletion(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index 81b4991..dfcd1ab 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -2541,6 +2541,27 @@ record_num_bytes_transferred(connection_t *conn,
#endif
#ifndef USE_BUFFEREVENTS
+/** Last emptied global or relay buckets in msec since midnight; only used
+ * in TestingTorNetwork mode. */
+static uint32_t global_relayed_read_emptied = 0,
+ global_relayed_write_emptied = 0,
+ global_read_emptied = 0,
+ global_write_emptied = 0;
+
+/** Check if a bucket has just run out of tokens, and if so, note the
+ * timestamp for TB_EMPTY events; only used in TestingTorNetwork mode. */
+static void
+connection_buckets_empty_ts(uint32_t *timestamp_var, int tokens_before,
+ size_t tokens_removed)
+{
+ if (tokens_before > 0 && tokens_before - (int)tokens_removed <= 0) {
+ struct timeval tvnow;
+ tor_gettimeofday_cached(&tvnow);
+ *timestamp_var = (uint32_t)(((tvnow.tv_sec % 86400L) * 1000L) +
+ ((uint32_t)tvnow.tv_usec / (uint32_t)1000L));
+ }
+}
+
/** We just read <b>num_read</b> and wrote <b>num_written</b> bytes
* onto <b>conn</b>. Decrement buckets appropriately. */
static void
@@ -2563,6 +2584,28 @@ connection_buckets_decrement(connection_t *conn, time_t now,
if (!connection_is_rate_limited(conn))
return; /* local IPs are free */
+ /* If one or more of our token buckets ran dry just now, note the
+ * timestamp for TB_EMPTY events. */
+ if (get_options()->TestingTorNetwork) {
+ if (connection_counts_as_relayed_traffic(conn, now)) {
+ connection_buckets_empty_ts(&global_relayed_read_emptied,
+ global_relayed_read_bucket, num_read);
+ connection_buckets_empty_ts(&global_relayed_write_emptied,
+ global_relayed_write_bucket, num_written);
+ }
+ connection_buckets_empty_ts(&global_read_emptied, global_read_bucket,
+ num_read);
+ connection_buckets_empty_ts(&global_write_emptied, global_write_bucket,
+ num_written);
+ if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ connection_buckets_empty_ts(&or_conn->read_emptied_time,
+ or_conn->read_bucket, num_read);
+ connection_buckets_empty_ts(&or_conn->write_emptied_time,
+ or_conn->write_bucket, num_written);
+ }
+ }
+
if (connection_counts_as_relayed_traffic(conn, now)) {
global_relayed_read_bucket -= (int)num_read;
global_relayed_write_bucket -= (int)num_written;
@@ -2677,6 +2720,11 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
smartlist_t *conns = get_connection_array();
int bandwidthrate, bandwidthburst, relayrate, relayburst;
+ int prev_global_read = global_read_bucket;
+ int prev_global_write = global_write_bucket;
+ int prev_relay_read = global_relayed_read_bucket;
+ int prev_relay_write = global_relayed_write_bucket;
+
bandwidthrate = (int)options->BandwidthRate;
bandwidthburst = (int)options->BandwidthBurst;
@@ -2711,12 +2759,25 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
milliseconds_elapsed,
"global_relayed_write_bucket");
+ control_event_refill_global(global_read_bucket, prev_global_read,
+ global_read_emptied, global_write_bucket,
+ prev_global_write, global_write_emptied,
+ global_relayed_read_bucket, prev_relay_read,
+ global_relayed_read_emptied,
+ global_relayed_write_bucket, prev_relay_write,
+ global_relayed_write_emptied,
+ milliseconds_elapsed);
+
/* refill the per-connection buckets */
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
int orbandwidthrate = or_conn->bandwidthrate;
int orbandwidthburst = or_conn->bandwidthburst;
+
+ int prev_conn_read = or_conn->read_bucket;
+ int prev_conn_write = or_conn->write_bucket;
+
if (connection_bucket_should_increase(or_conn->read_bucket, or_conn)) {
connection_bucket_refill_helper(&or_conn->read_bucket,
orbandwidthrate,
@@ -2731,6 +2792,9 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
milliseconds_elapsed,
"or_conn->write_bucket");
}
+
+ control_event_refill_conn(or_conn, prev_conn_read, prev_conn_write,
+ (uint32_t)milliseconds_elapsed);
}
if (conn->read_blocked_on_bw == 1 /* marked to turn reading back on now */
diff --git a/src/or/control.c b/src/or/control.c
index 6625877..47d08c2 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -84,7 +84,8 @@
#define EVENT_CONF_CHANGED 0x0019
#define EVENT_CONN_BW 0x001A
#define EVENT_CELL_STATS 0x001B
-#define EVENT_MAX_ 0x001B
+#define EVENT_TB_EMPTY 0x001C
+#define EVENT_MAX_ 0x001C
/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
@@ -962,6 +963,7 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_CONF_CHANGED, "CONF_CHANGED"},
{ EVENT_CONN_BW, "CONN_BW" },
{ EVENT_CELL_STATS, "CELL_STATS" },
+ { EVENT_TB_EMPTY, "TB_EMPTY" },
{ 0, NULL },
};
@@ -4119,6 +4121,104 @@ control_event_circuit_cell_stats(void)
return 0;
}
+/** Helper: return the time in millis that a given bucket was empty,
+ * capped at the time in millis since last refilling that bucket. Return
+ * 0 if the bucket was not empty during the last refill period. */
+static uint32_t
+bucket_millis_empty(int prev_tokens, uint32_t last_empty_time,
+ uint32_t milliseconds_elapsed)
+{
+ uint32_t result = 0, refilled;
+ if (prev_tokens <= 0) {
+ struct timeval tvnow;
+ tor_gettimeofday_cached(&tvnow);
+ refilled = (uint32_t)((tvnow.tv_sec % 86400L) * 1000L +
+ (uint32_t)tvnow.tv_usec / (uint32_t)1000L);
+ result = (uint32_t)((refilled + 86400L * 1000L - last_empty_time) %
+ (86400L * 1000L));
+ if (result > milliseconds_elapsed)
+ result = milliseconds_elapsed;
+ }
+ return result;
+}
+
+/** Token buckets have been refilled: tell any interested control
+ * connections how global and relay token buckets have changed. */
+int
+control_event_refill_global(int global_read, int prev_global_read,
+ uint32_t global_read_emptied_time,
+ int global_write, int prev_global_write,
+ uint32_t global_write_emptied_time,
+ int relay_read, int prev_relay_read,
+ uint32_t relay_read_emptied_time,
+ int relay_write, int prev_relay_write,
+ uint32_t relay_write_emptied_time,
+ uint32_t milliseconds_elapsed)
+{
+ uint32_t global_read_empty_time, global_write_empty_time,
+ relay_read_empty_time, relay_write_empty_time;
+ if (!get_options()->TestingTorNetwork ||
+ !EVENT_IS_INTERESTING(EVENT_TB_EMPTY))
+ return 0;
+ if (prev_global_read == global_read &&
+ prev_global_write == global_write &&
+ prev_relay_read == relay_read &&
+ prev_relay_write == relay_write)
+ return 0;
+ if (prev_global_read <= 0 && prev_global_write <= 0) {
+ global_read_empty_time = bucket_millis_empty(prev_global_read,
+ global_read_emptied_time, milliseconds_elapsed);
+ global_write_empty_time = bucket_millis_empty(prev_global_write,
+ global_write_emptied_time, milliseconds_elapsed);
+ send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
+ "650 TB_EMPTY GLOBAL READ=%d WRITTEN=%d "
+ "LAST=%d\r\n",
+ global_read_empty_time, global_write_empty_time,
+ milliseconds_elapsed);
+ }
+ if (prev_relay_read <= 0 && prev_relay_write <= 0) {
+ relay_read_empty_time = bucket_millis_empty(prev_relay_read,
+ relay_read_emptied_time, milliseconds_elapsed);
+ relay_write_empty_time = bucket_millis_empty(prev_relay_write,
+ relay_write_emptied_time, milliseconds_elapsed);
+ send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
+ "650 TB_EMPTY RELAY READ=%d WRITTEN=%d "
+ "LAST=%d\r\n",
+ relay_read_empty_time, relay_write_empty_time,
+ milliseconds_elapsed);
+ }
+ return 0;
+}
+
+/** Token buckets of a connection have been refilled: tell any interested
+ * control connections how per-connection token buckets have changed. */
+int
+control_event_refill_conn(or_connection_t *or_conn,
+ int prev_read, int prev_write,
+ uint32_t milliseconds_elapsed)
+{
+ uint32_t read_bucket_empty_time, write_bucket_empty_time;
+ if (!get_options()->TestingTorNetwork ||
+ !EVENT_IS_INTERESTING(EVENT_TB_EMPTY))
+ return 0;
+ if (prev_read == or_conn->read_bucket &&
+ prev_write == or_conn->write_bucket)
+ return 0;
+ if (prev_read <= 0 || prev_write <= 0) {
+ read_bucket_empty_time = bucket_millis_empty(prev_read,
+ or_conn->read_emptied_time, milliseconds_elapsed);
+ write_bucket_empty_time = bucket_millis_empty(prev_write,
+ or_conn->write_emptied_time, milliseconds_elapsed);
+ send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
+ "650 TB_EMPTY ORCONN ID="U64_FORMAT" READ=%d "
+ "WRITTEN=%d LAST=%d\r\n",
+ U64_PRINTF_ARG(or_conn->base_.global_identifier),
+ read_bucket_empty_time, write_bucket_empty_time,
+ milliseconds_elapsed);
+ }
+ return 0;
+}
+
/** A second or more has elapsed: tell any interested control
* connections how much bandwidth we used. */
int
diff --git a/src/or/control.h b/src/or/control.h
index 4d950bf..2977159 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -53,6 +53,18 @@ int control_event_stream_bandwidth_used(void);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
+int control_event_refill_global(int global_read, int prev_global_read,
+ uint32_t global_read_emptied,
+ int global_write, int prev_global_write,
+ uint32_t global_write_emptied,
+ int relay_read, int prev_relay_read,
+ uint32_t relay_read_emptied,
+ int relay_write, int prev_relay_write,
+ uint32_t relay_write_emptied,
+ uint32_t milliseconds_elapsed);
+int control_event_refill_conn(or_connection_t *or_conn,
+ int prev_read, int prev_write,
+ uint32_t milliseconds_elapsed);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
diff --git a/src/or/or.h b/src/or/or.h
index 22e4b96..c2be282 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1477,6 +1477,12 @@ typedef struct or_connection_t {
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
+ /** Last emptied read token bucket in msec since midnight; only used in
+ * TestingTorNetwork mode. */
+ uint32_t read_emptied_time;
+ /** Last emptied write token bucket in msec since midnight; only used in
+ * TestingTorNetwork mode. */
+ uint32_t write_emptied_time;
} or_connection_t;
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
1
0
commit 2925e2fe786dfd9a27c2dff503996712cd180de4
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sun Feb 24 13:32:57 2013 +0100
Add new CIRC_BW event.
---
src/or/connection.c | 23 +++++++++++++++++++-
src/or/control.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-----
src/or/control.h | 1 +
src/or/main.c | 1 +
src/or/or.h | 9 ++++++++
5 files changed, 86 insertions(+), 6 deletions(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index dfcd1ab..a00351a 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -3203,14 +3203,25 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
/* change *max_to_read */
*max_to_read = at_most - n_read;
- /* Update edge_conn->n_read */
+ /* Update edge_conn->n_read and ocirc->n_read */
if (conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ circuit_t *circ = circuit_get_by_edge_conn(edge_conn);
+ origin_circuit_t *ocirc;
+
/* Check for overflow: */
if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_read > n_read))
edge_conn->n_read += (int)n_read;
else
edge_conn->n_read = UINT32_MAX;
+
+ if (circ && CIRCUIT_IS_ORIGIN(circ)) {
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_read > n_read))
+ ocirc->n_read += (int)n_read;
+ else
+ ocirc->n_read = UINT32_MAX;
+ }
}
/* In TestingTorNetwork mode, update conn->n_read for OR/DIR/EXIT
@@ -3662,12 +3673,22 @@ connection_handle_write_impl(connection_t *conn, int force)
if (n_written && conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ circuit_t *circ = circuit_get_by_edge_conn(edge_conn);
+ origin_circuit_t *ocirc;
/* Check for overflow: */
if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_written > n_written))
edge_conn->n_written += (int)n_written;
else
edge_conn->n_written = UINT32_MAX;
+
+ if (circ && CIRCUIT_IS_ORIGIN(circ)) {
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_written > n_written))
+ ocirc->n_written += (int)n_written;
+ else
+ ocirc->n_written = UINT32_MAX;
+ }
}
/* In TestingTorNetwork mode, update conn->n_written for OR/DIR/EXIT
diff --git a/src/or/control.c b/src/or/control.c
index 47d08c2..d3b968c 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -46,6 +46,8 @@
#include <sys/resource.h>
#endif
+extern circuit_t *global_circuitlist; /* from circuitlist.c */
+
#include "procmon.h"
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
@@ -85,7 +87,8 @@
#define EVENT_CONN_BW 0x001A
#define EVENT_CELL_STATS 0x001B
#define EVENT_TB_EMPTY 0x001C
-#define EVENT_MAX_ 0x001C
+#define EVENT_CIRC_BANDWIDTH_USED 0x001D
+#define EVENT_MAX_ 0x001D
/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
@@ -260,8 +263,8 @@ control_update_global_event_mask(void)
* we want to hear...*/
control_adjust_event_log_severity();
- /* ...then, if we've started logging stream bw, clear the appropriate
- * fields. */
+ /* ...then, if we've started logging stream or circ bw, clear the
+ * appropriate fields. */
if (! (old_mask & EVENT_STREAM_BANDWIDTH_USED) &&
(new_mask & EVENT_STREAM_BANDWIDTH_USED)) {
SMARTLIST_FOREACH(conns, connection_t *, conn,
@@ -272,6 +275,17 @@ control_update_global_event_mask(void)
}
});
}
+ if (! (old_mask & EVENT_CIRC_BANDWIDTH_USED) &&
+ (new_mask & EVENT_CIRC_BANDWIDTH_USED)) {
+ circuit_t *circ;
+ origin_circuit_t *ocirc;
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ continue;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->n_written = ocirc->n_read = 0;
+ }
+ }
}
/** Adjust the log severities that result in control_event_logmsg being called
@@ -964,6 +978,7 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_CONN_BW, "CONN_BW" },
{ EVENT_CELL_STATS, "CELL_STATS" },
{ EVENT_TB_EMPTY, "TB_EMPTY" },
+ { EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" },
{ 0, NULL },
};
@@ -3865,6 +3880,8 @@ control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp,
int
control_event_stream_bandwidth(edge_connection_t *edge_conn)
{
+ circuit_t *circ;
+ origin_circuit_t *ocirc;
if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) {
if (!edge_conn->n_read && !edge_conn->n_written)
return 0;
@@ -3875,6 +3892,12 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn)
(unsigned long)edge_conn->n_read,
(unsigned long)edge_conn->n_written);
+ circ = circuit_get_by_edge_conn(edge_conn);
+ if (circ && CIRCUIT_IS_ORIGIN(circ)) {
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->n_read += edge_conn->n_read;
+ ocirc->n_written += edge_conn->n_written;
+ }
edge_conn->n_written = edge_conn->n_read = 0;
}
@@ -3912,6 +3935,33 @@ control_event_stream_bandwidth_used(void)
return 0;
}
+/** A second or more has elapsed: tell any interested control connections
+ * how much bandwidth origin circuits have used. */
+int
+control_event_circ_bandwidth_used(void)
+{
+ circuit_t *circ;
+ origin_circuit_t *ocirc;
+ if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED))
+ return 0;
+
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ continue;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ if (!ocirc->n_read && !ocirc->n_written)
+ continue;
+ send_control_event(EVENT_CIRC_BANDWIDTH_USED, ALL_FORMATS,
+ "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu\r\n",
+ ocirc->global_identifier,
+ (unsigned long)ocirc->n_read,
+ (unsigned long)ocirc->n_written);
+ ocirc->n_written = ocirc->n_read = 0;
+ }
+
+ return 0;
+}
+
/** Print out CONN_BW event for a single OR/DIR/EXIT <b>conn</b> and reset
* bandwidth counters. */
int
@@ -3960,8 +4010,6 @@ control_event_conn_bandwidth_used(void)
return 0;
}
-extern circuit_t *global_circuitlist;
-
/** Convert the cell <b>command</b> into a lower-case, human-readable
* string. */
static const char *
diff --git a/src/or/control.h b/src/or/control.h
index 2977159..06a3849 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -50,6 +50,7 @@ int control_event_or_conn_status(or_connection_t *conn,
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
int control_event_stream_bandwidth(edge_connection_t *edge_conn);
int control_event_stream_bandwidth_used(void);
+int control_event_circ_bandwidth_used(void);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
diff --git a/src/or/main.c b/src/or/main.c
index ae60548..d381677 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1641,6 +1641,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written);
control_event_stream_bandwidth_used();
control_event_conn_bandwidth_used();
+ control_event_circ_bandwidth_used();
control_event_circuit_cell_stats();
if (server_mode(options) &&
diff --git a/src/or/or.h b/src/or/or.h
index c2be282..d41034c 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2967,6 +2967,15 @@ typedef struct origin_circuit_t {
/** Linked list of AP streams (or EXIT streams if hidden service)
* associated with this circuit. */
edge_connection_t *p_streams;
+
+ /** Bytes read from any attached stream since last call to
+ * control_event_circ_bandwidth_used() */
+ uint32_t n_read;
+
+ /** Bytes written to any attached stream since last call to
+ * control_event_circ_bandwidth_used() */
+ uint32_t n_written;
+
/** Build state for this circuit. It includes the intended path
* length, the chosen exit router, rendezvous information, etc.
*/
1
0

31 Oct '13
commit a84fae789206db4e27486e693488328da7b3474a
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri May 24 11:25:30 2013 +0200
Tweak ORCONN event based on comments by nickm.
- Move new ID= parameter in ORCONN event to end. Avoids possible trouble
from controllers that parse parameters by position, even though they
shouldn't.
---
src/or/control.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/or/control.c b/src/or/control.c
index d3b968c..2accf7f 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -3858,18 +3858,17 @@ control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp,
}
ncircs += connection_or_get_num_circuits(conn);
if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) {
- tor_snprintf(ncircs_buf, sizeof(ncircs_buf), "%sNCIRCS=%d",
- reason ? " " : "", ncircs);
+ tor_snprintf(ncircs_buf, sizeof(ncircs_buf), " NCIRCS=%d", ncircs);
}
orconn_target_get_name(name, sizeof(name), conn);
send_control_event(EVENT_OR_CONN_STATUS, ALL_FORMATS,
- "650 ORCONN %s %s ID="U64_FORMAT" %s%s%s\r\n",
+ "650 ORCONN %s %s%s%s%s ID="U64_FORMAT"\r\n",
name, status,
- U64_PRINTF_ARG(conn->base_.global_identifier),
- reason ? "REASON=" : "",
+ reason ? " REASON=" : "",
orconn_end_reason_to_control_string(reason),
- ncircs_buf);
+ ncircs_buf,
+ U64_PRINTF_ARG(conn->base_.global_identifier));
return 0;
}
1
0

31 Oct '13
commit 2f893624abb65a0df4f0f8ca6fbbe0c00fbf216a
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri May 24 12:01:32 2013 +0200
Tweak CONN_BW event based on comments by nickm.
- Rename read/write counters in connection_t to make it clear that these
are only used for CONN_BW events.
- Add TestingEnableConnBwEvent option.
---
doc/tor.1.txt | 6 ++++++
src/or/config.c | 8 ++++++++
src/or/connection.c | 24 ++++++++++++------------
src/or/control.c | 12 ++++++------
src/or/or.h | 13 +++++++++----
5 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 0a6f8f5..209670a 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -2005,6 +2005,7 @@ The following options are used for running a testing Tor network.
TestingV3AuthInitialDistDelay 20 seconds
TestingAuthDirTimeToLearnReachability 0 minutes
TestingEstimatedDescriptorPropagationTime 0 minutes
+ TestingEnableConnBwEvent 1
**TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**::
Like V3AuthVotingInterval, but for initial voting interval before the first
@@ -2035,6 +2036,11 @@ The following options are used for running a testing Tor network.
Minimum value for the Fast flag. Overrides the ordinary minimum taken
from the consensus when TestingTorNetwork is set. (Default: 0.)
+**TestingEnableConnBwEvent** **0**|**1**::
+ If this option is set, then Tor controllers may register for CONN_BW
+ events. Changing this requires that **TestingTorNetwork** is set.
+ (Default: 0)
+
SIGNALS
-------
diff --git a/src/or/config.c b/src/or/config.c
index 8ca89b6..e7060a5 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -218,6 +218,7 @@ static config_var_t option_vars_[] = {
VPORT(DNSPort, LINELIST, NULL),
V(DNSListenAddress, LINELIST, NULL),
V(DownloadExtraInfo, BOOL, "0"),
+ V(TestingEnableConnBwEvent, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
@@ -461,6 +462,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
+ V(TestingEnableConnBwEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -3236,6 +3238,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high.");
}
+ if (options->TestingEnableConnBwEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableConnBwEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
diff --git a/src/or/connection.c b/src/or/connection.c
index a00351a..f7f028b 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -3224,16 +3224,16 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
}
}
- /* In TestingTorNetwork mode, update conn->n_read for OR/DIR/EXIT
- * connections, checking for overflow. */
- if (get_options()->TestingTorNetwork &&
+ /* If CONN_BW events are enabled, update conn->n_read_conn_bw for
+ * OR/DIR/EXIT connections, checking for overflow. */
+ if (get_options()->TestingEnableConnBwEvent &&
(conn->type == CONN_TYPE_OR ||
conn->type == CONN_TYPE_DIR ||
conn->type == CONN_TYPE_EXIT)) {
- if (PREDICT_LIKELY(UINT32_MAX - conn->n_read > n_read))
- conn->n_read += (int)n_read;
+ if (PREDICT_LIKELY(UINT32_MAX - conn->n_read_conn_bw > n_read))
+ conn->n_read_conn_bw += (int)n_read;
else
- conn->n_read = UINT32_MAX;
+ conn->n_read_conn_bw = UINT32_MAX;
}
}
@@ -3691,16 +3691,16 @@ connection_handle_write_impl(connection_t *conn, int force)
}
}
- /* In TestingTorNetwork mode, update conn->n_written for OR/DIR/EXIT
- * connections, checking for overflow. */
- if (n_written && get_options()->TestingTorNetwork &&
+ /* If CONN_BW events are enabled, update conn->n_written_conn_bw for
+ * OR/DIR/EXIT connections, checking for overflow. */
+ if (n_written && get_options()->TestingEnableConnBwEvent &&
(conn->type == CONN_TYPE_OR ||
conn->type == CONN_TYPE_DIR ||
conn->type == CONN_TYPE_EXIT)) {
- if (PREDICT_LIKELY(UINT32_MAX - conn->n_written > n_written))
- conn->n_written += (int)n_written;
+ if (PREDICT_LIKELY(UINT32_MAX - conn->n_written_conn_bw > n_written))
+ conn->n_written_conn_bw += (int)n_written;
else
- conn->n_written = UINT32_MAX;
+ conn->n_written_conn_bw = UINT32_MAX;
}
connection_buckets_decrement(conn, approx_time(), n_read, n_written);
diff --git a/src/or/control.c b/src/or/control.c
index 2accf7f..10f96b3 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -3967,10 +3967,10 @@ int
control_event_conn_bandwidth(connection_t *conn)
{
const char *conn_type_str;
- if (!get_options()->TestingTorNetwork ||
+ if (!get_options()->TestingEnableConnBwEvent ||
!EVENT_IS_INTERESTING(EVENT_CONN_BW))
return 0;
- if (!conn->n_read && !conn->n_written)
+ if (!conn->n_read_conn_bw && !conn->n_written_conn_bw)
return 0;
switch (conn->type) {
case CONN_TYPE_OR:
@@ -3990,9 +3990,9 @@ control_event_conn_bandwidth(connection_t *conn)
"READ=%lu WRITTEN=%lu\r\n",
U64_PRINTF_ARG(conn->global_identifier),
conn_type_str,
- (unsigned long)conn->n_read,
- (unsigned long)conn->n_written);
- conn->n_written = conn->n_read = 0;
+ (unsigned long)conn->n_read_conn_bw,
+ (unsigned long)conn->n_written_conn_bw);
+ conn->n_written_conn_bw = conn->n_read_conn_bw = 0;
return 0;
}
@@ -4001,7 +4001,7 @@ control_event_conn_bandwidth(connection_t *conn)
int
control_event_conn_bandwidth_used(void)
{
- if (get_options()->TestingTorNetwork &&
+ if (get_options()->TestingEnableConnBwEvent &&
EVENT_IS_INTERESTING(EVENT_CONN_BW)) {
SMARTLIST_FOREACH(get_connection_array(), connection_t *, conn,
control_event_conn_bandwidth(conn));
diff --git a/src/or/or.h b/src/or/or.h
index d41034c..c807fb0 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1249,11 +1249,13 @@ typedef struct connection_t {
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
- /** Bytes read since last call to control_event_conn_bandwidth_used() */
- uint32_t n_read;
+ /** Bytes read since last call to control_event_conn_bandwidth_used().
+ * Only used if we're configured to emit CONN_BW events. */
+ uint32_t n_read_conn_bw;
- /** Bytes written since last call to control_event_conn_bandwidth_used() */
- uint32_t n_written;
+ /** Bytes written since last call to control_event_conn_bandwidth_used().
+ * Only used if we're configured to emit CONN_BW events. */
+ uint32_t n_written_conn_bw;
} connection_t;
/** Subtype of connection_t; used for a listener socket. */
@@ -3983,6 +3985,9 @@ typedef struct {
/** Minimum value for the Fast flag threshold on testing networks. */
uint64_t TestingMinFastFlagThreshold;
+ /** Enable CONN_BW events. Only altered on testing networks. */
+ int TestingEnableConnBwEvent;
+
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
1
0

31 Oct '13
commit b33b366a7f8bcab1c9b4859788e3b2c7d3dcf180
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sat May 25 13:04:33 2013 +0200
Tweak CIRC_BW event based on comments by nickm.
- Rename n_read and n_written in origin_circuit_t to make it clear that
these are only used for CIRC_BW events.
- Extract new code in control_update_global_event_mask to new
clear_circ_bw_fields function.
---
src/or/connection.c | 14 +++++++-------
src/or/control.c | 35 +++++++++++++++++++++--------------
src/or/or.h | 10 ++++++----
3 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index 2f2a421..88def49 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -3271,7 +3271,7 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
/* change *max_to_read */
*max_to_read = at_most - n_read;
- /* Update edge_conn->n_read and ocirc->n_read */
+ /* Update edge_conn->n_read and ocirc->n_read_circ_bw */
if (conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
circuit_t *circ = circuit_get_by_edge_conn(edge_conn);
@@ -3285,10 +3285,10 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
if (circ && CIRCUIT_IS_ORIGIN(circ)) {
ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_read > n_read))
- ocirc->n_read += (int)n_read;
+ if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_read_circ_bw > n_read))
+ ocirc->n_read_circ_bw += (int)n_read;
else
- ocirc->n_read = UINT32_MAX;
+ ocirc->n_read_circ_bw = UINT32_MAX;
}
}
@@ -3752,10 +3752,10 @@ connection_handle_write_impl(connection_t *conn, int force)
if (circ && CIRCUIT_IS_ORIGIN(circ)) {
ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_written > n_written))
- ocirc->n_written += (int)n_written;
+ if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_written_circ_bw > n_written))
+ ocirc->n_written_circ_bw += (int)n_written;
else
- ocirc->n_written = UINT32_MAX;
+ ocirc->n_written_circ_bw = UINT32_MAX;
}
}
diff --git a/src/or/control.c b/src/or/control.c
index ac7be8d..5e2020f 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -237,6 +237,20 @@ log_severity_to_event(int severity)
}
}
+/** Helper: clear bandwidth counters of all origin circuits. */
+static void
+clear_circ_bw_fields(void)
+{
+ circuit_t *circ;
+ origin_circuit_t *ocirc;
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ continue;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
+ }
+}
+
/** Set <b>global_event_mask*</b> to the bitwise OR of each live control
* connection's event_mask field. */
void
@@ -276,14 +290,7 @@ control_update_global_event_mask(void)
}
if (! (old_mask & EVENT_CIRC_BANDWIDTH_USED) &&
(new_mask & EVENT_CIRC_BANDWIDTH_USED)) {
- circuit_t *circ;
- origin_circuit_t *ocirc;
- for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
- if (!CIRCUIT_IS_ORIGIN(circ))
- continue;
- ocirc = TO_ORIGIN_CIRCUIT(circ);
- ocirc->n_written = ocirc->n_read = 0;
- }
+ clear_circ_bw_fields();
}
}
@@ -3893,8 +3900,8 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn)
circ = circuit_get_by_edge_conn(edge_conn);
if (circ && CIRCUIT_IS_ORIGIN(circ)) {
ocirc = TO_ORIGIN_CIRCUIT(circ);
- ocirc->n_read += edge_conn->n_read;
- ocirc->n_written += edge_conn->n_written;
+ ocirc->n_read_circ_bw += edge_conn->n_read;
+ ocirc->n_written_circ_bw += edge_conn->n_written;
}
edge_conn->n_written = edge_conn->n_read = 0;
}
@@ -3947,14 +3954,14 @@ control_event_circ_bandwidth_used(void)
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (!ocirc->n_read && !ocirc->n_written)
+ if (!ocirc->n_read_circ_bw && !ocirc->n_written_circ_bw)
continue;
send_control_event(EVENT_CIRC_BANDWIDTH_USED, ALL_FORMATS,
"650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu\r\n",
ocirc->global_identifier,
- (unsigned long)ocirc->n_read,
- (unsigned long)ocirc->n_written);
- ocirc->n_written = ocirc->n_read = 0;
+ (unsigned long)ocirc->n_read_circ_bw,
+ (unsigned long)ocirc->n_written_circ_bw);
+ ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
}
return 0;
diff --git a/src/or/or.h b/src/or/or.h
index 21a36c9..6dd3ce4 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2971,12 +2971,14 @@ typedef struct origin_circuit_t {
edge_connection_t *p_streams;
/** Bytes read from any attached stream since last call to
- * control_event_circ_bandwidth_used() */
- uint32_t n_read;
+ * 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
- * control_event_circ_bandwidth_used() */
- uint32_t n_written;
+ * control_event_circ_bandwidth_used(). Only used if we're configured
+ * to emit CIRC_BW events. */
+ uint32_t n_written_circ_bw;
/** Build state for this circuit. It includes the intended path
* length, the chosen exit router, rendezvous information, etc.
1
0

31 Oct '13
commit 26b49f525d5b2a4781755d72738491c016dd15a9
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri May 24 12:29:42 2013 +0200
Tweak CELL_STATS event based on comments by nickm.
- Move cell_command_to_string from control.c to command.c.
- Use accessor for global_circuitlist instead of extern.
- Add a struct for cell statistics by command instead of six arrays.
- Split up control_event_circuit_cell_stats by using two helper functions.
- Add TestingEnableCellStatsEvent option.
- Prepare functions for testing.
- Rename a few variables and document a few things better.
---
doc/tor.1.txt | 6 ++
src/or/command.c | 27 +++++++
src/or/command.h | 2 +
src/or/config.c | 8 ++
src/or/control.c | 225 +++++++++++++++++++++++++-----------------------------
src/or/or.h | 17 +++--
src/or/relay.c | 122 +++++++++++++++++------------
src/or/relay.h | 2 +-
8 files changed, 233 insertions(+), 176 deletions(-)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 209670a..253436e 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -2006,6 +2006,7 @@ The following options are used for running a testing Tor network.
TestingAuthDirTimeToLearnReachability 0 minutes
TestingEstimatedDescriptorPropagationTime 0 minutes
TestingEnableConnBwEvent 1
+ TestingEnableCellStatsEvent 1
**TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**::
Like V3AuthVotingInterval, but for initial voting interval before the first
@@ -2041,6 +2042,11 @@ The following options are used for running a testing Tor network.
events. Changing this requires that **TestingTorNetwork** is set.
(Default: 0)
+**TestingEnableCellStatsEvent** **0**|**1**::
+ If this option is set, then Tor controllers may register for CELL_STATS
+ events. Changing this requires that **TestingTorNetwork** is set.
+ (Default: 0)
+
SIGNALS
-------
diff --git a/src/or/command.c b/src/or/command.c
index 876ff52..d086335 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -52,6 +52,33 @@ static void command_process_created_cell(cell_t *cell, channel_t *chan);
static void command_process_relay_cell(cell_t *cell, channel_t *chan);
static void command_process_destroy_cell(cell_t *cell, channel_t *chan);
+/** Convert the cell <b>command</b> into a lower-case, human-readable
+ * string. */
+const char *
+cell_command_to_string(uint8_t command)
+{
+ switch (command) {
+ case CELL_PADDING: return "padding";
+ case CELL_CREATE: return "create";
+ case CELL_CREATED: return "created";
+ case CELL_RELAY: return "relay";
+ case CELL_DESTROY: return "destroy";
+ case CELL_CREATE_FAST: return "create_fast";
+ case CELL_CREATED_FAST: return "created_fast";
+ case CELL_VERSIONS: return "versions";
+ case CELL_NETINFO: return "netinfo";
+ case CELL_RELAY_EARLY: return "relay_early";
+ case CELL_CREATE2: return "create2";
+ case CELL_CREATED2: return "created2";
+ case CELL_VPADDING: return "vpadding";
+ case CELL_CERTS: return "certs";
+ case CELL_AUTH_CHALLENGE: return "auth_challenge";
+ case CELL_AUTHENTICATE: return "authenticate";
+ case CELL_AUTHORIZE: return "authorize";
+ default: return "unrecognized";
+ }
+}
+
#ifdef KEEP_TIMING_STATS
/** This is a wrapper function around the actual function that processes the
* <b>cell</b> that just arrived on <b>conn</b>. Increment <b>*time</b>
diff --git a/src/or/command.h b/src/or/command.h
index 913f46a..adea6ad 100644
--- a/src/or/command.h
+++ b/src/or/command.h
@@ -19,6 +19,8 @@ void command_process_var_cell(channel_t *chan, var_cell_t *cell);
void command_setup_channel(channel_t *chan);
void command_setup_listener(channel_listener_t *chan_l);
+const char *cell_command_to_string(uint8_t command);
+
extern uint64_t stats_n_padding_cells_processed;
extern uint64_t stats_n_create_cells_processed;
extern uint64_t stats_n_created_cells_processed;
diff --git a/src/or/config.c b/src/or/config.c
index e7060a5..7a17a9f 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -219,6 +219,7 @@ static config_var_t option_vars_[] = {
V(DNSListenAddress, LINELIST, NULL),
V(DownloadExtraInfo, BOOL, "0"),
V(TestingEnableConnBwEvent, BOOL, "0"),
+ V(TestingEnableCellStatsEvent, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
@@ -463,6 +464,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
V(TestingEnableConnBwEvent, BOOL, "1"),
+ V(TestingEnableCellStatsEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -3244,6 +3246,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
"Tor networks!");
}
+ if (options->TestingEnableCellStatsEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableCellStatsEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
diff --git a/src/or/control.c b/src/or/control.c
index 10f96b3..c06a911 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -19,6 +19,7 @@
#include "circuitlist.h"
#include "circuitstats.h"
#include "circuituse.h"
+#include "command.h"
#include "config.h"
#include "confparse.h"
#include "connection.h"
@@ -46,8 +47,6 @@
#include <sys/resource.h>
#endif
-extern circuit_t *global_circuitlist; /* from circuitlist.c */
-
#include "procmon.h"
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
@@ -279,7 +278,7 @@ control_update_global_event_mask(void)
(new_mask & EVENT_CIRC_BANDWIDTH_USED)) {
circuit_t *circ;
origin_circuit_t *ocirc;
- for (circ = global_circuitlist; circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -3944,7 +3943,7 @@ control_event_circ_bandwidth_used(void)
if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED))
return 0;
- for (circ = global_circuitlist; circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -4009,162 +4008,150 @@ control_event_conn_bandwidth_used(void)
return 0;
}
-/** Convert the cell <b>command</b> into a lower-case, human-readable
- * string. */
-static const char *
-cell_command_to_string(uint8_t command)
+/** Helper structure: temporarily stores cell statistics for a circuit. */
+typedef struct cell_stats_t {
+ /** Number of cells added in app-ward direction by command. */
+ uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells added in exit-ward direction by command. */
+ uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells removed in app-ward direction by command. */
+ uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells removed in exit-ward direction by command. */
+ uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1];
+ /** Total waiting time of cells in app-ward direction by command. */
+ uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1];
+ /** Total waiting time of cells in exit-ward direction by command. */
+ uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1];
+} cell_stats_t;
+
+/** Helper: iterate over cell statistics of <b>circ</b> and sum up added
+ * cells, removed cells, and waiting times by cell command and direction.
+ * Store results in <b>cell_stats</b>. Free cell statistics of the
+ * circuit afterwards. */
+static void
+sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats)
{
- switch (command) {
- case CELL_PADDING: return "padding";
- case CELL_CREATE: return "create";
- case CELL_CREATED: return "created";
- case CELL_RELAY: return "relay";
- case CELL_DESTROY: return "destroy";
- case CELL_CREATE_FAST: return "create_fast";
- case CELL_CREATED_FAST: return "created_fast";
- case CELL_VERSIONS: return "versions";
- case CELL_NETINFO: return "netinfo";
- case CELL_RELAY_EARLY: return "relay_early";
- case CELL_CREATE2: return "create2";
- case CELL_CREATED2: return "created2";
- case CELL_VPADDING: return "vpadding";
- case CELL_CERTS: return "certs";
- case CELL_AUTH_CHALLENGE: return "auth_challenge";
- case CELL_AUTHENTICATE: return "authenticate";
- case CELL_AUTHORIZE: return "authorize";
- default: return "unrecognized";
- }
+ memset(cell_stats, 0, sizeof(cell_stats_t));
+ SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats,
+ testing_cell_stats_entry_t *, ent) {
+ tor_assert(ent->command <= CELL_COMMAND_MAX_);
+ if (!ent->removed && !ent->exitward) {
+ cell_stats->added_cells_appward[ent->command] += 1;
+ } else if (!ent->removed && ent->exitward) {
+ cell_stats->added_cells_exitward[ent->command] += 1;
+ } else if (!ent->exitward) {
+ cell_stats->removed_cells_appward[ent->command] += 1;
+ cell_stats->total_time_appward[ent->command] += ent->waiting_time * 10;
+ } else {
+ cell_stats->removed_cells_exitward[ent->command] += 1;
+ cell_stats->total_time_exitward[ent->command] += ent->waiting_time * 10;
+ }
+ tor_free(ent);
+ } SMARTLIST_FOREACH_END(ent);
+ smartlist_free(circ->testing_cell_stats);
+ circ->testing_cell_stats = NULL;
}
/** Helper: append a cell statistics string to <code>event_parts</code>,
* prefixed with <code>key</code>=. Statistics consist of comma-separated
* key:value pairs with lower-case command strings as keys and cell
* numbers or total waiting times as values. A key:value pair is included
- * if the entry in <code>include_if_positive</code> is positive, but with
+ * if the entry in <code>include_if_non_zero</code> is not zero, but with
* the (possibly zero) entry from <code>number_to_include</code>. If no
- * entry in <code>include_if_positive</code> is positive, no string will
+ * entry in <code>include_if_non_zero</code> is positive, no string will
* be added to <code>event_parts</code>. */
static void
append_cell_stats_by_command(smartlist_t *event_parts, const char *key,
- uint64_t *include_if_positive,
+ uint64_t *include_if_non_zero,
uint64_t *number_to_include)
{
smartlist_t *key_value_strings = smartlist_new();
int i;
- for (i = 0; i <= CELL_MAX_; i++) {
- if (include_if_positive[i] > 0) {
+ for (i = 0; i <= CELL_COMMAND_MAX_; i++) {
+ if (include_if_non_zero[i] > 0) {
smartlist_add_asprintf(key_value_strings, "%s:"U64_FORMAT,
cell_command_to_string(i),
U64_PRINTF_ARG(number_to_include[i]));
}
}
- if (key_value_strings->num_used > 0) {
+ if (smartlist_len(key_value_strings) > 0) {
char *joined = smartlist_join_strings(key_value_strings, ",", 0, NULL);
- char *result;
- tor_asprintf(&result, "%s=%s", key, joined);
- smartlist_add(event_parts, result);
+ smartlist_add_asprintf(event_parts, "%s=%s", key, joined);
SMARTLIST_FOREACH(key_value_strings, char *, cp, tor_free(cp));
tor_free(joined);
}
smartlist_free(key_value_strings);
}
+/** Helper: format <b>cell_stats</b> for <b>circ</b> for inclusion in a
+ * CELL_STATS event and write result string to <b>event_string</b>. */
+static void
+format_cell_stats(char **event_string, circuit_t *circ,
+ cell_stats_t *cell_stats)
+{
+ smartlist_t *event_parts = smartlist_new();
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ smartlist_add_asprintf(event_parts, "ID=%lu",
+ (unsigned long)ocirc->global_identifier);
+ } else {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ smartlist_add_asprintf(event_parts, "InboundQueue=%lu",
+ (unsigned long)or_circ->p_circ_id);
+ smartlist_add_asprintf(event_parts, "InboundConn="U64_FORMAT,
+ U64_PRINTF_ARG(or_circ->p_chan->global_identifier));
+ append_cell_stats_by_command(event_parts, "InboundAdded",
+ cell_stats->added_cells_appward,
+ cell_stats->added_cells_appward);
+ append_cell_stats_by_command(event_parts, "InboundRemoved",
+ cell_stats->removed_cells_appward,
+ cell_stats->removed_cells_appward);
+ append_cell_stats_by_command(event_parts, "InboundTime",
+ cell_stats->removed_cells_appward,
+ cell_stats->total_time_appward);
+ }
+ if (circ->n_chan) {
+ smartlist_add_asprintf(event_parts, "OutboundQueue=%lu",
+ (unsigned long)circ->n_circ_id);
+ smartlist_add_asprintf(event_parts, "OutboundConn="U64_FORMAT,
+ U64_PRINTF_ARG(circ->n_chan->global_identifier));
+ append_cell_stats_by_command(event_parts, "OutboundAdded",
+ cell_stats->added_cells_exitward,
+ cell_stats->added_cells_exitward);
+ append_cell_stats_by_command(event_parts, "OutboundRemoved",
+ cell_stats->removed_cells_exitward,
+ cell_stats->removed_cells_exitward);
+ append_cell_stats_by_command(event_parts, "OutboundTime",
+ cell_stats->removed_cells_exitward,
+ cell_stats->total_time_exitward);
+ }
+ *event_string = smartlist_join_strings(event_parts, " ", 0, NULL);
+ SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp));
+ smartlist_free(event_parts);
+}
+
/** A second or more has elapsed: tell any interested control connection
* how many cells have been processed for a given circuit. */
int
control_event_circuit_cell_stats(void)
{
- /* These arrays temporarily consume slightly over 6 KiB on the stack
- * every second, most of which are wasted for the non-existant commands
- * between CELL_RELAY_EARLY (9) and CELL_VPADDING (128). But nothing
- * beats the stack when it comes to performance. */
- uint64_t added_cells_appward[CELL_MAX_ + 1],
- added_cells_exitward[CELL_MAX_ + 1],
- removed_cells_appward[CELL_MAX_ + 1],
- removed_cells_exitward[CELL_MAX_ + 1],
- total_time_appward[CELL_MAX_ + 1],
- total_time_exitward[CELL_MAX_ + 1];
circuit_t *circ;
- if (!get_options()->TestingTorNetwork ||
+ cell_stats_t *cell_stats;
+ char *event_string;
+ if (!get_options()->TestingEnableCellStatsEvent ||
!EVENT_IS_INTERESTING(EVENT_CELL_STATS))
return 0;
- for (circ = global_circuitlist; circ; circ = circ->next) {
- smartlist_t *event_parts;
- char *event_string;
-
+ cell_stats = tor_malloc(sizeof(cell_stats_t));;
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!circ->testing_cell_stats)
continue;
-
- memset(added_cells_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- memset(added_cells_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- memset(removed_cells_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- memset(removed_cells_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- memset(total_time_appward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- memset(total_time_exitward, 0, (CELL_MAX_ + 1) * sizeof(uint64_t));
- SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats,
- testing_cell_stats_entry_t *, ent) {
- tor_assert(ent->command <= CELL_MAX_);
- if (!ent->removed && !ent->exit_ward) {
- added_cells_appward[ent->command] += 1;
- } else if (!ent->removed && ent->exit_ward) {
- added_cells_exitward[ent->command] += 1;
- } else if (!ent->exit_ward) {
- removed_cells_appward[ent->command] += 1;
- total_time_appward[ent->command] += ent->waiting_time * 10;
- } else {
- removed_cells_exitward[ent->command] += 1;
- total_time_exitward[ent->command] += ent->waiting_time * 10;
- }
- tor_free(ent);
- } SMARTLIST_FOREACH_END(ent);
- smartlist_free(circ->testing_cell_stats);
- circ->testing_cell_stats = NULL;
-
- event_parts = smartlist_new();
- if (CIRCUIT_IS_ORIGIN(circ)) {
- origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
- char *id_string;
- tor_asprintf(&id_string, "ID=%lu",
- (unsigned long)ocirc->global_identifier);
- smartlist_add(event_parts, id_string);
- } else {
- or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- char *queue_string, *conn_string;
- tor_asprintf(&queue_string, "InboundQueue=%lu",
- (unsigned long)or_circ->p_circ_id);
- tor_asprintf(&conn_string, "InboundConn="U64_FORMAT,
- U64_PRINTF_ARG(or_circ->p_chan->global_identifier));
- smartlist_add(event_parts, queue_string);
- smartlist_add(event_parts, conn_string);
- append_cell_stats_by_command(event_parts, "InboundAdded",
- added_cells_appward, added_cells_appward);
- append_cell_stats_by_command(event_parts, "InboundRemoved",
- removed_cells_appward, removed_cells_appward);
- append_cell_stats_by_command(event_parts, "InboundTime",
- removed_cells_appward, total_time_appward);
- }
- if (circ->n_chan) {
- char *queue_string, *conn_string;
- tor_asprintf(&queue_string, "OutboundQueue=%lu",
- (unsigned long)circ->n_circ_id);
- tor_asprintf(&conn_string, "OutboundConn="U64_FORMAT,
- U64_PRINTF_ARG(circ->n_chan->global_identifier));
- smartlist_add(event_parts, queue_string);
- smartlist_add(event_parts, conn_string);
- append_cell_stats_by_command(event_parts, "OutboundAdded",
- added_cells_exitward, added_cells_exitward);
- append_cell_stats_by_command(event_parts, "OutboundRemoved",
- removed_cells_exitward, removed_cells_exitward);
- append_cell_stats_by_command(event_parts, "OutboundTime",
- removed_cells_exitward, total_time_exitward);
- }
- event_string = smartlist_join_strings(event_parts, " ", 0, NULL);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ format_cell_stats(&event_string, circ, cell_stats);
send_control_event(EVENT_CELL_STATS, ALL_FORMATS,
"650 CELL_STATS %s\r\n", event_string);
- SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp));
- smartlist_free(event_parts);
tor_free(event_string);
}
+ tor_free(cell_stats);
return 0;
}
diff --git a/src/or/or.h b/src/or/or.h
index c807fb0..3702664 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -839,7 +839,7 @@ typedef enum {
#define CELL_AUTH_CHALLENGE 130
#define CELL_AUTHENTICATE 131
#define CELL_AUTHORIZE 132
-#define CELL_MAX_ 132
+#define CELL_COMMAND_MAX_ 132
/** How long to test reachability before complaining to the user. */
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
@@ -1089,7 +1089,7 @@ typedef struct insertion_time_queue_t {
} insertion_time_queue_t;
/** Number of cells with the same command consecutively added to a circuit
- * queue; used for cell statistics only in TestingTorNetwork mode. */
+ * queue; used for cell statistics only if CELL_STATS events are enabled. */
typedef struct insertion_command_elem_t {
struct insertion_command_elem_t *next; /**< Next element in queue. */
/** Which command did these consecutively added cells have? */
@@ -2756,8 +2756,8 @@ typedef struct {
struct create_cell_t;
-/** Entry in the cell stats list of a circuit; used only when
- * TestingTorNetwork is set. */
+/** Entry in the cell stats list of a circuit; used only if CELL_STATS
+ * events are enabled. */
typedef struct testing_cell_stats_entry_t {
uint8_t command; /**< cell command number. */
/** Waiting time in centiseconds if this event is for a removed cell,
@@ -2766,7 +2766,7 @@ typedef struct testing_cell_stats_entry_t {
* delay would long have been closed. */
unsigned int waiting_time:22;
unsigned int removed:1; /**< 0 for added to, 1 for removed from queue. */
- unsigned int exit_ward:1; /**< 0 for app-ward, 1 for exit-ward. */
+ unsigned int exitward:1; /**< 0 for app-ward, 1 for exit-ward. */
} testing_cell_stats_entry_t;
/**
@@ -2896,8 +2896,8 @@ typedef struct circuit_t {
struct circuit_t *prev_active_on_n_chan;
/** Various statistics about cells being added to or removed from this
- * circuit's queues; used only when TestingTorNetwork is set and cleared
- * after being sent to control port. */
+ * circuit's queues; used only if CELL_STATS events are enabled and
+ * cleared after being sent to control port. */
smartlist_t *testing_cell_stats;
} circuit_t;
@@ -3988,6 +3988,9 @@ typedef struct {
/** Enable CONN_BW events. Only altered on testing networks. */
int TestingEnableConnBwEvent;
+ /** Enable CELL_STATS events. Only altered on testing networks. */
+ int TestingEnableCellStatsEvent;
+
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
diff --git a/src/or/relay.c b/src/or/relay.c
index 02b3b1c..66c24f3 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -2046,7 +2046,7 @@ static mp_pool_t *cell_pool = NULL;
static mp_pool_t *it_pool = NULL;
/** Memory pool to allocate insertion_command_elem_t objects used for cell
- * statistics in TestingTorNetwork mode. */
+ * statistics if CELL_STATS events are enabled. */
static mp_pool_t *ic_pool = NULL;
/** Allocate structures to hold cells. */
@@ -2058,7 +2058,7 @@ init_cell_pool(void)
}
/** Free all storage used to hold cells (and insertion times/commands if we
- * measure cell statistics and/or are in TestingTorNetwork mode). */
+ * measure cell statistics and/or if CELL_STATS events are enabled). */
void
free_cell_pool(void)
{
@@ -2153,16 +2153,68 @@ cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
++queue->n;
}
+/** Append command of type <b>command</b> in direction to <b>queue</b> for
+ * CELL_STATS event. */
+static void
+cell_command_queue_append(cell_queue_t *queue, uint8_t command)
+{
+ insertion_command_queue_t *ic_queue = queue->insertion_commands;
+ if (!ic_pool)
+ ic_pool = mp_pool_new(sizeof(insertion_command_elem_t), 1024);
+ if (!ic_queue) {
+ ic_queue = tor_malloc_zero(sizeof(insertion_command_queue_t));
+ queue->insertion_commands = ic_queue;
+ }
+ if (ic_queue->last && ic_queue->last->command == command) {
+ ic_queue->last->counter++;
+ } else {
+ insertion_command_elem_t *elem = mp_pool_get(ic_pool);
+ elem->next = NULL;
+ elem->command = command;
+ elem->counter = 1;
+ if (ic_queue->last) {
+ ic_queue->last->next = elem;
+ ic_queue->last = elem;
+ } else {
+ ic_queue->first = ic_queue->last = elem;
+ }
+ }
+}
+
+/** Retrieve oldest command from <b>queue</b> and write it to
+ * <b>command</b> for CELL_STATS event. Return 0 for success, -1
+ * otherwise. */
+static int
+cell_command_queue_pop(uint8_t *command, cell_queue_t *queue)
+{
+ int res = -1;
+ insertion_command_queue_t *ic_queue = queue->insertion_commands;
+ if (ic_queue && ic_queue->first) {
+ insertion_command_elem_t *ic_elem = ic_queue->first;
+ ic_elem->counter--;
+ if (ic_elem->counter < 1) {
+ ic_queue->first = ic_elem->next;
+ if (ic_elem == ic_queue->last)
+ ic_queue->last = NULL;
+ mp_pool_release(ic_elem);
+ }
+ *command = ic_elem->command;
+ res = 0;
+ }
+ return res;
+}
+
/** Append a newly allocated copy of <b>cell</b> to the end of the
- * <b>exit_ward</b> (or app-ward) <b>queue</b> of <b>circ</b>. */
+ * <b>exitward</b> (or app-ward) <b>queue</b> of <b>circ</b>. */
void
cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
- int exit_ward, const cell_t *cell,
+ int exitward, const cell_t *cell,
int wide_circ_ids)
{
packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
/* Remember the time when this cell was put in the queue. */
- if (get_options()->CellStatistics || get_options()->TestingTorNetwork) {
+ if (get_options()->CellStatistics ||
+ get_options()->TestingEnableCellStatsEvent) {
struct timeval now;
uint32_t added;
insertion_time_queue_t *it_queue = queue->insertion_times;
@@ -2193,35 +2245,15 @@ cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
}
/* Remember that we added a cell to the queue, and remember the cell
* command. */
- if (get_options()->TestingTorNetwork) {
- insertion_command_queue_t *ic_queue = queue->insertion_commands;
+ if (get_options()->TestingEnableCellStatsEvent) {
testing_cell_stats_entry_t *ent =
tor_malloc_zero(sizeof(testing_cell_stats_entry_t));
ent->command = cell->command;
- ent->exit_ward = exit_ward;
+ ent->exitward = exitward;
if (!circ->testing_cell_stats)
circ->testing_cell_stats = smartlist_new();
smartlist_add(circ->testing_cell_stats, ent);
- if (!ic_pool)
- ic_pool = mp_pool_new(sizeof(insertion_command_elem_t), 1024);
- if (!ic_queue) {
- ic_queue = tor_malloc_zero(sizeof(insertion_command_queue_t));
- queue->insertion_commands = ic_queue;
- }
- if (ic_queue->last && ic_queue->last->command == cell->command) {
- ic_queue->last->counter++;
- } else {
- insertion_command_elem_t *elem = mp_pool_get(ic_pool);
- elem->next = NULL;
- elem->command = cell->command;
- elem->counter = 1;
- if (ic_queue->last) {
- ic_queue->last->next = elem;
- ic_queue->last = elem;
- } else {
- ic_queue->first = ic_queue->last = elem;
- }
- }
+ cell_command_queue_append(queue, cell->command);
}
cell_queue_append(queue, copy);
}
@@ -2429,7 +2461,7 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
/* Calculate the exact time that this cell has spent in the queue. */
if (get_options()->CellStatistics ||
- get_options()->TestingTorNetwork) {
+ get_options()->TestingEnableCellStatsEvent) {
struct timeval tvnow;
uint32_t flushed;
uint32_t cell_waiting_time;
@@ -2460,28 +2492,20 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
or_circ->total_cell_waiting_time += cell_waiting_time;
or_circ->processed_cells++;
}
- if (get_options()->TestingTorNetwork) {
- insertion_command_queue_t *ic_queue = queue->insertion_commands;
- if (!ic_queue || !ic_queue->first) {
- log_info(LD_BUG, "Cannot determine command of cell, which "
- "is a bug, because TestingTorNetwork cannot "
- "be enabled while running.");
+ if (get_options()->TestingEnableCellStatsEvent) {
+ uint8_t command;
+ if (cell_command_queue_pop(&command, queue) < 0) {
+ log_info(LD_GENERAL, "Cannot determine command of cell. "
+ "Looks like the CELL_STATS event was "
+ "recently enabled.");
} else {
testing_cell_stats_entry_t *ent =
tor_malloc_zero(sizeof(testing_cell_stats_entry_t));
- insertion_command_elem_t *ic_elem = ic_queue->first;
- ent->command = ic_elem->command;
- ic_elem->counter--;
- if (ic_elem->counter < 1) {
- ic_queue->first = ic_elem->next;
- if (ic_elem == ic_queue->last)
- ic_queue->last = NULL;
- mp_pool_release(ic_elem);
- }
+ ent->command = command;
ent->waiting_time = (unsigned int)cell_waiting_time / 10;
ent->removed = 1;
if (circ->n_chan == chan)
- ent->exit_ward = 1;
+ ent->exitward = 1;
if (!circ->testing_cell_stats)
circ->testing_cell_stats = smartlist_new();
smartlist_add(circ->testing_cell_stats, ent);
@@ -2542,12 +2566,12 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
{
cell_queue_t *queue;
int streams_blocked;
- int exit_ward;
+ int exitward;
if (circ->marked_for_close)
return;
- exit_ward = (direction == CELL_DIRECTION_OUT);
- if (exit_ward) {
+ exitward = (direction == CELL_DIRECTION_OUT);
+ if (exitward) {
queue = &circ->n_chan_cells;
streams_blocked = circ->streams_blocked_on_n_chan;
} else {
@@ -2556,7 +2580,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
streams_blocked = circ->streams_blocked_on_p_chan;
}
- cell_queue_append_packed_copy(circ, queue, exit_ward, cell,
+ cell_queue_append_packed_copy(circ, queue, exitward, cell,
chan->wide_circ_ids);
/* If we have too many cells on the circuit, we should stop reading from
diff --git a/src/or/relay.h b/src/or/relay.h
index e3b392c..b545857 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -53,7 +53,7 @@ void packed_cell_free(packed_cell_t *cell);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
void cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
- int exit_ward, const cell_t *cell,
+ int exitward, const cell_t *cell,
int wide_circ_ids);
void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
1
0

31 Oct '13
commit ef67077fba6061a6e5b9a76caf60a33d17a81ce6
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sat May 25 12:21:09 2013 +0200
Tweak TB_EMPTY event based on comments by nickm.
- Avoid control_event_refill_global function with 13 arguments and
increase code reuse factor by moving more code from control.c to
connection.c.
- Avoid an unsafe uint32_t -> int cast.
- Add TestingEnableTbEmptyEvent option.
- Prepare functions for testing.
- Rename a few functions and improve documentation.
---
doc/tor.1.txt | 6 +++
src/or/config.c | 8 +++
src/or/connection.c | 138 ++++++++++++++++++++++++++++++++++++++-------------
src/or/control.c | 102 +++++--------------------------------
src/or/control.h | 15 ++----
src/or/or.h | 11 ++--
6 files changed, 140 insertions(+), 140 deletions(-)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 253436e..3996334 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -2007,6 +2007,7 @@ The following options are used for running a testing Tor network.
TestingEstimatedDescriptorPropagationTime 0 minutes
TestingEnableConnBwEvent 1
TestingEnableCellStatsEvent 1
+ TestingEnableTbEmptyEvent 1
**TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**::
Like V3AuthVotingInterval, but for initial voting interval before the first
@@ -2047,6 +2048,11 @@ The following options are used for running a testing Tor network.
events. Changing this requires that **TestingTorNetwork** is set.
(Default: 0)
+**TestingEnableTbEmptyEvent** **0**|**1**::
+ If this option is set, then Tor controllers may register for TB_EMPTY
+ events. Changing this requires that **TestingTorNetwork** is set.
+ (Default: 0)
+
SIGNALS
-------
diff --git a/src/or/config.c b/src/or/config.c
index 7a17a9f..4ca0338 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -220,6 +220,7 @@ static config_var_t option_vars_[] = {
V(DownloadExtraInfo, BOOL, "0"),
V(TestingEnableConnBwEvent, BOOL, "0"),
V(TestingEnableCellStatsEvent, BOOL, "0"),
+ V(TestingEnableTbEmptyEvent, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
@@ -465,6 +466,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
V(TestingEnableConnBwEvent, BOOL, "1"),
V(TestingEnableCellStatsEvent, BOOL, "1"),
+ V(TestingEnableTbEmptyEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -3252,6 +3254,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
"Tor networks!");
}
+ if (options->TestingEnableTbEmptyEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableTbEmptyEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
diff --git a/src/or/connection.c b/src/or/connection.c
index f7f028b..2f2a421 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -2541,25 +2541,33 @@ record_num_bytes_transferred(connection_t *conn,
#endif
#ifndef USE_BUFFEREVENTS
-/** Last emptied global or relay buckets in msec since midnight; only used
- * in TestingTorNetwork mode. */
+/** Last time at which the global or relay buckets were emptied in msec
+ * since midnight. */
static uint32_t global_relayed_read_emptied = 0,
global_relayed_write_emptied = 0,
global_read_emptied = 0,
global_write_emptied = 0;
-/** Check if a bucket has just run out of tokens, and if so, note the
- * timestamp for TB_EMPTY events; only used in TestingTorNetwork mode. */
+/** Helper: convert given <b>tvnow</b> time value to milliseconds since
+ * midnight. */
+static uint32_t
+msec_since_midnight(struct timeval tvnow)
+{
+ return (uint32_t)(((tvnow.tv_sec % 86400L) * 1000L) +
+ ((uint32_t)tvnow.tv_usec / (uint32_t)1000L));
+}
+
+/** Check if a bucket which had <b>tokens_before</b> tokens and which got
+ * <b>tokens_removed</b> tokens removed at timestamp <b>tvnow</b> has run
+ * out of tokens, and if so, note the milliseconds since midnight in
+ * <b>timestamp_var</b> for the next TB_EMPTY event. */
static void
-connection_buckets_empty_ts(uint32_t *timestamp_var, int tokens_before,
- size_t tokens_removed)
+connection_buckets_note_empty_ts(uint32_t *timestamp_var,
+ int tokens_before, size_t tokens_removed,
+ struct timeval tvnow)
{
- if (tokens_before > 0 && tokens_before - (int)tokens_removed <= 0) {
- struct timeval tvnow;
- tor_gettimeofday_cached(&tvnow);
- *timestamp_var = (uint32_t)(((tvnow.tv_sec % 86400L) * 1000L) +
- ((uint32_t)tvnow.tv_usec / (uint32_t)1000L));
- }
+ if (tokens_before > 0 && (uint32_t)tokens_before <= tokens_removed)
+ *timestamp_var = msec_since_midnight(tvnow);
}
/** We just read <b>num_read</b> and wrote <b>num_written</b> bytes
@@ -2586,23 +2594,25 @@ connection_buckets_decrement(connection_t *conn, time_t now,
/* If one or more of our token buckets ran dry just now, note the
* timestamp for TB_EMPTY events. */
- if (get_options()->TestingTorNetwork) {
+ if (get_options()->TestingEnableTbEmptyEvent) {
+ struct timeval tvnow;
+ tor_gettimeofday_cached(&tvnow);
if (connection_counts_as_relayed_traffic(conn, now)) {
- connection_buckets_empty_ts(&global_relayed_read_emptied,
- global_relayed_read_bucket, num_read);
- connection_buckets_empty_ts(&global_relayed_write_emptied,
- global_relayed_write_bucket, num_written);
+ connection_buckets_note_empty_ts(&global_relayed_read_emptied,
+ global_relayed_read_bucket, num_read, tvnow);
+ connection_buckets_note_empty_ts(&global_relayed_write_emptied,
+ global_relayed_write_bucket, num_written, tvnow);
}
- connection_buckets_empty_ts(&global_read_emptied, global_read_bucket,
- num_read);
- connection_buckets_empty_ts(&global_write_emptied, global_write_bucket,
- num_written);
+ connection_buckets_note_empty_ts(&global_read_emptied,
+ global_read_bucket, num_read, tvnow);
+ connection_buckets_note_empty_ts(&global_write_emptied,
+ global_write_bucket, num_written, tvnow);
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
or_connection_t *or_conn = TO_OR_CONN(conn);
- connection_buckets_empty_ts(&or_conn->read_emptied_time,
- or_conn->read_bucket, num_read);
- connection_buckets_empty_ts(&or_conn->write_emptied_time,
- or_conn->write_bucket, num_written);
+ connection_buckets_note_empty_ts(&or_conn->read_emptied_time,
+ or_conn->read_bucket, num_read, tvnow);
+ connection_buckets_note_empty_ts(&or_conn->write_emptied_time,
+ or_conn->write_bucket, num_written, tvnow);
}
}
@@ -2712,6 +2722,28 @@ connection_bucket_refill_helper(int *bucket, int rate, int burst,
}
}
+/** Helper: return the time in milliseconds since <b>last_empty_time</b>
+ * when a bucket ran empty that previously had <b>tokens_before</b> tokens
+ * now has <b>tokens_after</b> tokens after refilling at timestamp
+ * <b>tvnow</b>, capped at <b>milliseconds_elapsed</b> milliseconds since
+ * last refilling that bucket. Return 0 if the bucket has not been empty
+ * since the last refill or has not been refilled. */
+static uint32_t
+bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
+ int tokens_after, int milliseconds_elapsed,
+ struct timeval tvnow)
+{
+ uint32_t result = 0, refilled;
+ if (tokens_before <= 0 && tokens_after > tokens_before) {
+ refilled = msec_since_midnight(tvnow);
+ result = (uint32_t)((refilled + 86400L * 1000L - last_empty_time) %
+ (86400L * 1000L));
+ if (result > (uint32_t)milliseconds_elapsed)
+ result = (uint32_t)milliseconds_elapsed;
+ }
+ return result;
+}
+
/** Time has passed; increment buckets appropriately. */
void
connection_bucket_refill(int milliseconds_elapsed, time_t now)
@@ -2724,6 +2756,7 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
int prev_global_write = global_write_bucket;
int prev_relay_read = global_relayed_read_bucket;
int prev_relay_write = global_relayed_write_bucket;
+ struct timeval tvnow; /*< Only used if TB_EMPTY events are enabled. */
bandwidthrate = (int)options->BandwidthRate;
bandwidthburst = (int)options->BandwidthBurst;
@@ -2759,14 +2792,31 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
milliseconds_elapsed,
"global_relayed_write_bucket");
- control_event_refill_global(global_read_bucket, prev_global_read,
- global_read_emptied, global_write_bucket,
- prev_global_write, global_write_emptied,
- global_relayed_read_bucket, prev_relay_read,
- global_relayed_read_emptied,
- global_relayed_write_bucket, prev_relay_write,
- global_relayed_write_emptied,
- milliseconds_elapsed);
+ /* If buckets were empty before and have now been refilled, tell any
+ * interested controllers. */
+ if (get_options()->TestingEnableTbEmptyEvent) {
+ uint32_t global_read_empty_time, global_write_empty_time,
+ relay_read_empty_time, relay_write_empty_time;
+ tor_gettimeofday_cached(&tvnow);
+ global_read_empty_time = bucket_millis_empty(prev_global_read,
+ global_read_emptied, global_read_bucket,
+ milliseconds_elapsed, tvnow);
+ global_write_empty_time = bucket_millis_empty(prev_global_write,
+ global_write_emptied, global_write_bucket,
+ milliseconds_elapsed, tvnow);
+ control_event_tb_empty("GLOBAL", global_read_empty_time,
+ global_write_empty_time, milliseconds_elapsed);
+ relay_read_empty_time = bucket_millis_empty(prev_relay_read,
+ global_relayed_read_emptied,
+ global_relayed_read_bucket,
+ milliseconds_elapsed, tvnow);
+ relay_write_empty_time = bucket_millis_empty(prev_relay_write,
+ global_relayed_write_emptied,
+ global_relayed_write_bucket,
+ milliseconds_elapsed, tvnow);
+ control_event_tb_empty("RELAY", relay_read_empty_time,
+ relay_write_empty_time, milliseconds_elapsed);
+ }
/* refill the per-connection buckets */
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
@@ -2793,8 +2843,26 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
"or_conn->write_bucket");
}
- control_event_refill_conn(or_conn, prev_conn_read, prev_conn_write,
- (uint32_t)milliseconds_elapsed);
+ /* If buckets were empty before and have now been refilled, tell any
+ * interested controllers. */
+ if (get_options()->TestingEnableTbEmptyEvent) {
+ char *bucket;
+ uint32_t conn_read_empty_time, conn_write_empty_time;
+ tor_asprintf(&bucket, "ORCONN ID="U64_FORMAT,
+ U64_PRINTF_ARG(or_conn->base_.global_identifier));
+ conn_read_empty_time = bucket_millis_empty(prev_conn_read,
+ or_conn->read_emptied_time,
+ or_conn->read_bucket,
+ milliseconds_elapsed, tvnow);
+ conn_write_empty_time = bucket_millis_empty(prev_conn_write,
+ or_conn->write_emptied_time,
+ or_conn->write_bucket,
+ milliseconds_elapsed, tvnow);
+ control_event_tb_empty(bucket, conn_read_empty_time,
+ conn_write_empty_time,
+ milliseconds_elapsed);
+ tor_free(bucket);
+ }
}
if (conn->read_blocked_on_bw == 1 /* marked to turn reading back on now */
diff --git a/src/or/control.c b/src/or/control.c
index c06a911..ac7be8d 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -4155,99 +4155,23 @@ control_event_circuit_cell_stats(void)
return 0;
}
-/** Helper: return the time in millis that a given bucket was empty,
- * capped at the time in millis since last refilling that bucket. Return
- * 0 if the bucket was not empty during the last refill period. */
-static uint32_t
-bucket_millis_empty(int prev_tokens, uint32_t last_empty_time,
- uint32_t milliseconds_elapsed)
-{
- uint32_t result = 0, refilled;
- if (prev_tokens <= 0) {
- struct timeval tvnow;
- tor_gettimeofday_cached(&tvnow);
- refilled = (uint32_t)((tvnow.tv_sec % 86400L) * 1000L +
- (uint32_t)tvnow.tv_usec / (uint32_t)1000L);
- result = (uint32_t)((refilled + 86400L * 1000L - last_empty_time) %
- (86400L * 1000L));
- if (result > milliseconds_elapsed)
- result = milliseconds_elapsed;
- }
- return result;
-}
-
-/** Token buckets have been refilled: tell any interested control
- * connections how global and relay token buckets have changed. */
+/** Tokens in <b>bucket</b> have been refilled: the read bucket was empty
+ * for <b>read_empty_time</b> millis, the write bucket was empty for
+ * <b>write_empty_time</b> millis, and buckets were last refilled
+ * <b>milliseconds_elapsed</b> millis ago. Only emit TB_EMPTY event if
+ * either read or write bucket have been empty before. */
int
-control_event_refill_global(int global_read, int prev_global_read,
- uint32_t global_read_emptied_time,
- int global_write, int prev_global_write,
- uint32_t global_write_emptied_time,
- int relay_read, int prev_relay_read,
- uint32_t relay_read_emptied_time,
- int relay_write, int prev_relay_write,
- uint32_t relay_write_emptied_time,
- uint32_t milliseconds_elapsed)
+control_event_tb_empty(const char *bucket, uint32_t read_empty_time,
+ uint32_t write_empty_time,
+ int milliseconds_elapsed)
{
- uint32_t global_read_empty_time, global_write_empty_time,
- relay_read_empty_time, relay_write_empty_time;
- if (!get_options()->TestingTorNetwork ||
- !EVENT_IS_INTERESTING(EVENT_TB_EMPTY))
- return 0;
- if (prev_global_read == global_read &&
- prev_global_write == global_write &&
- prev_relay_read == relay_read &&
- prev_relay_write == relay_write)
- return 0;
- if (prev_global_read <= 0 && prev_global_write <= 0) {
- global_read_empty_time = bucket_millis_empty(prev_global_read,
- global_read_emptied_time, milliseconds_elapsed);
- global_write_empty_time = bucket_millis_empty(prev_global_write,
- global_write_emptied_time, milliseconds_elapsed);
+ if (get_options()->TestingEnableTbEmptyEvent &&
+ EVENT_IS_INTERESTING(EVENT_TB_EMPTY) &&
+ (read_empty_time > 0 || write_empty_time > 0)) {
send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
- "650 TB_EMPTY GLOBAL READ=%d WRITTEN=%d "
+ "650 TB_EMPTY %s READ=%d WRITTEN=%d "
"LAST=%d\r\n",
- global_read_empty_time, global_write_empty_time,
- milliseconds_elapsed);
- }
- if (prev_relay_read <= 0 && prev_relay_write <= 0) {
- relay_read_empty_time = bucket_millis_empty(prev_relay_read,
- relay_read_emptied_time, milliseconds_elapsed);
- relay_write_empty_time = bucket_millis_empty(prev_relay_write,
- relay_write_emptied_time, milliseconds_elapsed);
- send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
- "650 TB_EMPTY RELAY READ=%d WRITTEN=%d "
- "LAST=%d\r\n",
- relay_read_empty_time, relay_write_empty_time,
- milliseconds_elapsed);
- }
- return 0;
-}
-
-/** Token buckets of a connection have been refilled: tell any interested
- * control connections how per-connection token buckets have changed. */
-int
-control_event_refill_conn(or_connection_t *or_conn,
- int prev_read, int prev_write,
- uint32_t milliseconds_elapsed)
-{
- uint32_t read_bucket_empty_time, write_bucket_empty_time;
- if (!get_options()->TestingTorNetwork ||
- !EVENT_IS_INTERESTING(EVENT_TB_EMPTY))
- return 0;
- if (prev_read == or_conn->read_bucket &&
- prev_write == or_conn->write_bucket)
- return 0;
- if (prev_read <= 0 || prev_write <= 0) {
- read_bucket_empty_time = bucket_millis_empty(prev_read,
- or_conn->read_emptied_time, milliseconds_elapsed);
- write_bucket_empty_time = bucket_millis_empty(prev_write,
- or_conn->write_emptied_time, milliseconds_elapsed);
- send_control_event(EVENT_TB_EMPTY, ALL_FORMATS,
- "650 TB_EMPTY ORCONN ID="U64_FORMAT" READ=%d "
- "WRITTEN=%d LAST=%d\r\n",
- U64_PRINTF_ARG(or_conn->base_.global_identifier),
- read_bucket_empty_time, write_bucket_empty_time,
+ bucket, read_empty_time, write_empty_time,
milliseconds_elapsed);
}
return 0;
diff --git a/src/or/control.h b/src/or/control.h
index 06a3849..c79c432 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -54,18 +54,9 @@ int control_event_circ_bandwidth_used(void);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
-int control_event_refill_global(int global_read, int prev_global_read,
- uint32_t global_read_emptied,
- int global_write, int prev_global_write,
- uint32_t global_write_emptied,
- int relay_read, int prev_relay_read,
- uint32_t relay_read_emptied,
- int relay_write, int prev_relay_write,
- uint32_t relay_write_emptied,
- uint32_t milliseconds_elapsed);
-int control_event_refill_conn(or_connection_t *or_conn,
- int prev_read, int prev_write,
- uint32_t milliseconds_elapsed);
+int control_event_tb_empty(const char *bucket, uint32_t read_empty_time,
+ uint32_t write_empty_time,
+ int milliseconds_elapsed);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
diff --git a/src/or/or.h b/src/or/or.h
index 3702664..21a36c9 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1479,11 +1479,11 @@ typedef struct or_connection_t {
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
- /** Last emptied read token bucket in msec since midnight; only used in
- * TestingTorNetwork mode. */
+ /** Last emptied read token bucket in msec since midnight; only used if
+ * TB_EMPTY events are enabled. */
uint32_t read_emptied_time;
- /** Last emptied write token bucket in msec since midnight; only used in
- * TestingTorNetwork mode. */
+ /** Last emptied write token bucket in msec since midnight; only used if
+ * TB_EMPTY events are enabled. */
uint32_t write_emptied_time;
} or_connection_t;
@@ -3991,6 +3991,9 @@ typedef struct {
/** Enable CELL_STATS events. Only altered on testing networks. */
int TestingEnableCellStatsEvent;
+ /** Enable TB_EMPTY events. Only altered on testing networks. */
+ int TestingEnableTbEmptyEvent;
+
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
1
0

[tor/master] Test functions used for TB_EMPTY and CELL_STATS events.
by nickm@torproject.org 31 Oct '13
by nickm@torproject.org 31 Oct '13
31 Oct '13
commit e39292f21dd363bd7601b63b4f43a95705c3332b
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri May 31 15:51:25 2013 +0200
Test functions used for TB_EMPTY and CELL_STATS events.
---
src/or/connection.c | 5 +-
src/or/connection.h | 11 ++
src/or/control.c | 22 +--
src/or/control.h | 26 +++-
src/test/Makefile.nmake | 6 +-
src/test/include.am | 1 +
src/test/test.c | 2 +
src/test/test_controller_events.c | 283 +++++++++++++++++++++++++++++++++++++
8 files changed, 331 insertions(+), 25 deletions(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index 88def49..8425239 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -17,6 +17,7 @@
* part of a subclass (channel_tls_t).
*/
#define TOR_CHANNEL_INTERNAL_
+#define CONNECTION_PRIVATE
#include "channel.h"
#include "channeltls.h"
#include "circuitbuild.h"
@@ -2561,7 +2562,7 @@ msec_since_midnight(struct timeval tvnow)
* <b>tokens_removed</b> tokens removed at timestamp <b>tvnow</b> has run
* out of tokens, and if so, note the milliseconds since midnight in
* <b>timestamp_var</b> for the next TB_EMPTY event. */
-static void
+void
connection_buckets_note_empty_ts(uint32_t *timestamp_var,
int tokens_before, size_t tokens_removed,
struct timeval tvnow)
@@ -2728,7 +2729,7 @@ connection_bucket_refill_helper(int *bucket, int rate, int burst,
* <b>tvnow</b>, capped at <b>milliseconds_elapsed</b> milliseconds since
* last refilling that bucket. Return 0 if the bucket has not been empty
* since the last refill or has not been refilled. */
-static uint32_t
+uint32_t
bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
int tokens_after, int milliseconds_elapsed,
struct timeval tvnow)
diff --git a/src/or/connection.h b/src/or/connection.h
index 3e656ec..c0894cd 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -214,5 +214,16 @@ void connection_enable_rate_limiting(connection_t *conn);
#define connection_type_uses_bufferevent(c) (0)
#endif
+#ifdef CONNECTION_PRIVATE
+/* Used only by connection.c and test*.c */
+uint32_t bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
+ int tokens_after, int milliseconds_elapsed,
+ struct timeval tvnow);
+void connection_buckets_note_empty_ts(uint32_t *timestamp_var,
+ int tokens_before,
+ size_t tokens_removed,
+ struct timeval tvnow);
+#endif
+
#endif
diff --git a/src/or/control.c b/src/or/control.c
index 5e2020f..495b7d7 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -4015,27 +4015,11 @@ control_event_conn_bandwidth_used(void)
return 0;
}
-/** Helper structure: temporarily stores cell statistics for a circuit. */
-typedef struct cell_stats_t {
- /** Number of cells added in app-ward direction by command. */
- uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1];
- /** Number of cells added in exit-ward direction by command. */
- uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1];
- /** Number of cells removed in app-ward direction by command. */
- uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1];
- /** Number of cells removed in exit-ward direction by command. */
- uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1];
- /** Total waiting time of cells in app-ward direction by command. */
- uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1];
- /** Total waiting time of cells in exit-ward direction by command. */
- uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1];
-} cell_stats_t;
-
/** Helper: iterate over cell statistics of <b>circ</b> and sum up added
* cells, removed cells, and waiting times by cell command and direction.
* Store results in <b>cell_stats</b>. Free cell statistics of the
* circuit afterwards. */
-static void
+void
sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats)
{
memset(cell_stats, 0, sizeof(cell_stats_t));
@@ -4067,7 +4051,7 @@ sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats)
* the (possibly zero) entry from <code>number_to_include</code>. If no
* entry in <code>include_if_non_zero</code> is positive, no string will
* be added to <code>event_parts</code>. */
-static void
+void
append_cell_stats_by_command(smartlist_t *event_parts, const char *key,
uint64_t *include_if_non_zero,
uint64_t *number_to_include)
@@ -4092,7 +4076,7 @@ append_cell_stats_by_command(smartlist_t *event_parts, const char *key,
/** Helper: format <b>cell_stats</b> for <b>circ</b> for inclusion in a
* CELL_STATS event and write result string to <b>event_string</b>. */
-static void
+void
format_cell_stats(char **event_string, circuit_t *circ,
cell_stats_t *cell_stats)
{
diff --git a/src/or/control.h b/src/or/control.h
index c79c432..1773a87 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -97,9 +97,33 @@ void control_event_bootstrap_problem(const char *warn, int reason);
void control_event_clients_seen(const char *controller_str);
#ifdef CONTROL_PRIVATE
-/* Used only by control.c and test.c */
+/* Used only by control.c and test*.c */
size_t write_escaped_data(const char *data, size_t len, char **out);
size_t read_escaped_data(const char *data, size_t len, char **out);
+
+/** Helper structure: temporarily stores cell statistics for a circuit. */
+typedef struct cell_stats_t {
+ /** Number of cells added in app-ward direction by command. */
+ uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells added in exit-ward direction by command. */
+ uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells removed in app-ward direction by command. */
+ uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1];
+ /** Number of cells removed in exit-ward direction by command. */
+ uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1];
+ /** Total waiting time of cells in app-ward direction by command. */
+ uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1];
+ /** Total waiting time of cells in exit-ward direction by command. */
+ uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1];
+} cell_stats_t;
+void sum_up_cell_stats_by_command(circuit_t *circ,
+ cell_stats_t *cell_stats);
+void append_cell_stats_by_command(smartlist_t *event_parts,
+ const char *key,
+ uint64_t *include_if_non_zero,
+ uint64_t *number_to_include);
+void format_cell_stats(char **event_string, circuit_t *circ,
+ cell_stats_t *cell_stats);
#endif
#endif
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index 562c8df..6479f9d 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -12,9 +12,9 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \
crypt32.lib gdi32.lib user32.lib
TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \
- test_crypto.obj test_data.obj test_dir.obj test_microdesc.obj \
- test_pt.obj test_util.obj test_config.obj test_cell_formats.obj \
- test_replay.obj test_introduce.obj tinytest.obj
+ test_controller_events.ogj test_crypto.obj test_data.obj test_dir.obj \
+ test_microdesc.obj test_pt.obj test_util.obj test_config.obj \
+ test_cell_formats.obj test_replay.obj test_introduce.obj tinytest.obj
tinytest.obj: ..\ext\tinytest.c
$(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
diff --git a/src/test/include.am b/src/test/include.am
index 112d1a7..84a7643 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -16,6 +16,7 @@ src_test_test_SOURCES = \
src/test/test_addr.c \
src/test/test_cell_formats.c \
src/test/test_containers.c \
+ src/test/test_controller_events.c \
src/test/test_crypto.c \
src/test/test_data.c \
src/test/test_dir.c \
diff --git a/src/test/test.c b/src/test/test.c
index a9cf899..eec591a 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -2133,6 +2133,7 @@ extern struct testcase_t config_tests[];
extern struct testcase_t introduce_tests[];
extern struct testcase_t replaycache_tests[];
extern struct testcase_t cell_format_tests[];
+extern struct testcase_t controller_event_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@@ -2148,6 +2149,7 @@ static struct testgroup_t testgroups[] = {
{ "config/", config_tests },
{ "replaycache/", replaycache_tests },
{ "introduce/", introduce_tests },
+ { "control/", controller_event_tests },
END_OF_GROUPS
};
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
new file mode 100644
index 0000000..28ba4fa
--- /dev/null
+++ b/src/test/test_controller_events.c
@@ -0,0 +1,283 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONNECTION_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
+#define CONTROL_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "connection.h"
+#include "control.h"
+#include "test.h"
+
+static void
+help_test_bucket_note_empty(uint32_t expected_msec_since_midnight,
+ int tokens_before, size_t tokens_removed,
+ uint32_t msec_since_epoch)
+{
+ uint32_t timestamp_var = 0;
+ struct timeval tvnow;
+ tvnow.tv_sec = msec_since_epoch / 1000;
+ tvnow.tv_usec = (msec_since_epoch % 1000) * 1000;
+ connection_buckets_note_empty_ts(×tamp_var, tokens_before,
+ tokens_removed, tvnow);
+ tt_int_op(expected_msec_since_midnight, ==, timestamp_var);
+
+ done:
+ ;
+}
+
+static void
+test_cntev_bucket_note_empty(void *arg)
+{
+ (void)arg;
+
+ /* Two cases with nothing to note, because bucket was empty before;
+ * 86442200 == 1970-01-02 00:00:42.200000 */
+ help_test_bucket_note_empty(0, 0, 0, 86442200);
+ help_test_bucket_note_empty(0, -100, 100, 86442200);
+
+ /* Nothing to note, because bucket has not been emptied. */
+ help_test_bucket_note_empty(0, 101, 100, 86442200);
+
+ /* Bucket was emptied, note 42200 msec since midnight. */
+ help_test_bucket_note_empty(42200, 101, 101, 86442200);
+ help_test_bucket_note_empty(42200, 101, 102, 86442200);
+}
+
+static void
+test_cntev_bucket_millis_empty(void *arg)
+{
+ struct timeval tvnow;
+ (void)arg;
+
+ /* 1970-01-02 00:00:42.200000 */
+ tvnow.tv_sec = 86400 + 42;
+ tvnow.tv_usec = 200000;
+
+ /* Bucket has not been refilled. */
+ tt_int_op(0, ==, bucket_millis_empty(0, 42120, 0, 100, tvnow));
+ tt_int_op(0, ==, bucket_millis_empty(-10, 42120, -10, 100, tvnow));
+
+ /* Bucket was not empty. */
+ tt_int_op(0, ==, bucket_millis_empty(10, 42120, 20, 100, tvnow));
+
+ /* Bucket has been emptied 80 msec ago and has just been refilled. */
+ tt_int_op(80, ==, bucket_millis_empty(-20, 42120, -10, 100, tvnow));
+ tt_int_op(80, ==, bucket_millis_empty(-10, 42120, 0, 100, tvnow));
+ tt_int_op(80, ==, bucket_millis_empty(0, 42120, 10, 100, tvnow));
+
+ /* Bucket has been emptied 180 msec ago, last refill was 100 msec ago
+ * which was insufficient to make it positive, so cap msec at 100. */
+ tt_int_op(100, ==, bucket_millis_empty(0, 42020, 1, 100, tvnow));
+
+ /* 1970-01-02 00:00:00:050000 */
+ tvnow.tv_sec = 86400;
+ tvnow.tv_usec = 50000;
+
+ /* Last emptied 30 msec before midnight, tvnow is 50 msec after
+ * midnight, that's 80 msec in total. */
+ tt_int_op(80, ==, bucket_millis_empty(0, 86400000 - 30, 1, 100, tvnow));
+
+ done:
+ ;
+}
+
+static void
+add_testing_cell_stats_entry(circuit_t *circ, uint8_t command,
+ unsigned int waiting_time,
+ unsigned int removed, unsigned int exitward)
+{
+ testing_cell_stats_entry_t *ent = tor_malloc_zero(
+ sizeof(testing_cell_stats_entry_t));
+ ent->command = command;
+ ent->waiting_time = waiting_time;
+ ent->removed = removed;
+ ent->exitward = exitward;
+ if (!circ->testing_cell_stats)
+ circ->testing_cell_stats = smartlist_new();
+ smartlist_add(circ->testing_cell_stats, ent);
+}
+
+static void
+test_cntev_sum_up_cell_stats(void *arg)
+{
+ or_circuit_t *or_circ;
+ circuit_t *circ;
+ cell_stats_t *cell_stats;
+ (void)arg;
+
+ or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
+ circ = TO_CIRCUIT(or_circ);
+
+ /* A single RELAY cell was added to the appward queue. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 0);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_int_op(1, ==, cell_stats->added_cells_appward[CELL_RELAY]);
+
+ /* A single RELAY cell was added to the exitward queue. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 1);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_int_op(1, ==, cell_stats->added_cells_exitward[CELL_RELAY]);
+
+ /* A single RELAY cell was removed from the appward queue where it spent
+ * 20 msec. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 2, 1, 0);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_int_op(20, ==, cell_stats->total_time_appward[CELL_RELAY]);
+ tt_int_op(1, ==, cell_stats->removed_cells_appward[CELL_RELAY]);
+
+ /* A single RELAY cell was removed from the exitward queue where it
+ * spent 30 msec. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 3, 1, 1);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_int_op(30, ==, cell_stats->total_time_exitward[CELL_RELAY]);
+ tt_int_op(1, ==, cell_stats->removed_cells_exitward[CELL_RELAY]);
+
+ done:
+ ;
+}
+
+static void
+test_cntev_append_cell_stats(void *arg)
+{
+ smartlist_t *event_parts;
+ const char *key = "Z";
+ uint64_t include_if_non_zero[CELL_COMMAND_MAX_ + 1],
+ number_to_include[CELL_COMMAND_MAX_ + 1];
+ (void)arg;
+
+ event_parts = smartlist_new();
+ memset(include_if_non_zero, 0,
+ (CELL_COMMAND_MAX_ + 1) * sizeof(uint64_t));
+ memset(number_to_include, 0,
+ (CELL_COMMAND_MAX_ + 1) * sizeof(uint64_t));
+
+ /* All array entries empty. */
+ append_cell_stats_by_command(event_parts, key, include_if_non_zero,
+ number_to_include);
+ tt_int_op(0, ==, smartlist_len(event_parts));
+
+ /* There's a RELAY cell to include, but the corresponding field in
+ * include_if_non_zero is still zero. */
+ number_to_include[CELL_RELAY] = 1;
+ append_cell_stats_by_command(event_parts, key, include_if_non_zero,
+ number_to_include);
+ tt_int_op(0, ==, smartlist_len(event_parts));
+
+ /* Now include single RELAY cell. */
+ include_if_non_zero[CELL_RELAY] = 2;
+ append_cell_stats_by_command(event_parts, key, include_if_non_zero,
+ number_to_include);
+ tt_str_op("Z=relay:1", ==, smartlist_pop_last(event_parts));
+
+ /* Add four CREATE cells. */
+ include_if_non_zero[CELL_CREATE] = 3;
+ number_to_include[CELL_CREATE] = 4;
+ append_cell_stats_by_command(event_parts, key, include_if_non_zero,
+ number_to_include);
+ tt_str_op("Z=create:4,relay:1", ==, smartlist_pop_last(event_parts));
+
+ done:
+ ;
+}
+
+static void
+test_cntev_format_cell_stats(void *arg)
+{
+ char *event_string;
+ origin_circuit_t *ocirc;
+ or_circuit_t *or_circ;
+ cell_stats_t *cell_stats;
+ channel_tls_t *n_chan, *p_chan;
+ (void)arg;
+
+ n_chan = tor_malloc_zero(sizeof(channel_tls_t));
+ n_chan->base_.global_identifier = 1;
+
+ ocirc = tor_malloc_zero(sizeof(origin_circuit_t));
+ ocirc->base_.magic = ORIGIN_CIRCUIT_MAGIC;
+ ocirc->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ ocirc->global_identifier = 2;
+ ocirc->base_.n_circ_id = 3;
+ ocirc->base_.n_chan = &(n_chan->base_);
+
+ /* Origin circuit was completely idle. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1", ==, event_string);
+
+ /* Origin circuit had 4 RELAY cells added to its exitward queue. */
+ cell_stats->added_cells_exitward[CELL_RELAY] = 4;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4",
+ ==, event_string);
+
+ /* Origin circuit also had 5 CREATE2 cells added to its exitward
+ * queue. */
+ cell_stats->added_cells_exitward[CELL_CREATE2] = 5;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
+ "create2:5", ==, event_string);
+
+ /* Origin circuit also had 7 RELAY cells removed from its exitward queue
+ * which together spent 6 msec in the queue. */
+ cell_stats->total_time_exitward[CELL_RELAY] = 6;
+ cell_stats->removed_cells_exitward[CELL_RELAY] = 7;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
+ "create2:5 OutboundRemoved=relay:7 OutboundTime=relay:6",
+ ==, event_string);
+
+ p_chan = tor_malloc_zero(sizeof(channel_tls_t));
+ p_chan->base_.global_identifier = 2;
+
+ or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
+ or_circ->p_circ_id = 8;
+ or_circ->p_chan = &(p_chan->base_);
+ or_circ->base_.n_circ_id = 9;
+ or_circ->base_.n_chan = &(n_chan->base_);
+
+ /* OR circuit was idle. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 OutboundQueue=9 OutboundConn=1",
+ ==, event_string);
+
+ /* OR circuit had 3 RELAY cells added to its appward queue. */
+ cell_stats->added_cells_appward[CELL_RELAY] = 3;
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
+ "OutboundQueue=9 OutboundConn=1", ==, event_string);
+
+ /* OR circuit had 7 RELAY cells removed from its appward queue which
+ * together spent 6 msec in the queue. */
+ cell_stats->total_time_appward[CELL_RELAY] = 6;
+ cell_stats->removed_cells_appward[CELL_RELAY] = 7;
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
+ "InboundRemoved=relay:7 InboundTime=relay:6 "
+ "OutboundQueue=9 OutboundConn=1", ==, event_string);
+
+ done:
+ ;
+}
+
+#define TEST(name, flags) \
+ { #name, test_cntev_ ## name, flags, 0, NULL }
+
+struct testcase_t controller_event_tests[] = {
+ TEST(bucket_note_empty, 0),
+ TEST(bucket_millis_empty, 0),
+ TEST(sum_up_cell_stats, 0),
+ TEST(append_cell_stats, 0),
+ TEST(format_cell_stats, 0),
+ END_OF_TESTCASES
+};
+
1
0
commit 9e0ed8136a53665a21ecdf2bc335cc8ce438e0c8
Author: George Kadianakis <desnacked(a)riseup.net>
Date: Tue Oct 29 22:49:37 2013 +0000
Fix an always-true assert in PT code.
---
changes/bug10046 | 3 +++
src/or/transports.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/changes/bug10046 b/changes/bug10046
new file mode 100644
index 0000000..b2f545e
--- /dev/null
+++ b/changes/bug10046
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Fix an always-true assertion in pluggable transports code. Fixes
+ issue 10046. Found by dcb.
diff --git a/src/or/transports.c b/src/or/transports.c
index f9499eb..8b4a118 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -552,7 +552,7 @@ pt_configure_remaining_proxies(void)
assert_unconfigured_count_ok();
SMARTLIST_FOREACH_BEGIN(tmp, managed_proxy_t *, mp) {
- tor_assert(mp->conf_state != PT_PROTO_BROKEN ||
+ tor_assert(mp->conf_state != PT_PROTO_BROKEN &&
mp->conf_state != PT_PROTO_FAILED_LAUNCH);
if (mp->got_hup) {
1
0