summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/Makefile.am2
-rw-r--r--src/or/Makefile.nmake28
-rw-r--r--src/or/buffers.c46
-rw-r--r--src/or/circuitlist.c10
-rw-r--r--src/or/config.c56
-rw-r--r--src/or/connection.c162
-rw-r--r--src/or/connection_edge.c125
-rw-r--r--src/or/connection_edge.h3
-rw-r--r--src/or/connection_or.c4
-rw-r--r--src/or/control.c43
-rw-r--r--src/or/control.h1
-rw-r--r--src/or/directory.c17
-rw-r--r--src/or/dnsserv.c2
-rw-r--r--src/or/geoip.c308
-rw-r--r--src/or/geoip.h5
-rw-r--r--src/or/main.c16
-rw-r--r--src/or/microdesc.c15
-rw-r--r--src/or/networkstatus.c11
-rw-r--r--src/or/or.h11
-rw-r--r--src/or/rephist.c240
-rw-r--r--src/or/rephist.h4
-rw-r--r--src/or/status.c2
22 files changed, 699 insertions, 412 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index 344e63ff87..e2a1b6d649 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -7,7 +7,7 @@ else
tor_platform_source=
endif
-EXTRA_DIST=ntmain.c or_sha1.i
+EXTRA_DIST=ntmain.c or_sha1.i Makefile.nmake
if USE_EXTERNAL_EVDNS
evdns_source=
diff --git a/src/or/Makefile.nmake b/src/or/Makefile.nmake
new file mode 100644
index 0000000000..919edbbf22
--- /dev/null
+++ b/src/or/Makefile.nmake
@@ -0,0 +1,28 @@
+all: tor.exe
+
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common
+
+LIBS = ..\..\..\build-alpha\lib\libevent.a \
+ ..\..\..\build-alpha\lib\libcrypto.a \
+ ..\..\..\build-alpha\lib\libssl.a \
+ ..\..\..\build-alpha\lib\libz.a \
+ ws2_32.lib advapi32.lib shell32.lib
+
+LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
+ command.obj config.obj connection.obj connection_edge.obj \
+ connection_or.obj control.obj cpuworker.obj directory.obj \
+ dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj \
+ hibernate.obj main.obj microdesc.obj networkstatus.obj \
+ nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
+ rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
+ rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
+ config_codedigest.obj ntmain.obj
+
+libtor.lib: $(LIBTOR_OBJECTS)
+ lib $(LIBTOR_OBJECTS) /out:libtor.lib
+
+tor.exe: libtor.lib tor_main.obj
+ $(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj
+
+clean:
+ del $(LIBTOR_OBJECTS) *.lib tor.exe
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 5b9e55ebd5..85d58e8986 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1054,14 +1054,14 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
#ifdef USE_BUFFEREVENTS
/** Try to read <b>n</b> bytes from <b>buf</b> at <b>pos</b> (which may be
* NULL for the start of the buffer), copying the data only if necessary. Set
- * *<b>data</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
- * if we needed to malloc *<b>data</b> because the original bytes were
+ * *<b>data_out</b> to a pointer to the desired bytes. Set <b>free_out</b>
+ * to 1 if we needed to malloc *<b>data</b> because the original bytes were
* noncontiguous; 0 otherwise. Return the number of bytes actually available
- * at <b>data</b>.
+ * at *<b>data_out</b>.
*/
static ssize_t
-inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
- struct evbuffer_ptr *pos)
+inspect_evbuffer(struct evbuffer *buf, char **data_out, size_t n,
+ int *free_out, struct evbuffer_ptr *pos)
{
int n_vecs, i;
@@ -1075,25 +1075,15 @@ inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
struct evbuffer_iovec v;
i = evbuffer_peek(buf, n, pos, &v, 1);
tor_assert(i == 1);
- *data = v.iov_base;
+ *data_out = v.iov_base;
*free_out = 0;
return v.iov_len;
} else {
- struct evbuffer_iovec *vecs =
- tor_malloc(sizeof(struct evbuffer_iovec)*n_vecs);
- size_t copied = 0;
- i = evbuffer_peek(buf, n, NULL, vecs, n_vecs);
- tor_assert(i == n_vecs);
- *data = tor_malloc(n);
- for (i=0; i < n_vecs; ++i) {
- size_t copy = n - copied;
- if (copy > vecs[i].iov_len)
- copy = vecs[i].iov_len;
- tor_assert(copied+copy <= n);
- memcpy(data+copied, vecs[i].iov_base, copy);
- copied += copy;
- }
+ ev_ssize_t copied;
+ *data_out = tor_malloc(n);
*free_out = 1;
+ copied = evbuffer_copyout(buf, *data_out, n);
+ tor_assert(copied >= 0 && (size_t)copied == n);
return copied;
}
}
@@ -1532,8 +1522,14 @@ socks_request_free(socks_request_t *req)
{
if (!req)
return;
- tor_free(req->username);
- tor_free(req->password);
+ if (req->username) {
+ memset(req->username, 0x10, req->usernamelen);
+ tor_free(req->username);
+ }
+ if (req->password) {
+ memset(req->password, 0x04, req->passwordlen);
+ tor_free(req->password);
+ }
memset(req, 0xCC, sizeof(socks_request_t));
tor_free(req);
}
@@ -1661,9 +1657,9 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
if (res == 0 && n_drain == 0 && want_length <= last_wanted) {
/* If we drained nothing, and we didn't ask for more than last time,
- * we're stuck in a loop. That's bad. It shouldn't be possible, but
- * let's make sure. */
- log_warn(LD_BUG, "We seem to be caught in a parse loop; breaking out");
+ * then we probably wanted more data than the buffer actually had,
+ * and we're finding out that we're not satisified with it. It's
+ * time to break until we have more data. */
break;
}
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 48c5afc7d0..2222a25af0 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -552,8 +552,14 @@ circuit_free(circuit_t *circ)
rend_data_free(ocirc->rend_data);
tor_free(ocirc->dest_address);
- tor_free(ocirc->socks_username);
- tor_free(ocirc->socks_password);
+ if (ocirc->socks_username) {
+ memset(ocirc->socks_username, 0x12, ocirc->socks_username_len);
+ tor_free(ocirc->socks_username);
+ }
+ if (ocirc->socks_password) {
+ memset(ocirc->socks_password, 0x06, ocirc->socks_password_len);
+ tor_free(ocirc->socks_password);
+ }
} else {
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
/* Remember cell statistics for this circuit before deallocating. */
diff --git a/src/or/config.c b/src/or/config.c
index 088617bb49..dbc355d728 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -40,6 +40,9 @@
#include "procmon.h"
+/* From main.c */
+extern int quiet_level;
+
/** Enumeration of types which option values can take */
typedef enum config_type_t {
CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
@@ -693,6 +696,9 @@ get_options(void)
int
set_options(or_options_t *new_val, char **msg)
{
+ int i;
+ smartlist_t *elements;
+ config_line_t *line;
or_options_t *old_options = global_options;
global_options = new_val;
/* Note that we pass the *old* options below, for comparison. It
@@ -707,7 +713,34 @@ set_options(or_options_t *new_val, char **msg)
"Acting on config options left us in a broken state. Dying.");
exit(1);
}
-
+ /* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
+ * just starting up then the old_options will be undefined. */
+ if (old_options) {
+ elements = smartlist_create();
+ for (i=0; options_format.vars[i].name; ++i) {
+ const config_var_t *var = &options_format.vars[i];
+ const char *var_name = var->name;
+ if (var->type == CONFIG_TYPE_LINELIST_S ||
+ var->type == CONFIG_TYPE_OBSOLETE) {
+ continue;
+ }
+ if (!option_is_same(&options_format, new_val, old_options, var_name)) {
+ line = get_assigned_option(&options_format, new_val, var_name, 1);
+
+ if (line) {
+ for (; line; line = line->next) {
+ smartlist_add(elements, line->key);
+ smartlist_add(elements, line->value);
+ }
+ } else {
+ smartlist_add(elements, (char*)options_format.vars[i].name);
+ smartlist_add(elements, NULL);
+ }
+ }
+ }
+ control_event_conf_changed(elements);
+ smartlist_free(elements);
+ }
config_free(&options_format, old_options);
return 0;
@@ -1087,6 +1120,9 @@ options_act_reversible(const or_options_t *old_options, char **msg)
/* No need to roll back, since you can't change the value. */
}
+ /* Write control ports to disk as appropriate */
+ control_ports_write_to_file();
+
if (directory_caches_v2_dir_info(options)) {
size_t len = strlen(options->DataDirectory)+32;
char *fn = tor_malloc(len);
@@ -3095,8 +3131,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
"misconfigured or something else goes wrong.");
/* Special case on first boot if no Log options are given. */
- if (!options->Logs && !options->RunAsDaemon && !from_setconf)
- config_line_append(&options->Logs, "Log", "notice stdout");
+ if (!options->Logs && !options->RunAsDaemon && !from_setconf) {
+ if (quiet_level == 0)
+ config_line_append(&options->Logs, "Log", "notice stdout");
+ else if (quiet_level == 1)
+ config_line_append(&options->Logs, "Log", "warn stdout");
+ }
if (options_init_logs(options, 1)<0) /* Validate the log(s) */
REJECT("Failed to validate Log options. See logs for details.");
@@ -3926,6 +3966,12 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
+ if (old->DisableIOCP != new_val->DisableIOCP) {
+ *msg = tor_strdup("While Tor is running, changing DisableIOCP "
+ "is not allowed.");
+ return -1;
+ }
+
return 0;
}
@@ -4947,7 +4993,7 @@ parse_client_port_config(smartlist_t *out,
mainport = (int)tor_parse_long(ports->value, 10, 0, 65535, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG, "%sListenAddress can only be used with a single "
- "%sPort with value \"auto\" or 1-65535.", portname, portname);
+ "%sPort with value \"auto\" or 1-65535.", portname, portname);
return -1;
}
}
@@ -5111,7 +5157,7 @@ parse_client_port_config(smartlist_t *out,
}
} SMARTLIST_FOREACH_END(elt);
- if (out) {
+ if (out && port) {
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
cfg->type = listener_type;
cfg->port = port;
diff --git a/src/or/connection.c b/src/or/connection.c
index 012a3fbd03..97989c07f5 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -544,6 +544,7 @@ _connection_free(connection_t *conn)
#ifdef USE_BUFFEREVENTS
if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) {
ev_token_bucket_cfg_free(TO_OR_CONN(conn)->bucket_cfg);
+ TO_OR_CONN(conn)->bucket_cfg = NULL;
}
#endif
@@ -581,41 +582,6 @@ connection_free(connection_t *conn)
_connection_free(conn);
}
-/** Call _connection_free() on every connection in our array, and release all
- * storage held by connection.c. This is used by cpuworkers and dnsworkers
- * when they fork, so they don't keep resources held open (especially
- * sockets).
- *
- * Don't do the checks in connection_free(), because they will
- * fail.
- */
-void
-connection_free_all(void)
-{
- smartlist_t *conns = get_connection_array();
-
- /* We don't want to log any messages to controllers. */
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- if (conn->type == CONN_TYPE_CONTROL)
- TO_CONTROL_CONN(conn)->event_mask = 0);
-
- control_update_global_event_mask();
-
- /* Unlink everything from the identity map. */
- connection_or_clear_identity_map();
-
- /* Clear out our list of broken connections */
- clear_broken_connection_map(0);
-
- SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
-
- if (outgoing_addrs) {
- SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
- smartlist_free(outgoing_addrs);
- outgoing_addrs = NULL;
- }
-}
-
/**
* Called when we're about to finally unlink and free a connection:
* perform necessary accounting and cleanup
@@ -1042,9 +1008,6 @@ connection_create_listener(const struct sockaddr *listensockaddr,
"%s listening on port %u.",
conn_type_to_string(type), gotPort);
- if (type == CONN_TYPE_CONTROL_LISTENER)
- control_ports_write_to_file();
-
conn->state = LISTENER_STATE_READY;
if (start_reading) {
connection_start_reading(conn);
@@ -1271,6 +1234,7 @@ connection_init_accepted_conn(connection_t *conn,
TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags;
TO_ENTRY_CONN(conn)->session_group = listener->session_group;
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
+ TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->_base.type;
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
@@ -1841,6 +1805,8 @@ retry_listener_ports(smartlist_t *old_conns,
socklen_t listensocklen = 0;
char *address=NULL;
connection_t *conn;
+ int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port;
+ tor_assert(real_port <= UINT16_MAX);
if (port->is_unix_addr) {
listensockaddr = (struct sockaddr *)
@@ -1849,7 +1815,7 @@ retry_listener_ports(smartlist_t *old_conns,
} else {
listensockaddr = tor_malloc(sizeof(struct sockaddr_storage));
listensocklen = tor_addr_to_sockaddr(&port->addr,
- port->port,
+ real_port,
listensockaddr,
sizeof(struct sockaddr_storage));
address = tor_dup_addr(&port->addr);
@@ -2248,24 +2214,11 @@ global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
return 0;
}
-#ifndef USE_BUFFEREVENTS
-/** We just read <b>num_read</b> and wrote <b>num_written</b> bytes
- * onto <b>conn</b>. Decrement buckets appropriately. */
+/** DOCDOC */
static void
-connection_buckets_decrement(connection_t *conn, time_t now,
- size_t num_read, size_t num_written)
+record_num_bytes_transferred_impl(connection_t *conn,
+ time_t now, size_t num_read, size_t num_written)
{
- if (num_written >= INT_MAX || num_read >= INT_MAX) {
- log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, "
- "connection type=%s, state=%s",
- (unsigned long)num_read, (unsigned long)num_written,
- conn_type_to_string(conn->type),
- conn_state_to_string(conn->type, conn->state));
- if (num_written >= INT_MAX) num_written = 1;
- if (num_read >= INT_MAX) num_read = 1;
- tor_fragile_assert();
- }
-
/* Count bytes of answering direct and tunneled directory requests */
if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) {
if (num_read > 0)
@@ -2289,6 +2242,52 @@ connection_buckets_decrement(connection_t *conn, time_t now,
}
if (conn->type == CONN_TYPE_EXIT)
rep_hist_note_exit_bytes(conn->port, num_written, num_read);
+}
+
+#ifdef USE_BUFFEREVENTS
+/** DOCDOC */
+static void
+record_num_bytes_transferred(connection_t *conn,
+ time_t now, size_t num_read, size_t num_written)
+{
+ /* XXX023 check if this is necessary */
+ if (num_written >= INT_MAX || num_read >= INT_MAX) {
+ log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, "
+ "connection type=%s, state=%s",
+ (unsigned long)num_read, (unsigned long)num_written,
+ conn_type_to_string(conn->type),
+ conn_state_to_string(conn->type, conn->state));
+ if (num_written >= INT_MAX) num_written = 1;
+ if (num_read >= INT_MAX) num_read = 1;
+ tor_fragile_assert();
+ }
+
+ record_num_bytes_transferred_impl(conn,now,num_read,num_written);
+}
+#endif
+
+#ifndef USE_BUFFEREVENTS
+/** We just read <b>num_read</b> and wrote <b>num_written</b> bytes
+ * onto <b>conn</b>. Decrement buckets appropriately. */
+static void
+connection_buckets_decrement(connection_t *conn, time_t now,
+ size_t num_read, size_t num_written)
+{
+ if (num_written >= INT_MAX || num_read >= INT_MAX) {
+ log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, "
+ "connection type=%s, state=%s",
+ (unsigned long)num_read, (unsigned long)num_written,
+ conn_type_to_string(conn->type),
+ conn_state_to_string(conn->type, conn->state));
+ if (num_written >= INT_MAX) num_written = 1;
+ if (num_read >= INT_MAX) num_read = 1;
+ tor_fragile_assert();
+ }
+
+ record_num_bytes_transferred_impl(conn, now, num_read, num_written);
+
+ if (!connection_is_rate_limited(conn))
+ return; /* local IPs are free */
if (connection_counts_as_relayed_traffic(conn, now)) {
global_relayed_read_bucket -= (int)num_read;
@@ -2498,7 +2497,6 @@ connection_bucket_should_increase(int bucket, or_connection_t *conn)
return 1;
}
#else
-
static void
connection_buckets_decrement(connection_t *conn, time_t now,
size_t num_read, size_t num_written)
@@ -2509,6 +2507,7 @@ connection_buckets_decrement(connection_t *conn, time_t now,
(void) num_written;
/* Libevent does this for us. */
}
+
void
connection_bucket_refill(int seconds_elapsed, time_t now)
{
@@ -2564,7 +2563,7 @@ connection_enable_rate_limiting(connection_t *conn)
if (conn->bufev) {
if (!global_rate_limit)
connection_bucket_init();
- bufferevent_add_to_rate_limit_group(conn->bufev, global_rate_limit);
+ tor_add_bufferevent_to_rate_limit_group(conn->bufev, global_rate_limit);
}
}
@@ -2883,7 +2882,7 @@ evbuffer_inbuf_callback(struct evbuffer *buf,
if (info->n_added) {
time_t now = approx_time();
conn->timestamp_lastread = now;
- connection_buckets_decrement(conn, now, info->n_added, 0);
+ record_num_bytes_transferred(conn, now, info->n_added, 0);
connection_consider_empty_read_buckets(conn);
if (conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
@@ -2904,7 +2903,7 @@ evbuffer_outbuf_callback(struct evbuffer *buf,
if (info->n_deleted) {
time_t now = approx_time();
conn->timestamp_lastwritten = now;
- connection_buckets_decrement(conn, now, 0, info->n_deleted);
+ record_num_bytes_transferred(conn, now, 0, info->n_deleted);
connection_consider_empty_write_buckets(conn);
if (conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
@@ -3006,6 +3005,11 @@ connection_configure_bufferevent_callbacks(connection_t *conn)
connection_handle_write_cb,
connection_handle_event_cb,
conn);
+ /* Set a fairly high write low-watermark so that we get the write callback
+ called whenever data is written to bring us under 128K. Leave the
+ high-watermark at 0.
+ */
+ bufferevent_setwatermark(bufev, EV_WRITE, 128*1024, 0);
input = bufferevent_get_input(bufev);
output = bufferevent_get_output(bufev);
@@ -4184,3 +4188,43 @@ proxy_type_to_string(int proxy_type)
return NULL; /*Unreached*/
}
+/** Call _connection_free() on every connection in our array, and release all
+ * storage held by connection.c. This is used by cpuworkers and dnsworkers
+ * when they fork, so they don't keep resources held open (especially
+ * sockets).
+ *
+ * Don't do the checks in connection_free(), because they will
+ * fail.
+ */
+void
+connection_free_all(void)
+{
+ smartlist_t *conns = get_connection_array();
+
+ /* We don't want to log any messages to controllers. */
+ SMARTLIST_FOREACH(conns, connection_t *, conn,
+ if (conn->type == CONN_TYPE_CONTROL)
+ TO_CONTROL_CONN(conn)->event_mask = 0);
+
+ control_update_global_event_mask();
+
+ /* Unlink everything from the identity map. */
+ connection_or_clear_identity_map();
+
+ /* Clear out our list of broken connections */
+ clear_broken_connection_map(0);
+
+ SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
+
+ if (outgoing_addrs) {
+ SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
+ smartlist_free(outgoing_addrs);
+ outgoing_addrs = NULL;
+ }
+
+#ifdef USE_BUFFEREVENTS
+ if (global_rate_limit)
+ bufferevent_rate_limit_group_free(global_rate_limit);
+#endif
+}
+
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index df4acc46e5..0d2c10f5dd 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -165,7 +165,8 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
"data from edge while in '%s' state. Sending it anyway. "
"package_partial=%d, buflen=%ld",
conn_state_to_string(conn->_base.type, conn->_base.state),
- package_partial, connection_get_inbuf_len(TO_CONN(conn)));
+ package_partial,
+ (long)connection_get_inbuf_len(TO_CONN(conn)));
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
/* (We already sent an end cell if possible) */
connection_mark_for_close(TO_CONN(conn));
@@ -938,12 +939,10 @@ addressmap_clear_excluded_trackexithosts(const or_options_t *options)
if (len < 6)
continue; /* malformed. */
dot = target + len - 6; /* dot now points to just before .exit */
- dot = strrchr(dot, '.'); /* dot now points to the . before .exit or NULL */
- if (!dot) {
- nodename = tor_strndup(target, len-5);
- } else {
- nodename = tor_strndup(dot+1, strlen(dot+1)-5);
- }
+ while(dot > target && *dot != '.')
+ dot--;
+ if (*dot == '.') dot++;
+ nodename = tor_strndup(dot, len-5-(dot-target));;
node = node_get_by_nickname(nodename, 0);
tor_free(nodename);
if (!node ||
@@ -2455,9 +2454,9 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
ap_conn->sending_optimistic_data) &&
connection_ap_supports_optimistic_data(ap_conn)) {
log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data",
- connection_get_inbuf_len(base_conn),
+ (long)connection_get_inbuf_len(base_conn),
ap_conn->sending_optimistic_data ?
- generic_buffer_len(ap_conn->sending_optimistic_data) : 0);
+ (long)generic_buffer_len(ap_conn->sending_optimistic_data) : 0);
if (connection_edge_package_raw_inbuf(edge_conn, 1, NULL) < 0) {
connection_mark_for_close(base_conn);
}
@@ -2599,6 +2598,7 @@ connection_ap_make_link(connection_t *partner,
}
/* Populate isolation fields. */
+ conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
conn->original_dest_address = tor_strdup(address);
conn->session_group = session_group;
conn->isolation_flags = isolation_flags;
@@ -3344,52 +3344,21 @@ parse_extended_hostname(char *address, int allowdotexit)
return BAD_HOSTNAME;
}
-/** Return true iff <b>a</b> and <b>b</b> have isolation rules and fields that
- * make it permissible to put them on the same circuit.*/
-int
-connection_edge_streams_are_compatible(const entry_connection_t *a,
- const entry_connection_t *b)
+/** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at
+ * <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory
+ * at <b>b</b>. */
+static int
+memeq_opt(const char *a, size_t alen, const char *b, size_t blen)
{
- const uint8_t iso = a->isolation_flags | b->isolation_flags;
-
- if (! a->original_dest_address) {
- log_warn(LD_BUG, "Reached connection_edge_streams_are_compatible without "
- "having set a->original_dest_address");
- ((entry_connection_t*)a)->original_dest_address =
- tor_strdup(a->socks_request->address);
- }
- if (! b->original_dest_address) {
- log_warn(LD_BUG, "Reached connection_edge_streams_are_compatible without "
- "having set b->original_dest_address");
- ((entry_connection_t*)b)->original_dest_address =
- tor_strdup(a->socks_request->address);
- }
-
- if (iso & ISO_STREAM)
- return 0;
-
- if ((iso & ISO_DESTPORT) && a->socks_request->port != b->socks_request->port)
+ if (a == NULL) {
+ return (b == NULL);
+ } else if (b == NULL) {
return 0;
- if ((iso & ISO_DESTADDR) &&
- strcasecmp(a->original_dest_address, b->original_dest_address))
- return 0;
- if ((iso & ISO_SOCKSAUTH) &&
- (strcmp_opt(a->socks_request->username, b->socks_request->username) ||
- strcmp_opt(a->socks_request->password, b->socks_request->password)))
+ } else if (alen != blen) {
return 0;
- if ((iso & ISO_CLIENTPROTO) &&
- (ENTRY_TO_CONN(a)->type != ENTRY_TO_CONN(b)->type ||
- a->socks_request->socks_version != b->socks_request->socks_version))
- return 0;
- if ((iso & ISO_CLIENTADDR) &&
- !tor_addr_eq(&ENTRY_TO_CONN(a)->addr, &ENTRY_TO_CONN(b)->addr))
- return 0;
- if ((iso & ISO_SESSIONGRP) && a->session_group != b->session_group)
- return 0;
- if ((iso & ISO_NYM_EPOCH) && a->nym_epoch != b->nym_epoch)
- return 0;
-
- return 1;
+ } else {
+ return tor_memeq(a, b, alen);
+ }
}
/**
@@ -3401,6 +3370,7 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn,
const origin_circuit_t *circ)
{
const uint8_t iso = conn->isolation_flags;
+ const socks_request_t *sr = conn->socks_request;
/* If circ has never been used for an isolated connection, we can
* totally use it for this one. */
@@ -3425,9 +3395,9 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn,
tor_strdup(conn->socks_request->address);
}
- /* If isolation_values_set, then the circuit is not compatible with
- * any new ISO_STREAM stream. */
- if (iso & ISO_STREAM)
+ if ((iso & ISO_STREAM) &&
+ (circ->associated_isolated_stream_global_id !=
+ ENTRY_TO_CONN(conn)->global_identifier))
return 0;
if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port)
@@ -3436,11 +3406,13 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn,
strcasecmp(conn->original_dest_address, circ->dest_address))
return 0;
if ((iso & ISO_SOCKSAUTH) &&
- (strcmp_opt(conn->socks_request->username, circ->socks_username) ||
- strcmp_opt(conn->socks_request->password, circ->socks_password)))
+ (! memeq_opt(sr->username, sr->usernamelen,
+ circ->socks_username, circ->socks_username_len) ||
+ ! memeq_opt(sr->password, sr->passwordlen,
+ circ->socks_password, circ->socks_password_len)))
return 0;
if ((iso & ISO_CLIENTPROTO) &&
- (ENTRY_TO_CONN(conn)->type != circ->client_proto_type ||
+ (conn->socks_request->listener_type != circ->client_proto_type ||
conn->socks_request->socks_version != circ->client_proto_socksver))
return 0;
if ((iso & ISO_CLIENTADDR) &&
@@ -3467,6 +3439,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
origin_circuit_t *circ,
int dry_run)
{
+ const socks_request_t *sr = conn->socks_request;
if (! conn->original_dest_address) {
log_warn(LD_BUG, "Reached connection_update_circuit_isolation without "
"having set conn->original_dest_address");
@@ -3477,17 +3450,21 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
if (!circ->isolation_values_set) {
if (dry_run)
return -1;
+ circ->associated_isolated_stream_global_id =
+ ENTRY_TO_CONN(conn)->global_identifier;
circ->dest_port = conn->socks_request->port;
circ->dest_address = tor_strdup(conn->original_dest_address);
- circ->client_proto_type = ENTRY_TO_CONN(conn)->type;
+ circ->client_proto_type = conn->socks_request->listener_type;
circ->client_proto_socksver = conn->socks_request->socks_version;
tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr);
circ->session_group = conn->session_group;
circ->nym_epoch = conn->nym_epoch;
- circ->socks_username = conn->socks_request->username ?
- tor_strdup(conn->socks_request->username) : NULL;
- circ->socks_password = conn->socks_request->password ?
- tor_strdup(conn->socks_request->password) : NULL;
+ circ->socks_username = sr->username ?
+ tor_memdup(sr->username, sr->usernamelen) : NULL;
+ circ->socks_password = sr->password ?
+ tor_memdup(sr->password, sr->passwordlen) : NULL;
+ circ->socks_username_len = sr->usernamelen;
+ circ->socks_password_len = sr->passwordlen;
circ->isolation_values_set = 1;
return 0;
@@ -3497,10 +3474,12 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
mixed |= ISO_DESTPORT;
if (strcasecmp(conn->original_dest_address, circ->dest_address))
mixed |= ISO_DESTADDR;
- if (strcmp_opt(conn->socks_request->username, circ->socks_username) ||
- strcmp_opt(conn->socks_request->password, circ->socks_password))
+ if (!memeq_opt(sr->username, sr->usernamelen,
+ circ->socks_username, circ->socks_username_len) ||
+ !memeq_opt(sr->password, sr->passwordlen,
+ circ->socks_password, circ->socks_password_len))
mixed |= ISO_SOCKSAUTH;
- if ((ENTRY_TO_CONN(conn)->type != circ->client_proto_type ||
+ if ((conn->socks_request->listener_type != circ->client_proto_type ||
conn->socks_request->socks_version != circ->client_proto_socksver))
mixed |= ISO_CLIENTPROTO;
if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
@@ -3514,7 +3493,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
return mixed;
if ((mixed & conn->isolation_flags) != 0) {
- log_warn(LD_BUG, "Updating a circuit with seemingly incomaptible "
+ log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
"isolation flags.");
}
circ->isolation_flags_mixed |= mixed;
@@ -3548,6 +3527,7 @@ circuit_clear_isolation(origin_circuit_t *circ)
circ->isolation_values_set = 0;
circ->isolation_flags_mixed = 0;
+ circ->associated_isolated_stream_global_id = 0;
circ->client_proto_type = 0;
circ->client_proto_socksver = 0;
circ->dest_port = 0;
@@ -3555,7 +3535,14 @@ circuit_clear_isolation(origin_circuit_t *circ)
tor_free(circ->dest_address);
circ->session_group = -1;
circ->nym_epoch = 0;
- tor_free(circ->socks_username);
- tor_free(circ->socks_password);
+ if (circ->socks_username) {
+ memset(circ->socks_username, 0x11, circ->socks_username_len);
+ tor_free(circ->socks_username);
+ }
+ if (circ->socks_password) {
+ memset(circ->socks_password, 0x05, circ->socks_password_len);
+ tor_free(circ->socks_password);
+ }
+ circ->socks_username_len = circ->socks_password_len = 0;
}
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index cf60cf4698..75a54e85e1 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -105,8 +105,7 @@ hostname_type_t parse_extended_hostname(char *address, int allowdotexit);
int get_pf_socket(void);
#endif
-int connection_edge_streams_are_compatible(const entry_connection_t *a,
- const entry_connection_t *b);
+
int connection_edge_compatible_with_circuit(const entry_connection_t *conn,
const origin_circuit_t *circ);
int connection_edge_update_circuit_isolation(const entry_connection_t *conn,
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index e66d36a2f3..a75444e1ed 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -585,7 +585,7 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
burst, tick);
old_cfg = conn->bucket_cfg;
if (conn->_base.bufev)
- bufferevent_set_rate_limit(conn->_base.bufev, cfg);
+ tor_set_bufferevent_rate_limit(conn->_base.bufev, cfg);
if (old_cfg)
ev_token_bucket_cfg_free(old_cfg);
conn->bucket_cfg = cfg;
@@ -1102,7 +1102,7 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving)
}
conn->_base.bufev = b;
if (conn->bucket_cfg)
- bufferevent_set_rate_limit(conn->_base.bufev, conn->bucket_cfg);
+ tor_set_bufferevent_rate_limit(conn->_base.bufev, conn->bucket_cfg);
connection_enable_rate_limiting(TO_CONN(conn));
connection_configure_bufferevent_callbacks(TO_CONN(conn));
diff --git a/src/or/control.c b/src/or/control.c
index 6a44730f2f..f852659983 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -74,7 +74,8 @@
#define EVENT_NEWCONSENSUS 0x0016
#define EVENT_BUILDTIMEOUT_SET 0x0017
#define EVENT_SIGNAL 0x0018
-#define _EVENT_MAX 0x0018
+#define EVENT_CONF_CHANGED 0x0019
+#define _EVENT_MAX 0x0019
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1&lt;&lt;e is set if <b>any</b> open control
@@ -502,8 +503,8 @@ connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
va_end(ap);
if (len < 0) {
- log_warn(LD_BUG, "Unable to format string for controller.");
- return;
+ log_err(LD_BUG, "Unable to format string for controller.");
+ tor_assert(0);
}
connection_write_to_buf(buf, (size_t)len, TO_CONN(conn));
@@ -946,6 +947,7 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_NEWCONSENSUS, "NEWCONSENSUS" },
{ EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" },
{ EVENT_SIGNAL, "SIGNAL" },
+ { EVENT_CONF_CHANGED, "CONF_CHANGED"},
{ 0, NULL },
};
@@ -3569,7 +3571,7 @@ control_event_logmsg(int severity, uint32_t domain, const char *msg)
severity <= LOG_NOTICE) {
char *esc = esc_for_log(msg);
++disable_log_messages;
- control_event_general_status(severity, "BUG REASON=\"%s\"", esc);
+ control_event_general_status(severity, "BUG REASON=%s", esc);
--disable_log_messages;
tor_free(esc);
}
@@ -3998,6 +4000,39 @@ control_event_guard(const char *nickname, const char *digest,
return 0;
}
+/** Called when a configuration option changes. This is generally triggered
+ * by SETCONF requests and RELOAD/SIGHUP signals. The <b>elements</b> is
+ * a smartlist_t containing (key, value, ...) pairs in sequence.
+ * <b>value</b> can be NULL. */
+int
+control_event_conf_changed(smartlist_t *elements)
+{
+ int i;
+ char *result;
+ smartlist_t *lines;
+ if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) ||
+ smartlist_len(elements) == 0) {
+ return 0;
+ }
+ lines = smartlist_create();
+ for (i = 0; i < smartlist_len(elements); i += 2) {
+ char *k = smartlist_get(elements, i);
+ char *v = smartlist_get(elements, i+1);
+ if (v == NULL) {
+ smartlist_asprintf_add(lines, "650-%s", k);
+ } else {
+ smartlist_asprintf_add(lines, "650-%s=%s", k, v);
+ }
+ }
+ result = smartlist_join_strings(lines, "\r\n", 0, NULL);
+ send_control_event(EVENT_CONF_CHANGED, 0,
+ "650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result);
+ tor_free(result);
+ SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
+ smartlist_free(lines);
+ return 0;
+}
+
/** Helper: Return a newly allocated string containing a path to the
* file where we store our authentication cookie. */
static char *
diff --git a/src/or/control.h b/src/or/control.h
index 3655184690..0d9acd26ef 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -66,6 +66,7 @@ int control_event_server_status(int severity, const char *format, ...)
CHECK_PRINTF(2,3);
int control_event_guard(const char *nickname, const char *digest,
const char *status);
+int control_event_conf_changed(smartlist_t *elements);
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
buildtimeout_set_event_t type);
int control_event_signal(uintptr_t signal);
diff --git a/src/or/directory.c b/src/or/directory.c
index 16bea8256b..cd0b9b4de7 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -3546,8 +3546,21 @@ connection_dir_finished_flushing(dir_connection_t *conn)
conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
return 0;
case DIR_CONN_STATE_SERVER_WRITING:
- log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
- connection_mark_for_close(TO_CONN(conn));
+ if (conn->dir_spool_src != DIR_SPOOL_NONE) {
+#ifdef USE_BUFFEREVENTS
+ /* This can happen with paired bufferevents, since a paired connection
+ * can flush immediately when you write to it, making the subsequent
+ * check in connection_handle_write_cb() decide that the connection
+ * is flushed. */
+ log_debug(LD_DIRSERV, "Emptied a dirserv buffer, but still spooling.");
+#else
+ log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!");
+ connection_mark_for_close(TO_CONN(conn));
+#endif
+ } else {
+ log_debug(LD_DIRSERV, "Finished writing server response. Closing.");
+ connection_mark_for_close(TO_CONN(conn));
+ }
return 0;
default:
log_warn(LD_BUG,"called in unexpected state %d.",
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index a54530c2b1..7f519398fa 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -133,6 +133,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
strlcpy(entry_conn->socks_request->address, q->name,
sizeof(entry_conn->socks_request->address));
+ entry_conn->socks_request->listener_type = listener->_base.type;
entry_conn->dns_server_request = req;
entry_conn->isolation_flags = listener->isolation_flags;
entry_conn->session_group = listener->session_group;
@@ -189,6 +190,7 @@ dnsserv_launch_request(const char *name, int reverse)
strlcpy(entry_conn->socks_request->address, name,
sizeof(entry_conn->socks_request->address));
+ entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER;
entry_conn->original_dest_address = tor_strdup(name);
entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE;
entry_conn->nym_epoch = get_signewnym_epoch();
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 5596ff3253..67dea965f3 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -930,10 +930,9 @@ geoip_dirreq_stats_init(time_t now)
start_of_dirreq_stats_interval = now;
}
-/** Stop collecting directory request stats in a way that we can re-start
- * doing so in geoip_dirreq_stats_init(). */
+/** Reset counters for dirreq stats. */
void
-geoip_dirreq_stats_term(void)
+geoip_reset_dirreq_stats(time_t now)
{
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
@@ -965,59 +964,41 @@ geoip_dirreq_stats_term(void)
tor_free(this);
}
}
- start_of_dirreq_stats_interval = 0;
+ start_of_dirreq_stats_interval = now;
}
-/** Write dirreq statistics to $DATADIR/stats/dirreq-stats and return when
- * we would next want to write. */
-time_t
-geoip_dirreq_stats_write(time_t now)
+/** Stop collecting directory request stats in a way that we can re-start
+ * doing so in geoip_dirreq_stats_init(). */
+void
+geoip_dirreq_stats_term(void)
{
- char *statsdir = NULL, *filename = NULL;
- char *data_v2 = NULL, *data_v3 = NULL;
- char written[ISO_TIME_LEN+1];
- open_file_t *open_file = NULL;
+ geoip_reset_dirreq_stats(0);
+}
+
+/** Return a newly allocated string containing the dirreq statistics
+ * until <b>now</b>, or NULL if we're not collecting dirreq stats. */
+char *
+geoip_format_dirreq_stats(time_t now)
+{
+ char t[ISO_TIME_LEN+1];
double v2_share = 0.0, v3_share = 0.0;
- FILE *out;
int i;
+ char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string,
+ *v2_share_string = NULL, *v3_share_string = NULL,
+ *v3_direct_dl_string, *v2_direct_dl_string,
+ *v3_tunneled_dl_string, *v2_tunneled_dl_string;
+ char *result;
if (!start_of_dirreq_stats_interval)
- return 0; /* Not initialized. */
- if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now)
- goto done; /* Not ready to write. */
+ return NULL; /* Not initialized. */
- /* Discard all items in the client history that are too old. */
- geoip_remove_old_clients(start_of_dirreq_stats_interval);
-
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
- goto done;
- filename = get_datadir_fname2("stats", "dirreq-stats");
- data_v2 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
- data_v3 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
- format_iso_time(written, now);
- out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
- 0600, &open_file);
- if (!out)
- goto done;
- if (fprintf(out, "dirreq-stats-end %s (%d s)\ndirreq-v3-ips %s\n"
- "dirreq-v2-ips %s\n", written,
- (unsigned) (now - start_of_dirreq_stats_interval),
- data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
- goto done;
- tor_free(data_v2);
- tor_free(data_v3);
+ format_iso_time(t, now);
+ v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
+ v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
+ v2_reqs_string = geoip_get_request_history(
+ GEOIP_CLIENT_NETWORKSTATUS_V2);
+ v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
- data_v2 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
- data_v3 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
- if (fprintf(out, "dirreq-v3-reqs %s\ndirreq-v2-reqs %s\n",
- data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
- goto done;
- tor_free(data_v2);
- tor_free(data_v3);
- SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
- c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
- });
#define RESPONSE_GRANULARITY 8
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
ns_v2_responses[i] = round_uint32_to_next_multiple_of(
@@ -1026,61 +1007,117 @@ geoip_dirreq_stats_write(time_t now)
ns_v3_responses[i], RESPONSE_GRANULARITY);
}
#undef RESPONSE_GRANULARITY
- if (fprintf(out, "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
- "not-found=%u,not-modified=%u,busy=%u\n",
- ns_v3_responses[GEOIP_SUCCESS],
- ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
- ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
- ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
- ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
- ns_v3_responses[GEOIP_REJECT_BUSY]) < 0)
- goto done;
- if (fprintf(out, "dirreq-v2-resp ok=%u,unavailable=%u,"
- "not-found=%u,not-modified=%u,busy=%u\n",
- ns_v2_responses[GEOIP_SUCCESS],
- ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
- ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
- ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
- ns_v2_responses[GEOIP_REJECT_BUSY]) < 0)
- goto done;
- memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
- memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
+
if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
- if (fprintf(out, "dirreq-v2-share %0.2lf%%\n", v2_share*100) < 0)
- goto done;
- if (fprintf(out, "dirreq-v3-share %0.2lf%%\n", v3_share*100) < 0)
- goto done;
+ tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2lf%%\n",
+ v2_share*100);
+ tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2lf%%\n",
+ v3_share*100);
}
- data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
- DIRREQ_DIRECT);
- data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
- DIRREQ_DIRECT);
- if (fprintf(out, "dirreq-v3-direct-dl %s\ndirreq-v2-direct-dl %s\n",
- data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
- goto done;
- tor_free(data_v2);
- tor_free(data_v3);
- data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
- DIRREQ_TUNNELED);
- data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
- DIRREQ_TUNNELED);
- if (fprintf(out, "dirreq-v3-tunneled-dl %s\ndirreq-v2-tunneled-dl %s\n",
- data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
- goto done;
+ v2_direct_dl_string = geoip_get_dirreq_history(
+ GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT);
+ v3_direct_dl_string = geoip_get_dirreq_history(
+ GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT);
+
+ v2_tunneled_dl_string = geoip_get_dirreq_history(
+ GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED);
+ v3_tunneled_dl_string = geoip_get_dirreq_history(
+ GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED);
+
+ /* Put everything together into a single string. */
+ tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n"
+ "dirreq-v3-ips %s\n"
+ "dirreq-v2-ips %s\n"
+ "dirreq-v3-reqs %s\n"
+ "dirreq-v2-reqs %s\n"
+ "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
+ "not-found=%u,not-modified=%u,busy=%u\n"
+ "dirreq-v2-resp ok=%u,unavailable=%u,"
+ "not-found=%u,not-modified=%u,busy=%u\n"
+ "%s"
+ "%s"
+ "dirreq-v3-direct-dl %s\n"
+ "dirreq-v2-direct-dl %s\n"
+ "dirreq-v3-tunneled-dl %s\n"
+ "dirreq-v2-tunneled-dl %s\n",
+ t,
+ (unsigned) (now - start_of_dirreq_stats_interval),
+ v3_ips_string ? v3_ips_string : "",
+ v2_ips_string ? v2_ips_string : "",
+ v3_reqs_string ? v3_reqs_string : "",
+ v2_reqs_string ? v2_reqs_string : "",
+ ns_v3_responses[GEOIP_SUCCESS],
+ ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
+ ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
+ ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
+ ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
+ ns_v3_responses[GEOIP_REJECT_BUSY],
+ ns_v2_responses[GEOIP_SUCCESS],
+ ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
+ ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
+ ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
+ ns_v2_responses[GEOIP_REJECT_BUSY],
+ v2_share_string ? v2_share_string : "",
+ v3_share_string ? v3_share_string : "",
+ v3_direct_dl_string ? v3_direct_dl_string : "",
+ v2_direct_dl_string ? v2_direct_dl_string : "",
+ v3_tunneled_dl_string ? v3_tunneled_dl_string : "",
+ v2_tunneled_dl_string ? v2_tunneled_dl_string : "");
+
+ /* Free partial strings. */
+ tor_free(v3_ips_string);
+ tor_free(v2_ips_string);
+ tor_free(v3_reqs_string);
+ tor_free(v2_reqs_string);
+ tor_free(v2_share_string);
+ tor_free(v3_share_string);
+ tor_free(v3_direct_dl_string);
+ tor_free(v2_direct_dl_string);
+ tor_free(v3_tunneled_dl_string);
+ tor_free(v2_tunneled_dl_string);
- finish_writing_to_file(open_file);
- open_file = NULL;
+ return result;
+}
- start_of_dirreq_stats_interval = now;
+/** If 24 hours have passed since the beginning of the current dirreq
+ * stats period, write dirreq stats to $DATADIR/stats/dirreq-stats
+ * (possibly overwriting an existing file) and reset counters. Return
+ * when we would next want to write dirreq stats or 0 if we never want to
+ * write. */
+time_t
+geoip_dirreq_stats_write(time_t now)
+{
+ char *statsdir = NULL, *filename = NULL, *str = NULL;
+
+ if (!start_of_dirreq_stats_interval)
+ return 0; /* Not initialized. */
+ if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now)
+ goto done; /* Not ready to write. */
+
+ /* Discard all items in the client history that are too old. */
+ geoip_remove_old_clients(start_of_dirreq_stats_interval);
+
+ /* Generate history string .*/
+ str = geoip_format_dirreq_stats(now);
+
+ /* Write dirreq-stats string to disk. */
+ statsdir = get_datadir_fname("stats");
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
+ log_warn(LD_HIST, "Unable to create stats/ directory!");
+ goto done;
+ }
+ filename = get_datadir_fname2("stats", "dirreq-stats");
+ if (write_str_to_file(filename, str, 0) < 0)
+ log_warn(LD_HIST, "Unable to write dirreq statistics to disk!");
+
+ /* Reset measurement interval start. */
+ geoip_reset_dirreq_stats(now);
done:
- if (open_file)
- abort_writing_to_file(open_file);
- tor_free(filename);
tor_free(statsdir);
- tor_free(data_v2);
- tor_free(data_v3);
+ tor_free(filename);
+ tor_free(str);
return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -1160,8 +1197,8 @@ static char *bridge_stats_extrainfo = NULL;
/** Return a newly allocated string holding our bridge usage stats by country
* in a format suitable for inclusion in an extrainfo document. Return NULL on
* failure. */
-static char *
-format_bridge_stats_extrainfo(time_t now)
+char *
+geoip_format_bridge_stats(time_t now)
{
char *out = NULL, *data = NULL;
long duration = now - start_of_bridge_stats_interval;
@@ -1169,6 +1206,8 @@ format_bridge_stats_extrainfo(time_t now)
if (duration < 0)
return NULL;
+ if (!start_of_bridge_stats_interval)
+ return NULL; /* Not initialized. */
format_iso_time(written, now);
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
@@ -1218,7 +1257,7 @@ geoip_bridge_stats_write(time_t now)
geoip_remove_old_clients(start_of_bridge_stats_interval);
/* Generate formatted string */
- val = format_bridge_stats_extrainfo(now);
+ val = geoip_format_bridge_stats(now);
if (val == NULL)
goto done;
@@ -1295,25 +1334,51 @@ geoip_entry_stats_init(time_t now)
start_of_entry_stats_interval = now;
}
+/** Reset counters for entry stats. */
+void
+geoip_reset_entry_stats(time_t now)
+{
+ client_history_clear();
+ start_of_entry_stats_interval = now;
+}
+
/** Stop collecting entry stats in a way that we can re-start doing so in
* geoip_entry_stats_init(). */
void
geoip_entry_stats_term(void)
{
- client_history_clear();
- start_of_entry_stats_interval = 0;
+ geoip_reset_entry_stats(0);
}
-/** Write entry statistics to $DATADIR/stats/entry-stats and return time
- * when we would next want to write. */
+/** Return a newly allocated string containing the entry statistics
+ * until <b>now</b>, or NULL if we're not collecting entry stats. */
+char *
+geoip_format_entry_stats(time_t now)
+{
+ char t[ISO_TIME_LEN+1];
+ char *data = NULL;
+ char *result;
+
+ if (!start_of_entry_stats_interval)
+ return NULL; /* Not initialized. */
+
+ data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ format_iso_time(t, now);
+ tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
+ t, (unsigned) (now - start_of_entry_stats_interval),
+ data ? data : "");
+ tor_free(data);
+ return result;
+}
+
+/** If 24 hours have passed since the beginning of the current entry stats
+ * period, write entry stats to $DATADIR/stats/entry-stats (possibly
+ * overwriting an existing file) and reset counters. Return when we would
+ * next want to write entry stats or 0 if we never want to write. */
time_t
geoip_entry_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL;
- char *data = NULL;
- char written[ISO_TIME_LEN+1];
- open_file_t *open_file = NULL;
- FILE *out;
+ char *statsdir = NULL, *filename = NULL, *str = NULL;
if (!start_of_entry_stats_interval)
return 0; /* Not initialized. */
@@ -1323,31 +1388,26 @@ geoip_entry_stats_write(time_t now)
/* Discard all items in the client history that are too old. */
geoip_remove_old_clients(start_of_entry_stats_interval);
+ /* Generate history string .*/
+ str = geoip_format_entry_stats(now);
+
+ /* Write entry-stats string to disk. */
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
+ log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
+ }
filename = get_datadir_fname2("stats", "entry-stats");
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
- format_iso_time(written, now);
- out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
- 0600, &open_file);
- if (!out)
- goto done;
- if (fprintf(out, "entry-stats-end %s (%u s)\nentry-ips %s\n",
- written, (unsigned) (now - start_of_entry_stats_interval),
- data ? data : "") < 0)
- goto done;
+ if (write_str_to_file(filename, str, 0) < 0)
+ log_warn(LD_HIST, "Unable to write entry statistics to disk!");
- start_of_entry_stats_interval = now;
+ /* Reset measurement interval start. */
+ geoip_reset_entry_stats(now);
- finish_writing_to_file(open_file);
- open_file = NULL;
done:
- if (open_file)
- abort_writing_to_file(open_file);
- tor_free(filename);
tor_free(statsdir);
- tor_free(data);
+ tor_free(filename);
+ tor_free(str);
return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
}
diff --git a/src/or/geoip.h b/src/or/geoip.h
index b50da74dc3..ce3841967f 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -43,12 +43,17 @@ void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
dirreq_state_t new_state);
void geoip_dirreq_stats_init(time_t now);
+void geoip_reset_dirreq_stats(time_t now);
+char *geoip_format_dirreq_stats(time_t now);
time_t geoip_dirreq_stats_write(time_t now);
void geoip_dirreq_stats_term(void);
void geoip_entry_stats_init(time_t now);
time_t geoip_entry_stats_write(time_t now);
void geoip_entry_stats_term(void);
+void geoip_reset_entry_stats(time_t now);
+char *geoip_format_entry_stats(time_t now);
void geoip_bridge_stats_init(time_t now);
+char *geoip_format_bridge_stats(time_t now);
time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
diff --git a/src/or/main.c b/src/or/main.c
index 6866ccc8ce..2cdbe71f10 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -154,6 +154,12 @@ int can_complete_circuit=0;
* they are obsolete? */
#define TLS_HANDSHAKE_TIMEOUT (60)
+/** Decides our behavior when no logs are configured/before any
+ * logs have been configured. For 0, we log notice to stdout as normal.
+ * For 1, we log warnings only. For 2, we log nothing.
+ */
+int quiet_level = 0;
+
/********* END VARIABLES ************/
/****************************************************************************
@@ -2148,9 +2154,15 @@ tor_init(int argc, char *argv[])
default:
add_temp_log(LOG_NOTICE);
}
+ quiet_level = quiet;
- log(LOG_NOTICE, LD_GENERAL, "Tor v%s. This is experimental software. "
- "Do not rely on it for strong anonymity. (Running on %s)",get_version(),
+ log(LOG_NOTICE, LD_GENERAL, "Tor v%s%s. This is experimental software. "
+ "Do not rely on it for strong anonymity. (Running on %s)", get_version(),
+#ifdef USE_BUFFEREVENTS
+ " (with bufferevents)",
+#else
+ "",
+#endif
get_uname());
if (network_init()<0) {
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index 1b0c333dae..510b2f40f7 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -698,14 +698,9 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
int ret = options->UseMicrodescriptors;
if (ret == -1) {
/* UseMicrodescriptors is "auto"; we need to decide: */
-#if 0
- /* So we decide that we'll use microdescriptors iff we are not a server */
- ret = ! server_mode(options);
-#else
- /* We don't use microdescs for now: not enough caches are running
- * 0.2.3.1-alpha */
- ret = 0;
-#endif
+ /* So we decide that we'll use microdescriptors iff we are not a server,
+ * and we're not autofetching everything. */
+ ret = !server_mode(options) && !options->FetchUselessDescriptors;
}
return ret;
}
@@ -716,6 +711,8 @@ we_fetch_microdescriptors(const or_options_t *options)
{
if (directory_caches_dir_info(options))
return 1;
+ if (options->FetchUselessDescriptors)
+ return 1;
return we_use_microdescriptors_for_circuits(options);
}
@@ -725,6 +722,8 @@ we_fetch_router_descriptors(const or_options_t *options)
{
if (directory_caches_dir_info(options))
return 1;
+ if (options->FetchUselessDescriptors)
+ return 1;
return ! we_use_microdescriptors_for_circuits(options);
}
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 2586ce6ebe..398f041532 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1187,6 +1187,10 @@ we_want_to_fetch_flavor(const or_options_t *options, int flavor)
* it ourselves. */
return 1;
}
+ if (options->FetchUselessDescriptors) {
+ /* In order to get all descriptors, we need to fetch all consensuses. */
+ return 1;
+ }
/* Otherwise, we want the flavor only if we want to use it to build
* circuits. */
return flavor == usable_consensus_flavor();
@@ -2006,13 +2010,6 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
tor_memcmp(rs->identity_digest,
router->cache_info.identity_digest, DIGEST_LEN),
{
-#if 0
- /* We have no routerstatus for this router. Clear flags and skip it. */
- if (!authdir) {
- if (router->purpose == ROUTER_PURPOSE_GENERAL)
- router_clear_status_flags(router);
- }
-#endif
}) {
/* We have a routerstatus for this router. */
const char *digest = router->cache_info.identity_digest;
diff --git a/src/or/or.h b/src/or/or.h
index ca1433efc3..b67afd7900 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2558,8 +2558,15 @@ typedef struct origin_circuit_t {
char *dest_address;
int session_group;
unsigned nym_epoch;
+ size_t socks_username_len;
+ uint8_t socks_password_len;
+ /* Note that the next two values are NOT NUL-terminated; see
+ socks_username_len and socks_password_len for their lengths. */
char *socks_username;
char *socks_password;
+ /** Global identifier for the first stream attached here; used by
+ * ISO_STREAM. */
+ uint64_t associated_isolated_stream_global_id;
/**@}*/
} origin_circuit_t;
@@ -3416,6 +3423,8 @@ struct socks_request_t {
uint8_t auth_type;
/** What is this stream's goal? One of the SOCKS_COMMAND_* values */
uint8_t command;
+ /** Which kind of listener created this stream? */
+ uint8_t listener_type;
size_t replylen; /**< Length of <b>reply</b>. */
uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if
* we want to specify our own socks reply,
@@ -3432,7 +3441,7 @@ struct socks_request_t {
unsigned int got_auth : 1; /**< Have we received any authentication data? */
/** Number of bytes in username; 0 if username is NULL */
- uint8_t usernamelen;
+ size_t usernamelen;
/** Number of bytes in password; 0 if password is NULL */
uint8_t passwordlen;
/** The negotiated username value if any (for socks5), or the entire
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 1ad08fe93e..25aece3d59 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -2364,23 +2364,41 @@ typedef struct circ_buffer_stats_t {
/** List of circ_buffer_stats_t. */
static smartlist_t *circuits_for_buffer_stats = NULL;
+/** Remember cell statistics <b>mean_num_cells_in_queue</b>,
+ * <b>mean_time_cells_in_queue</b>, and <b>processed_cells</b> of a
+ * circuit. */
+void
+rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
+ double mean_time_cells_in_queue, uint32_t processed_cells)
+{
+ circ_buffer_stats_t *stat;
+ if (!start_of_buffer_stats_interval)
+ return; /* Not initialized. */
+ stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
+ stat->mean_num_cells_in_queue = mean_num_cells_in_queue;
+ stat->mean_time_cells_in_queue = mean_time_cells_in_queue;
+ stat->processed_cells = processed_cells;
+ if (!circuits_for_buffer_stats)
+ circuits_for_buffer_stats = smartlist_create();
+ smartlist_add(circuits_for_buffer_stats, stat);
+}
+
/** Remember cell statistics for circuit <b>circ</b> at time
* <b>end_of_interval</b> and reset cell counters in case the circuit
* remains open in the next measurement interval. */
void
rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
{
- circ_buffer_stats_t *stat;
time_t start_of_interval;
int interval_length;
or_circuit_t *orcirc;
+ double mean_num_cells_in_queue, mean_time_cells_in_queue;
+ uint32_t processed_cells;
if (CIRCUIT_IS_ORIGIN(circ))
return;
orcirc = TO_OR_CIRCUIT(circ);
if (!orcirc->processed_cells)
return;
- if (!circuits_for_buffer_stats)
- circuits_for_buffer_stats = smartlist_create();
start_of_interval = (circ->timestamp_created.tv_sec >
start_of_buffer_stats_interval) ?
circ->timestamp_created.tv_sec :
@@ -2388,17 +2406,18 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
interval_length = (int) (end_of_interval - start_of_interval);
if (interval_length <= 0)
return;
- stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
- stat->processed_cells = orcirc->processed_cells;
+ processed_cells = orcirc->processed_cells;
/* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
- stat->mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
+ mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
(double) interval_length / 1000.0 / 2.0;
- stat->mean_time_cells_in_queue =
+ mean_time_cells_in_queue =
(double) orcirc->total_cell_waiting_time /
(double) orcirc->processed_cells;
- smartlist_add(circuits_for_buffer_stats, stat);
orcirc->total_cell_waiting_time = 0;
orcirc->processed_cells = 0;
+ rep_hist_add_buffer_stats(mean_num_cells_in_queue,
+ mean_time_cells_in_queue,
+ processed_cells);
}
/** Sorting helper: return -1, 1, or 0 based on comparison of two
@@ -2420,135 +2439,160 @@ _buffer_stats_compare_entries(const void **_a, const void **_b)
void
rep_hist_buffer_stats_term(void)
{
- start_of_buffer_stats_interval = 0;
+ rep_hist_reset_buffer_stats(0);
+}
+
+/** Clear history of circuit statistics and set the measurement interval
+ * start to <b>now</b>. */
+void
+rep_hist_reset_buffer_stats(time_t now)
+{
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
stat, tor_free(stat));
smartlist_clear(circuits_for_buffer_stats);
+ start_of_buffer_stats_interval = now;
}
-/** Write buffer statistics to $DATADIR/stats/buffer-stats and return when
- * we would next want to write exit stats. */
-time_t
-rep_hist_buffer_stats_write(time_t now)
+/** Return a newly allocated string containing the buffer statistics until
+ * <b>now</b>, or NULL if we're not collecting buffer stats. */
+char *
+rep_hist_format_buffer_stats(time_t now)
{
- char *statsdir = NULL, *filename = NULL;
- char written[ISO_TIME_LEN+1];
- open_file_t *open_file = NULL;
- FILE *out;
#define SHARES 10
int processed_cells[SHARES], circs_in_share[SHARES],
number_of_circuits, i;
double queued_cells[SHARES], time_in_queue[SHARES];
- smartlist_t *str_build = NULL;
- char *str = NULL, *buf = NULL;
- circuit_t *circ;
+ char *buf = NULL;
+ smartlist_t *processed_cells_strings, *queued_cells_strings,
+ *time_in_queue_strings;
+ char *processed_cells_string, *queued_cells_string,
+ *time_in_queue_string;
+ char t[ISO_TIME_LEN+1];
+ char *result;
if (!start_of_buffer_stats_interval)
- return 0; /* Not initialized. */
- if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
- goto done; /* Not ready to write */
-
- str_build = smartlist_create();
+ return NULL; /* Not initialized. */
- /* add current circuits to stats */
- for (circ = _circuit_get_global_list(); circ; circ = circ->next)
- rep_hist_buffer_stats_add_circ(circ, now);
- /* calculate deciles */
+ /* Calculate deciles if we saw at least one circuit. */
memset(processed_cells, 0, SHARES * sizeof(int));
memset(circs_in_share, 0, SHARES * sizeof(int));
memset(queued_cells, 0, SHARES * sizeof(double));
memset(time_in_queue, 0, SHARES * sizeof(double));
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
- smartlist_sort(circuits_for_buffer_stats,
- _buffer_stats_compare_entries);
number_of_circuits = smartlist_len(circuits_for_buffer_stats);
- if (number_of_circuits < 1) {
- log_info(LD_HIST, "Attempt to write cell statistics to disk failed. "
- "We haven't seen a single circuit to report about.");
- goto done;
+ if (number_of_circuits > 0) {
+ smartlist_sort(circuits_for_buffer_stats,
+ _buffer_stats_compare_entries);
+ i = 0;
+ SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
+ circ_buffer_stats_t *, stat)
+ {
+ int share = i++ * SHARES / number_of_circuits;
+ processed_cells[share] += stat->processed_cells;
+ queued_cells[share] += stat->mean_num_cells_in_queue;
+ time_in_queue[share] += stat->mean_time_cells_in_queue;
+ circs_in_share[share]++;
+ }
+ SMARTLIST_FOREACH_END(stat);
}
- i = 0;
- SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
- circ_buffer_stats_t *, stat)
- {
- int share = i++ * SHARES / number_of_circuits;
- processed_cells[share] += stat->processed_cells;
- queued_cells[share] += stat->mean_num_cells_in_queue;
- time_in_queue[share] += stat->mean_time_cells_in_queue;
- circs_in_share[share]++;
- }
- SMARTLIST_FOREACH_END(stat);
- /* clear buffer stats history */
- SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
- stat, tor_free(stat));
- smartlist_clear(circuits_for_buffer_stats);
- /* write to file */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
- goto done;
- filename = get_datadir_fname2("stats", "buffer-stats");
- out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
- 0600, &open_file);
- if (!out)
- goto done;
- format_iso_time(written, now);
- if (fprintf(out, "cell-stats-end %s (%d s)\n", written,
- (unsigned) (now - start_of_buffer_stats_interval)) < 0)
- goto done;
+
+ /* Write deciles to strings. */
+ processed_cells_strings = smartlist_create();
+ queued_cells_strings = smartlist_create();
+ time_in_queue_strings = smartlist_create();
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf,"%d", !circs_in_share[i] ? 0 :
processed_cells[i] / circs_in_share[i]);
- smartlist_add(str_build, buf);
+ smartlist_add(processed_cells_strings, buf);
}
- str = smartlist_join_strings(str_build, ",", 0, NULL);
- if (fprintf(out, "cell-processed-cells %s\n", str) < 0)
- goto done;
- tor_free(str);
- SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
- smartlist_clear(str_build);
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf, "%.2f", circs_in_share[i] == 0 ? 0.0 :
queued_cells[i] / (double) circs_in_share[i]);
- smartlist_add(str_build, buf);
+ smartlist_add(queued_cells_strings, buf);
}
- str = smartlist_join_strings(str_build, ",", 0, NULL);
- if (fprintf(out, "cell-queued-cells %s\n", str) < 0)
- goto done;
- tor_free(str);
- SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
- smartlist_clear(str_build);
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf, "%.0f", circs_in_share[i] == 0 ? 0.0 :
time_in_queue[i] / (double) circs_in_share[i]);
- smartlist_add(str_build, buf);
+ smartlist_add(time_in_queue_strings, buf);
}
- str = smartlist_join_strings(str_build, ",", 0, NULL);
- if (fprintf(out, "cell-time-in-queue %s\n", str) < 0)
- goto done;
- tor_free(str);
- SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
- smartlist_free(str_build);
- str_build = NULL;
- if (fprintf(out, "cell-circuits-per-decile %d\n",
- (number_of_circuits + SHARES - 1) / SHARES) < 0)
+
+ /* Join all observations in single strings. */
+ processed_cells_string = smartlist_join_strings(processed_cells_strings,
+ ",", 0, NULL);
+ queued_cells_string = smartlist_join_strings(queued_cells_strings,
+ ",", 0, NULL);
+ time_in_queue_string = smartlist_join_strings(time_in_queue_strings,
+ ",", 0, NULL);
+ SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp));
+ smartlist_free(processed_cells_strings);
+ smartlist_free(queued_cells_strings);
+ smartlist_free(time_in_queue_strings);
+
+ /* Put everything together. */
+ format_iso_time(t, now);
+ tor_asprintf(&result, "cell-stats-end %s (%d s)\n"
+ "cell-processed-cells %s\n"
+ "cell-queued-cells %s\n"
+ "cell-time-in-queue %s\n"
+ "cell-circuits-per-decile %d\n",
+ t, (unsigned) (now - start_of_buffer_stats_interval),
+ processed_cells_string,
+ queued_cells_string,
+ time_in_queue_string,
+ (number_of_circuits + SHARES - 1) / SHARES);
+ tor_free(processed_cells_string);
+ tor_free(queued_cells_string);
+ tor_free(time_in_queue_string);
+ return result;
+#undef SHARES
+}
+
+/** If 24 hours have passed since the beginning of the current buffer
+ * stats period, write buffer stats to $DATADIR/stats/buffer-stats
+ * (possibly overwriting an existing file) and reset counters. Return
+ * when we would next want to write buffer stats or 0 if we never want to
+ * write. */
+time_t
+rep_hist_buffer_stats_write(time_t now)
+{
+ circuit_t *circ;
+ char *statsdir = NULL, *filename = NULL, *str = NULL;
+
+ if (!start_of_buffer_stats_interval)
+ return 0; /* Not initialized. */
+ if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
+ goto done; /* Not ready to write */
+
+ /* Add open circuits to the history. */
+ for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ rep_hist_buffer_stats_add_circ(circ, now);
+ }
+
+ /* Generate history string. */
+ str = rep_hist_format_buffer_stats(now);
+
+ /* Reset both buffer history and counters of open circuits. */
+ rep_hist_reset_buffer_stats(now);
+
+ /* Try to write to disk. */
+ statsdir = get_datadir_fname("stats");
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
+ log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
- finish_writing_to_file(open_file);
- open_file = NULL;
- start_of_buffer_stats_interval = now;
+ }
+ filename = get_datadir_fname2("stats", "buffer-stats");
+ if (write_str_to_file(filename, str, 0) < 0)
+ log_warn(LD_HIST, "Unable to write buffer stats to disk!");
+
done:
- if (open_file)
- abort_writing_to_file(open_file);
+ tor_free(str);
tor_free(filename);
tor_free(statsdir);
- if (str_build) {
- SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
- smartlist_free(str_build);
- }
- tor_free(str);
-#undef SHARES
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
}
diff --git a/src/or/rephist.h b/src/or/rephist.h
index 5748748a80..e590659441 100644
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@ -77,6 +77,10 @@ void rep_hist_buffer_stats_add_circ(circuit_t *circ,
time_t end_of_interval);
time_t rep_hist_buffer_stats_write(time_t now);
void rep_hist_buffer_stats_term(void);
+void rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
+ double mean_time_cells_in_queue, uint32_t processed_cells);
+char *rep_hist_format_buffer_stats(time_t now);
+void rep_hist_reset_buffer_stats(time_t now);
void rep_hist_conn_stats_init(time_t now);
void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
diff --git a/src/or/status.c b/src/or/status.c
index acb8ba4144..3e4cb779a3 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -103,7 +103,7 @@ log_heartbeat(time_t now)
bw_sent = bytes_to_usage(get_bytes_written());
log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d "
- "circuits open. I've pushed %s and received %s.",
+ "circuits open. I've sent %s and received %s.",
uptime, count_circuits(),bw_sent,bw_rcvd);
tor_free(uptime);