aboutsummaryrefslogtreecommitdiff
path: root/src/or/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/main.c')
-rw-r--r--src/or/main.c478
1 files changed, 413 insertions, 65 deletions
diff --git a/src/or/main.c b/src/or/main.c
index b1159746a..c1a7015e6 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -33,9 +33,11 @@
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "ntmain.h"
#include "onion.h"
#include "policies.h"
+#include "transports.h"
#include "relay.h"
#include "rendclient.h"
#include "rendcommon.h"
@@ -44,6 +46,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "status.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
#include <openssl/crypto.h>
@@ -56,6 +59,10 @@
#include <event.h>
#endif
+#ifdef USE_BUFFEREVENTS
+#include <event2/bufferevent.h>
+#endif
+
void evdns_shutdown(int);
/********* PROTOTYPES **********/
@@ -71,6 +78,7 @@ static int connection_should_read_from_linked_conn(connection_t *conn);
/********* START VARIABLES **********/
+#ifndef USE_BUFFEREVENTS
int global_read_bucket; /**< Max number of bytes I can read this second. */
int global_write_bucket; /**< Max number of bytes I can write this second. */
@@ -78,13 +86,17 @@ int global_write_bucket; /**< Max number of bytes I can write this second. */
int global_relayed_read_bucket;
/** Max number of relayed (bandwidth class 1) bytes I can write this second. */
int global_relayed_write_bucket;
-
/** What was the read bucket before the last second_elapsed_callback() call?
* (used to determine how many bytes we've read). */
static int stats_prev_global_read_bucket;
/** What was the write bucket before the last second_elapsed_callback() call?
* (used to determine how many bytes we've written). */
static int stats_prev_global_write_bucket;
+#endif
+
+static uint64_t stats_prev_n_read = 0;
+static uint64_t stats_prev_n_written = 0;
+
/* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/
/** How many bytes have we read since we started the process? */
static uint64_t stats_n_bytes_read = 0;
@@ -103,6 +115,8 @@ static time_t time_to_check_for_correct_dns = 0;
static time_t time_of_last_signewnym = 0;
/** Is there a signewnym request we're currently waiting to handle? */
static int signewnym_is_pending = 0;
+/** How many times have we called newnym? */
+static unsigned newnym_epoch = 0;
/** Smartlist of all open connections. */
static smartlist_t *connection_array = NULL;
@@ -141,6 +155,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 ************/
/****************************************************************************
@@ -150,12 +170,38 @@ int can_complete_circuit=0;
*
****************************************************************************/
+#if 0 && defined(USE_BUFFEREVENTS)
+static void
+free_old_inbuf(connection_t *conn)
+{
+ if (! conn->inbuf)
+ return;
+
+ tor_assert(conn->outbuf);
+ tor_assert(buf_datalen(conn->inbuf) == 0);
+ tor_assert(buf_datalen(conn->outbuf) == 0);
+ buf_free(conn->inbuf);
+ buf_free(conn->outbuf);
+ conn->inbuf = conn->outbuf = NULL;
+
+ if (conn->read_event) {
+ event_del(conn->read_event);
+ tor_event_free(conn->read_event);
+ }
+ if (conn->write_event) {
+ event_del(conn->read_event);
+ tor_event_free(conn->write_event);
+ }
+ conn->read_event = conn->write_event = NULL;
+}
+#endif
+
/** Add <b>conn</b> to the array of connections that we can poll on. The
* connection's socket must be set; the connection starts out
* non-reading and non-writing.
*/
int
-connection_add(connection_t *conn)
+connection_add_impl(connection_t *conn, int is_connecting)
{
tor_assert(conn);
tor_assert(SOCKET_OK(conn->s) ||
@@ -167,11 +213,63 @@ connection_add(connection_t *conn)
conn->conn_array_index = smartlist_len(connection_array);
smartlist_add(connection_array, conn);
- if (SOCKET_OK(conn->s) || conn->linked) {
+#ifdef USE_BUFFEREVENTS
+ if (connection_type_uses_bufferevent(conn)) {
+ if (SOCKET_OK(conn->s) && !conn->linked) {
+ conn->bufev = bufferevent_socket_new(
+ tor_libevent_get_base(),
+ conn->s,
+ BEV_OPT_DEFER_CALLBACKS);
+ if (!conn->bufev) {
+ log_warn(LD_BUG, "Unable to create socket bufferevent");
+ smartlist_del(connection_array, conn->conn_array_index);
+ conn->conn_array_index = -1;
+ return -1;
+ }
+ if (is_connecting) {
+ /* Put the bufferevent into a "connecting" state so that we'll get
+ * a "connected" event callback on successful write. */
+ bufferevent_socket_connect(conn->bufev, NULL, 0);
+ }
+ connection_configure_bufferevent_callbacks(conn);
+ } else if (conn->linked && conn->linked_conn &&
+ connection_type_uses_bufferevent(conn->linked_conn)) {
+ tor_assert(!(SOCKET_OK(conn->s)));
+ if (!conn->bufev) {
+ struct bufferevent *pair[2] = { NULL, NULL };
+ if (bufferevent_pair_new(tor_libevent_get_base(),
+ BEV_OPT_DEFER_CALLBACKS,
+ pair) < 0) {
+ log_warn(LD_BUG, "Unable to create bufferevent pair");
+ smartlist_del(connection_array, conn->conn_array_index);
+ conn->conn_array_index = -1;
+ return -1;
+ }
+ tor_assert(pair[0]);
+ conn->bufev = pair[0];
+ conn->linked_conn->bufev = pair[1];
+ } /* else the other side already was added, and got a bufferevent_pair */
+ connection_configure_bufferevent_callbacks(conn);
+ } else {
+ tor_assert(!conn->linked);
+ }
+
+ if (conn->bufev)
+ tor_assert(conn->inbuf == NULL);
+
+ if (conn->linked_conn && conn->linked_conn->bufev)
+ tor_assert(conn->linked_conn->inbuf == NULL);
+ }
+#else
+ (void) is_connecting;
+#endif
+
+ if (!HAS_BUFFEREVENT(conn) && (SOCKET_OK(conn->s) || conn->linked)) {
conn->read_event = tor_event_new(tor_libevent_get_base(),
conn->s, EV_READ|EV_PERSIST, conn_read_callback, conn);
conn->write_event = tor_event_new(tor_libevent_get_base(),
conn->s, EV_WRITE|EV_PERSIST, conn_write_callback, conn);
+ /* XXXX CHECK FOR NULL RETURN! */
}
log_debug(LD_NET,"new conn type %s, socket %d, address %s, n_conns %d.",
@@ -195,7 +293,13 @@ connection_unregister_events(connection_t *conn)
log_warn(LD_BUG, "Error removing write event for %d", (int)conn->s);
tor_free(conn->write_event);
}
- if (conn->dns_server_port) {
+#ifdef USE_BUFFEREVENTS
+ if (conn->bufev) {
+ bufferevent_free(conn->bufev);
+ conn->bufev = NULL;
+ }
+#endif
+ if (conn->type == CONN_TYPE_AP_DNS_LISTENER) {
dnsserv_close_listener(conn);
}
}
@@ -303,12 +407,37 @@ get_connection_array(void)
return connection_array;
}
+/** Provides the traffic read and written over the life of the process. */
+
+uint64_t
+get_bytes_read(void)
+{
+ return stats_n_bytes_read;
+}
+
+uint64_t
+get_bytes_written(void)
+{
+ return stats_n_bytes_written;
+}
+
/** Set the event mask on <b>conn</b> to <b>events</b>. (The event
* mask is a bitmask whose bits are READ_EVENT and WRITE_EVENT)
*/
void
connection_watch_events(connection_t *conn, watchable_events_t events)
{
+ IF_HAS_BUFFEREVENT(conn, {
+ short ev = ((short)events) & (EV_READ|EV_WRITE);
+ short old_ev = bufferevent_get_enabled(conn->bufev);
+ if ((ev & ~old_ev) != 0) {
+ bufferevent_enable(conn->bufev, ev);
+ }
+ if ((old_ev & ~ev) != 0) {
+ bufferevent_disable(conn->bufev, old_ev & ~ev);
+ }
+ return;
+ });
if (events & READ_EVENT)
connection_start_reading(conn);
else
@@ -326,6 +455,9 @@ connection_is_reading(connection_t *conn)
{
tor_assert(conn);
+ IF_HAS_BUFFEREVENT(conn,
+ return (bufferevent_get_enabled(conn->bufev) & EV_READ) != 0;
+ );
return conn->reading_from_linked_conn ||
(conn->read_event && event_pending(conn->read_event, EV_READ, NULL));
}
@@ -335,6 +467,12 @@ void
connection_stop_reading(connection_t *conn)
{
tor_assert(conn);
+
+ IF_HAS_BUFFEREVENT(conn, {
+ bufferevent_disable(conn->bufev, EV_READ);
+ return;
+ });
+
tor_assert(conn->read_event);
if (conn->linked) {
@@ -354,6 +492,12 @@ void
connection_start_reading(connection_t *conn)
{
tor_assert(conn);
+
+ IF_HAS_BUFFEREVENT(conn, {
+ bufferevent_enable(conn->bufev, EV_READ);
+ return;
+ });
+
tor_assert(conn->read_event);
if (conn->linked) {
@@ -375,6 +519,10 @@ connection_is_writing(connection_t *conn)
{
tor_assert(conn);
+ IF_HAS_BUFFEREVENT(conn,
+ return (bufferevent_get_enabled(conn->bufev) & EV_WRITE) != 0;
+ );
+
return conn->writing_to_linked_conn ||
(conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL));
}
@@ -384,6 +532,12 @@ void
connection_stop_writing(connection_t *conn)
{
tor_assert(conn);
+
+ IF_HAS_BUFFEREVENT(conn, {
+ bufferevent_disable(conn->bufev, EV_WRITE);
+ return;
+ });
+
tor_assert(conn->write_event);
if (conn->linked) {
@@ -404,6 +558,12 @@ void
connection_start_writing(connection_t *conn)
{
tor_assert(conn);
+
+ IF_HAS_BUFFEREVENT(conn, {
+ bufferevent_enable(conn->bufev, EV_WRITE);
+ return;
+ });
+
tor_assert(conn->write_event);
if (conn->linked) {
@@ -590,9 +750,32 @@ conn_close_if_marked(int i)
assert_connection_ok(conn, now);
/* assert_all_pending_dns_resolves_ok(); */
- log_debug(LD_NET,"Cleaning up connection (fd %d).",(int)conn->s);
- if ((SOCKET_OK(conn->s) || conn->linked_conn)
- && connection_wants_to_flush(conn)) {
+#ifdef USE_BUFFEREVENTS
+ if (conn->bufev) {
+ if (conn->hold_open_until_flushed &&
+ evbuffer_get_length(bufferevent_get_output(conn->bufev))) {
+ /* don't close yet. */
+ return 0;
+ }
+ if (conn->linked_conn && ! conn->linked_conn->marked_for_close) {
+ /* We need to do this explicitly so that the linked connection
+ * notices that there was an EOF. */
+ bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED);
+ }
+ }
+#endif
+
+ log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
+
+ /* If the connection we are about to close was trying to connect to
+ a proxy server and failed, the client won't be able to use that
+ proxy. We should warn the user about this. */
+ if (conn->proxy_state == PROXY_INFANT)
+ log_failed_proxy_connection(conn);
+
+ IF_HAS_BUFFEREVENT(conn, goto unlink);
+ if ((SOCKET_OK(conn->s) || conn->linked_conn) &&
+ connection_wants_to_flush(conn)) {
/* s == -1 means it's an incomplete edge connection, or that the socket
* has already been closed as unflushable. */
ssize_t sz = connection_bucket_write_limit(conn, now);
@@ -614,8 +797,8 @@ conn_close_if_marked(int i)
}
log_debug(LD_GENERAL, "Flushed last %d bytes from a linked conn; "
"%d left; flushlen %d; wants-to-flush==%d", retval,
- (int)buf_datalen(conn->outbuf),
- (int)conn->outbuf_flushlen,
+ (int)connection_get_outbuf_len(conn),
+ (int)conn->outbuf_flushlen,
connection_wants_to_flush(conn));
} else if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN) {
@@ -652,13 +835,17 @@ conn_close_if_marked(int i)
"something is wrong with your network connection, or "
"something is wrong with theirs. "
"(fd %d, type %s, state %d, marked at %s:%d).",
- (int)buf_datalen(conn->outbuf),
+ (int)connection_get_outbuf_len(conn),
escaped_safe_str_client(conn->address),
(int)conn->s, conn_type_to_string(conn->type), conn->state,
conn->marked_for_close_file,
conn->marked_for_close);
}
}
+
+#ifdef USE_BUFFEREVENTS
+ unlink:
+#endif
connection_unlink(conn); /* unlink, remove, free */
return 1;
}
@@ -679,13 +866,13 @@ directory_all_unreachable(time_t now)
while ((conn = connection_get_by_type_state(CONN_TYPE_AP,
AP_CONN_STATE_CIRCUIT_WAIT))) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ entry_connection_t *entry_conn = TO_ENTRY_CONN(conn);
log_notice(LD_NET,
"Is your network connection down? "
"Failing connection to '%s:%d'.",
- safe_str_client(edge_conn->socks_request->address),
- edge_conn->socks_request->port);
- connection_mark_unattached_ap(edge_conn,
+ safe_str_client(entry_conn->socks_request->address),
+ entry_conn->socks_request->port);
+ connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_NET_UNREACHABLE);
}
control_event_general_status(LOG_ERR, "DIR_ALL_UNREACHABLE");
@@ -696,18 +883,19 @@ directory_all_unreachable(time_t now)
void
directory_info_has_arrived(time_t now, int from_cache)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (!router_have_minimum_dir_info()) {
int quiet = directory_too_idle_to_fetch_descriptors(options, now);
log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
"I learned some more directory information, but not enough to "
"build a circuit: %s", get_dir_info_status_string());
- update_router_descriptor_downloads(now);
+ update_all_descriptor_downloads(now);
return;
} else {
- if (directory_fetches_from_authorities(options))
- update_router_descriptor_downloads(now);
+ if (directory_fetches_from_authorities(options)) {
+ update_all_descriptor_downloads(now);
+ }
/* if we have enough dir info, then update our guard status with
* whatever we just learned. */
@@ -740,12 +928,13 @@ run_connection_housekeeping(int i, time_t now)
{
cell_t cell;
connection_t *conn = smartlist_get(connection_array, i);
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
or_connection_t *or_conn;
int past_keepalive =
now >= conn->timestamp_lastwritten + options->KeepalivePeriod;
- if (conn->outbuf && !buf_datalen(conn->outbuf) && conn->type == CONN_TYPE_OR)
+ if (conn->outbuf && !connection_get_outbuf_len(conn) &&
+ conn->type == CONN_TYPE_OR)
TO_OR_CONN(conn)->timestamp_lastempty = now;
if (conn->marked_for_close) {
@@ -765,7 +954,7 @@ run_connection_housekeeping(int i, time_t now)
/* This check is temporary; it's to let us know whether we should consider
* parsing partial serverdesc responses. */
if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
- buf_datalen(conn->inbuf)>=1024) {
+ connection_get_inbuf_len(conn) >= 1024) {
log_info(LD_DIR,"Trying to extract information from wedged server desc "
"download.");
connection_dir_reached_eof(TO_DIR_CONN(conn));
@@ -782,7 +971,11 @@ run_connection_housekeeping(int i, time_t now)
the connection or send a keepalive, depending. */
or_conn = TO_OR_CONN(conn);
+#ifdef USE_BUFFEREVENTS
+ tor_assert(conn->bufev);
+#else
tor_assert(conn->outbuf);
+#endif
if (or_conn->is_bad_for_new_circs && !or_conn->n_circuits) {
/* It's bad for new circuits, and has no unmarked circuits on it:
@@ -794,8 +987,7 @@ run_connection_housekeeping(int i, time_t now)
connection_or_connect_failed(TO_OR_CONN(conn),
END_OR_CONN_REASON_TIMEOUT,
"Tor gave up on the connection");
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
+ connection_mark_and_flush(conn);
} else if (!connection_state_is_open(conn)) {
if (past_keepalive) {
/* We never managed to actually get this connection open and happy. */
@@ -804,13 +996,12 @@ run_connection_housekeeping(int i, time_t now)
connection_mark_for_close(conn);
}
} else if (we_are_hibernating() && !or_conn->n_circuits &&
- !buf_datalen(conn->outbuf)) {
+ !connection_get_outbuf_len(conn)) {
/* We're hibernating, there's no circuits, and nothing to flush.*/
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
(int)conn->s,conn->address, conn->port);
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
+ connection_mark_and_flush(conn);
} else if (!or_conn->n_circuits &&
now >= or_conn->timestamp_last_added_nonpadding +
IDLE_OR_CONN_TIMEOUT) {
@@ -818,7 +1009,6 @@ run_connection_housekeeping(int i, time_t now)
"[idle %d].", (int)conn->s,conn->address, conn->port,
(int)(now - or_conn->timestamp_last_added_nonpadding));
connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
} else if (
now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
@@ -826,10 +1016,10 @@ run_connection_housekeeping(int i, time_t now)
"Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to "
"flush; %d seconds since last write)",
(int)conn->s, conn->address, conn->port,
- (int)buf_datalen(conn->outbuf),
+ (int)connection_get_outbuf_len(conn),
(int)(now-conn->timestamp_lastwritten));
connection_mark_for_close(conn);
- } else if (past_keepalive && !buf_datalen(conn->outbuf)) {
+ } else if (past_keepalive && !connection_get_outbuf_len(conn)) {
/* send a padding cell */
log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
conn->address, conn->port);
@@ -844,7 +1034,7 @@ run_connection_housekeeping(int i, time_t now)
static void
signewnym_impl(time_t now)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (!proxy_mode(options)) {
log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality "
"is disabled.");
@@ -856,6 +1046,17 @@ signewnym_impl(time_t now)
rend_client_purge_state();
time_of_last_signewnym = now;
signewnym_is_pending = 0;
+
+ ++newnym_epoch;
+
+ control_event_signal(SIGNEWNYM);
+}
+
+/** Return the number of times that signewnym has been called. */
+unsigned
+get_signewnym_epoch(void)
+{
+ return newnym_epoch;
}
/** Perform regular maintenance tasks. This function gets run once per
@@ -881,10 +1082,14 @@ run_scheduled_events(time_t now)
static time_t time_to_check_for_expired_networkstatus = 0;
static time_t time_to_write_stats_files = 0;
static time_t time_to_write_bridge_stats = 0;
+ static time_t time_to_check_port_forwarding = 0;
static time_t time_to_launch_reachability_tests = 0;
static int should_init_bridge_stats = 1;
static time_t time_to_retry_dns_init = 0;
- or_options_t *options = get_options();
+ static time_t time_to_next_heartbeat = 0;
+ static int has_validated_pt = 0;
+ const or_options_t *options = get_options();
+
int is_server = server_mode(options);
int i;
int have_dir_info;
@@ -895,6 +1100,16 @@ run_scheduled_events(time_t now)
*/
consider_hibernation(now);
+#if 0
+ {
+ static time_t nl_check_time = 0;
+ if (nl_check_time <= now) {
+ nodelist_assert_ok();
+ nl_check_time = now + 30;
+ }
+ }
+#endif
+
/* 0b. If we've deferred a signewnym, make sure it gets handled
* eventually. */
if (signewnym_is_pending &&
@@ -923,7 +1138,7 @@ run_scheduled_events(time_t now)
}
if (time_to_try_getting_descriptors < now) {
- update_router_descriptor_downloads(now);
+ update_all_descriptor_downloads(now);
update_extrainfo_downloads(now);
if (router_have_minimum_dir_info())
time_to_try_getting_descriptors = now + LAZY_DESCRIPTOR_RETRY_INTERVAL;
@@ -1048,6 +1263,16 @@ run_scheduled_events(time_t now)
if (next_write && next_write < next_time_to_write_stats_files)
next_time_to_write_stats_files = next_write;
}
+ if (options->ConnDirectionStatistics) {
+ time_t next_write = rep_hist_conn_stats_write(time_to_write_stats_files);
+ if (next_write && next_write < next_time_to_write_stats_files)
+ next_time_to_write_stats_files = next_write;
+ }
+ if (options->BridgeAuthoritativeDir) {
+ time_t next_write = rep_hist_desc_stats_write(time_to_write_stats_files);
+ if (next_write && next_write < next_time_to_write_stats_files)
+ next_time_to_write_stats_files = next_write;
+ }
time_to_write_stats_files = next_time_to_write_stats_files;
}
@@ -1076,10 +1301,9 @@ run_scheduled_events(time_t now)
/* Remove old information from rephist and the rend cache. */
if (time_to_clean_caches < now) {
rep_history_clean(now - options->RephistTrackTime);
- rend_cache_clean();
- rend_cache_clean_v2_descs_as_dir();
- if (authdir_mode_v3(options))
- microdesc_cache_rebuild(NULL, 0);
+ rend_cache_clean(now);
+ rend_cache_clean_v2_descs_as_dir(now);
+ microdesc_cache_rebuild(NULL, 0);
#define CLEAN_CACHES_INTERVAL (30*60)
time_to_clean_caches = now + CLEAN_CACHES_INTERVAL;
}
@@ -1088,7 +1312,7 @@ run_scheduled_events(time_t now)
/* If we're a server and initializing dns failed, retry periodically. */
if (time_to_retry_dns_init < now) {
time_to_retry_dns_init = now + RETRY_DNS_INTERVAL;
- if (server_mode(options) && has_dns_init_failed())
+ if (is_server && has_dns_init_failed())
dns_init();
}
@@ -1111,15 +1335,11 @@ run_scheduled_events(time_t now)
time_to_check_ipaddress = now + CHECK_IPADDRESS_INTERVAL;
check_descriptor_ipaddress_changed(now);
}
-/** If our router descriptor ever goes this long without being regenerated
- * because something changed, we force an immediate regenerate-and-upload. */
-#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)
- mark_my_descriptor_dirty_if_older_than(
- now - FORCE_REGENERATE_DESCRIPTOR_INTERVAL);
+ mark_my_descriptor_dirty_if_too_old(now);
consider_publishable_server(0);
/* also, check religiously for reachability, if it's within the first
* 20 minutes of our uptime. */
- if (server_mode(options) &&
+ if (is_server &&
(can_complete_circuit || !any_predicted_circuits(now)) &&
!we_are_hibernating()) {
if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
@@ -1130,7 +1350,7 @@ run_scheduled_events(time_t now)
/* If we haven't checked for 12 hours and our bandwidth estimate is
* low, do another bandwidth test. This is especially important for
* bridges, since they might go long periods without much use. */
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
if (time_to_recheck_bandwidth && me &&
me->bandwidthcapacity < me->bandwidthrate &&
me->bandwidthcapacity < 51200) {
@@ -1251,13 +1471,44 @@ run_scheduled_events(time_t now)
}
}
- /** 10b. write bridge networkstatus file to disk */
+ /** 10. write bridge networkstatus file to disk */
if (options->BridgeAuthoritativeDir &&
time_to_write_bridge_status_file < now) {
networkstatus_dump_bridge_status_to_file(now);
#define BRIDGE_STATUSFILE_INTERVAL (30*60)
time_to_write_bridge_status_file = now+BRIDGE_STATUSFILE_INTERVAL;
}
+
+ /** 11. check the port forwarding app */
+ if (time_to_check_port_forwarding < now &&
+ options->PortForwarding &&
+ is_server) {
+#define PORT_FORWARDING_CHECK_INTERVAL 5
+ tor_check_port_forwarding(options->PortForwardingHelper,
+ options->DirPort,
+ options->ORPort,
+ now);
+ time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL;
+ }
+
+ /** 11b. check pending unconfigured managed proxies */
+ if (pt_proxies_configuration_pending())
+ pt_configure_remaining_proxies();
+
+ /** 11c. validate pluggable transports configuration if we need to */
+ if (!has_validated_pt &&
+ (options->Bridges || options->ClientTransportPlugin)) {
+ if (validate_pluggable_transports_config() == 0) {
+ has_validated_pt = 1;
+ }
+ }
+
+ /** 12. write the heartbeat message */
+ if (options->HeartbeatPeriod &&
+ time_to_next_heartbeat < now) {
+ log_heartbeat(now);
+ time_to_next_heartbeat = now+options->HeartbeatPeriod;
+ }
}
/** Timer: used to invoke second_elapsed_callback() once per second. */
@@ -1277,7 +1528,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
size_t bytes_written;
size_t bytes_read;
int seconds_elapsed;
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
(void)timer;
(void)arg;
@@ -1288,21 +1539,30 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
update_approx_time(now);
/* the second has rolled over. check more stuff. */
- bytes_written = stats_prev_global_write_bucket - global_write_bucket;
- bytes_read = stats_prev_global_read_bucket - global_read_bucket;
seconds_elapsed = current_second ? (int)(now - current_second) : 0;
- stats_n_bytes_read += bytes_read;
- stats_n_bytes_written += bytes_written;
- if (accounting_is_enabled(options) && seconds_elapsed >= 0)
- accounting_add_bytes(bytes_read, bytes_written, seconds_elapsed);
+#ifdef USE_BUFFEREVENTS
+ {
+ uint64_t cur_read,cur_written;
+ connection_get_rate_limit_totals(&cur_read, &cur_written);
+ bytes_written = (size_t)(cur_written - stats_prev_n_written);
+ bytes_read = (size_t)(cur_read - stats_prev_n_read);
+ stats_n_bytes_read += bytes_read;
+ stats_n_bytes_written += bytes_written;
+ if (accounting_is_enabled(options) && seconds_elapsed >= 0)
+ accounting_add_bytes(bytes_read, bytes_written, seconds_elapsed);
+ stats_prev_n_written = cur_written;
+ stats_prev_n_read = cur_read;
+ }
+#else
+ bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read);
+ bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written);
+ stats_prev_n_read = stats_n_bytes_read;
+ stats_prev_n_written = stats_n_bytes_written;
+#endif
+
control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written);
control_event_stream_bandwidth_used();
- if (seconds_elapsed > 0)
- connection_bucket_refill(seconds_elapsed, now);
- stats_prev_global_read_bucket = global_read_bucket;
- stats_prev_global_write_bucket = global_write_bucket;
-
if (server_mode(options) &&
!we_are_hibernating() &&
seconds_elapsed > 0 &&
@@ -1311,7 +1571,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
(stats_n_seconds_working+seconds_elapsed) /
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
/* every 20 minutes, check and complain if necessary */
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
if (me && !check_whether_orport_reachable()) {
log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that "
"its ORPort is reachable. Please check your firewalls, ports, "
@@ -1350,6 +1610,57 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
current_second = now; /* remember which second it is, for next time */
}
+#ifndef USE_BUFFEREVENTS
+/** Timer: used to invoke refill_callback(). */
+static periodic_timer_t *refill_timer = NULL;
+
+/** Libevent callback: invoked periodically to refill token buckets
+ * and count r/w bytes. It is only used when bufferevents are disabled. */
+static void
+refill_callback(periodic_timer_t *timer, void *arg)
+{
+ static struct timeval current_millisecond;
+ struct timeval now;
+
+ size_t bytes_written;
+ size_t bytes_read;
+ int milliseconds_elapsed = 0;
+ int seconds_rolled_over = 0;
+
+ const or_options_t *options = get_options();
+
+ (void)timer;
+ (void)arg;
+
+ tor_gettimeofday(&now);
+
+ /* If this is our first time, no time has passed. */
+ if (current_millisecond.tv_sec) {
+ long mdiff = tv_mdiff(&current_millisecond, &now);
+ if (mdiff > INT_MAX)
+ mdiff = INT_MAX;
+ milliseconds_elapsed = (int)mdiff;
+ seconds_rolled_over = (int)(now.tv_sec - current_millisecond.tv_sec);
+ }
+
+ bytes_written = stats_prev_global_write_bucket - global_write_bucket;
+ bytes_read = stats_prev_global_read_bucket - global_read_bucket;
+
+ stats_n_bytes_read += bytes_read;
+ stats_n_bytes_written += bytes_written;
+ if (accounting_is_enabled(options) && milliseconds_elapsed >= 0)
+ accounting_add_bytes(bytes_read, bytes_written, seconds_rolled_over);
+
+ if (milliseconds_elapsed > 0)
+ connection_bucket_refill(milliseconds_elapsed, now.tv_sec);
+
+ stats_prev_global_read_bucket = global_read_bucket;
+ stats_prev_global_write_bucket = global_write_bucket;
+
+ current_millisecond = now; /* remember what time it is, for next time */
+}
+#endif
+
#ifndef MS_WINDOWS
/** Called when a possibly ignorable libevent error occurs; ensures that we
* don't get into an infinite loop by ignoring too many errors from
@@ -1410,7 +1721,7 @@ dns_servers_relaunch_checks(void)
static int
do_hup(void)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
#ifdef USE_DMALLOC
dmalloc_log_stats();
@@ -1502,8 +1813,10 @@ do_main_loop(void)
/* Set up our buckets */
connection_bucket_init();
+#ifndef USE_BUFFEREVENTS
stats_prev_global_read_bucket = global_read_bucket;
stats_prev_global_write_bucket = global_write_bucket;
+#endif
/* initialize the bootstrap status events to know we're starting up */
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
@@ -1546,6 +1859,22 @@ do_main_loop(void)
tor_assert(second_timer);
}
+#ifndef USE_BUFFEREVENTS
+ if (!refill_timer) {
+ struct timeval refill_interval;
+ int msecs = get_options()->TokenBucketRefillInterval;
+
+ refill_interval.tv_sec = msecs/1000;
+ refill_interval.tv_usec = (msecs%1000)*1000;
+
+ refill_timer = periodic_timer_new(tor_libevent_get_base(),
+ &refill_interval,
+ refill_callback,
+ NULL);
+ tor_assert(refill_timer);
+ }
+#endif
+
for (;;) {
if (nt_service_is_stopping())
return 0;
@@ -1634,11 +1963,13 @@ process_signal(uintptr_t sig)
case SIGUSR1:
/* prefer to log it at INFO, but make sure we always see it */
dumpstats(get_min_log_level()<LOG_INFO ? get_min_log_level() : LOG_INFO);
+ control_event_signal(sig);
break;
case SIGUSR2:
switch_logs_debug();
log_debug(LD_GENERAL,"Caught USR2, going to loglevel debug. "
"Send HUP to change back.");
+ control_event_signal(sig);
break;
case SIGHUP:
if (do_hup() < 0) {
@@ -1646,6 +1977,7 @@ process_signal(uintptr_t sig)
tor_cleanup();
exit(1);
}
+ control_event_signal(sig);
break;
#ifdef SIGCHLD
case SIGCHLD:
@@ -1667,10 +1999,18 @@ process_signal(uintptr_t sig)
}
case SIGCLEARDNSCACHE:
addressmap_clear_transient();
+ control_event_signal(sig);
break;
}
}
+/** Returns Tor's uptime. */
+long
+get_uptime(void)
+{
+ return stats_n_seconds_working;
+}
+
extern uint64_t rephist_total_alloc;
extern uint32_t rephist_total_num;
@@ -1717,13 +2057,13 @@ dumpstats(int severity)
log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)",
i,
- (int)buf_datalen(conn->inbuf),
+ (int)connection_get_inbuf_len(conn),
(int)buf_allocation(conn->inbuf),
(int)(now - conn->timestamp_lastread));
log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on outbuf "
"(len %d, last written %d secs ago)",i,
- (int)buf_datalen(conn->outbuf),
+ (int)connection_get_outbuf_len(conn),
(int)buf_allocation(conn->outbuf),
(int)(now - conn->timestamp_lastwritten));
if (conn->type == CONN_TYPE_OR) {
@@ -1895,9 +2235,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) {
@@ -1938,7 +2284,7 @@ static tor_lockfile_t *lockfile = NULL;
* return -1 if we can't get the lockfile. Return 0 on success.
*/
int
-try_locking(or_options_t *options, int err_if_locked)
+try_locking(const or_options_t *options, int err_if_locked)
{
if (lockfile)
return 0;
@@ -2017,9 +2363,11 @@ tor_free_all(int postfork)
clear_pending_onions();
circuit_free_all();
entry_guards_free_all();
+ pt_free_all();
connection_free_all();
buf_shrink_freelists(1);
memarea_clear_freelist();
+ nodelist_free_all();
microdesc_free_all();
if (!postfork) {
config_free_all();
@@ -2051,7 +2399,7 @@ tor_free_all(int postfork)
void
tor_cleanup(void)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (options->command == CMD_RUN_TOR) {
time_t now = time(NULL);
/* Remove our pid file. We don't care if there was an error when we