|
@@ -2,6 +2,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+ * main.c: Tor main loop and startup functions.
|
|
|
+ *****/
|
|
|
+
|
|
|
#include "or.h"
|
|
|
|
|
|
|
|
@@ -11,18 +15,26 @@ static int init_from_config(int argc, char **argv);
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1];
|
|
|
|
|
|
or_options_t options;
|
|
|
int global_read_bucket;
|
|
|
|
|
|
+
|
|
|
+ * (used to determine how many bytes we've read). */
|
|
|
static int stats_prev_global_read_bucket;
|
|
|
+
|
|
|
static uint64_t stats_n_bytes_read = 0;
|
|
|
+
|
|
|
static long stats_n_seconds_reading = 0;
|
|
|
|
|
|
+
|
|
|
+ * poll_array in the same position. The first nfds elements are valid. */
|
|
|
static connection_t *connection_array[MAXCONNECTIONS] =
|
|
|
{ NULL };
|
|
|
|
|
|
+
|
|
|
static struct pollfd poll_array[MAXCONNECTIONS];
|
|
|
|
|
|
static int nfds=0;
|
|
@@ -33,14 +45,14 @@ static int please_reset=0;
|
|
|
static int please_reap_children=0;
|
|
|
#endif
|
|
|
|
|
|
-int has_fetched_directory=0;
|
|
|
|
|
|
* yet about unrecognized nicknames in entrynodes, exitnodes, etc.
|
|
|
* Also, we don't try building circuits unless this is 1. */
|
|
|
+int has_fetched_directory=0;
|
|
|
|
|
|
-int has_completed_circuit=0;
|
|
|
|
|
|
* entry to inform the user that Tor is working. */
|
|
|
+int has_completed_circuit=0;
|
|
|
|
|
|
|
|
|
|
|
@@ -52,6 +64,10 @@ int has_completed_circuit=0;
|
|
|
*
|
|
|
****************************************************************************/
|
|
|
|
|
|
+
|
|
|
+ * connection's socket must be set; the connection starts out
|
|
|
+ * non-reading and non-writing.
|
|
|
+ */
|
|
|
int connection_add(connection_t *conn) {
|
|
|
tor_assert(conn);
|
|
|
tor_assert(conn->s >= 0);
|
|
@@ -112,11 +128,17 @@ int connection_remove(connection_t *conn) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * of the array. *array and *n must not be modified.
|
|
|
+ */
|
|
|
void get_connection_array(connection_t ***array, int *n) {
|
|
|
*array = connection_array;
|
|
|
*n = nfds;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * as for poll().)
|
|
|
+ */
|
|
|
void connection_watch_events(connection_t *conn, short events) {
|
|
|
|
|
|
tor_assert(conn && conn->poll_index < nfds);
|
|
@@ -124,10 +146,12 @@ void connection_watch_events(connection_t *conn, short events) {
|
|
|
poll_array[conn->poll_index].events = events;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
int connection_is_reading(connection_t *conn) {
|
|
|
return poll_array[conn->poll_index].events & POLLIN;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
void connection_stop_reading(connection_t *conn) {
|
|
|
|
|
|
tor_assert(conn && conn->poll_index < nfds);
|
|
@@ -137,6 +161,7 @@ void connection_stop_reading(connection_t *conn) {
|
|
|
poll_array[conn->poll_index].events -= POLLIN;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
void connection_start_reading(connection_t *conn) {
|
|
|
|
|
|
tor_assert(conn && conn->poll_index < nfds);
|
|
@@ -144,10 +169,12 @@ void connection_start_reading(connection_t *conn) {
|
|
|
poll_array[conn->poll_index].events |= POLLIN;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
int connection_is_writing(connection_t *conn) {
|
|
|
return poll_array[conn->poll_index].events & POLLOUT;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
void connection_stop_writing(connection_t *conn) {
|
|
|
|
|
|
tor_assert(conn && conn->poll_index < nfds);
|
|
@@ -156,6 +183,7 @@ void connection_stop_writing(connection_t *conn) {
|
|
|
poll_array[conn->poll_index].events -= POLLOUT;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
void connection_start_writing(connection_t *conn) {
|
|
|
|
|
|
tor_assert(conn && conn->poll_index < nfds);
|
|
@@ -163,6 +191,10 @@ void connection_start_writing(connection_t *conn) {
|
|
|
poll_array[conn->poll_index].events |= POLLOUT;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * checks for validity, catches numerous errors, and dispatches to
|
|
|
+ * connection_handle_read.
|
|
|
+ */
|
|
|
static void conn_read(int i) {
|
|
|
connection_t *conn = connection_array[i];
|
|
|
|
|
@@ -200,6 +232,10 @@ static void conn_read(int i) {
|
|
|
assert_all_pending_dns_resolves_ok();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * checks for validity, catches numerous errors, and dispatches to
|
|
|
+ * connection_handle_write.
|
|
|
+ */
|
|
|
static void conn_write(int i) {
|
|
|
connection_t *conn;
|
|
|
|
|
@@ -227,6 +263,15 @@ static void conn_write(int i) {
|
|
|
assert_all_pending_dns_resolves_ok();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * - If it has data that it wants to flush, try to flush it.
|
|
|
+ * - If it _still_ has data to flush, and conn->hold_open_until_flushed is
|
|
|
+ * true, then leave the connection open and return.
|
|
|
+ * - Otherwise, remove the connection from connection_array and from
|
|
|
+ * all other lists, close it, and free it.
|
|
|
+ * If we remove the connection, then call conn_closed_if_marked at the new
|
|
|
+ * connection at position i.
|
|
|
+ */
|
|
|
static void conn_close_if_marked(int i) {
|
|
|
connection_t *conn;
|
|
|
int retval;
|
|
@@ -280,8 +325,7 @@ static void conn_close_if_marked(int i) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- * down a directory */
|
|
|
+
|
|
|
void directory_has_arrived(void) {
|
|
|
|
|
|
log_fn(LOG_INFO, "A directory has arrived.");
|
|
@@ -304,11 +348,13 @@ static void run_connection_housekeeping(int i, time_t now) {
|
|
|
cell_t cell;
|
|
|
connection_t *conn = connection_array[i];
|
|
|
|
|
|
+
|
|
|
if(conn->type == CONN_TYPE_DIR &&
|
|
|
!conn->marked_for_close &&
|
|
|
conn->timestamp_lastwritten + 5*60 < now) {
|
|
|
log_fn(LOG_WARN,"Expiring wedged directory conn (purpose %d)", conn->purpose);
|
|
|
connection_mark_for_close(conn,0);
|
|
|
+
|
|
|
conn->hold_open_until_flushed = 1;
|
|
|
return;
|
|
|
}
|
|
@@ -317,6 +363,8 @@ static void run_connection_housekeeping(int i, time_t now) {
|
|
|
if(!connection_speaks_cells(conn))
|
|
|
return;
|
|
|
|
|
|
+
|
|
|
+ the connection or send a keepalive, depending. */
|
|
|
if(now >= conn->timestamp_lastwritten + options.KeepalivePeriod) {
|
|
|
if((!options.ORPort && !circuit_get_by_conn(conn)) ||
|
|
|
(!connection_state_is_open(conn))) {
|
|
@@ -450,6 +498,10 @@ static void run_scheduled_events(time_t now) {
|
|
|
conn_close_if_marked(i);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * and adjusts token buckets. Returns the number of milliseconds to use for
|
|
|
+ * the poll() timeout.
|
|
|
+ */
|
|
|
static int prepare_for_poll(void) {
|
|
|
static long current_second = 0;
|
|
|
connection_t *conn;
|
|
@@ -458,8 +510,8 @@ static int prepare_for_poll(void) {
|
|
|
|
|
|
tor_gettimeofday(&now);
|
|
|
|
|
|
-
|
|
|
- * and increment the token buckets. */
|
|
|
+
|
|
|
+ * buckets. */
|
|
|
stats_n_bytes_read += stats_prev_global_read_bucket-global_read_bucket;
|
|
|
connection_bucket_refill(&now);
|
|
|
stats_prev_global_read_bucket = global_read_bucket;
|
|
@@ -486,23 +538,30 @@ static int prepare_for_poll(void) {
|
|
|
return (1000 - (now.tv_usec / 1000));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * configuration file.
|
|
|
+ */
|
|
|
static int init_from_config(int argc, char **argv) {
|
|
|
+
|
|
|
if(getconfig(argc,argv,&options)) {
|
|
|
log_fn(LOG_ERR,"Reading config failed. For usage, try -h.");
|
|
|
return -1;
|
|
|
}
|
|
|
close_logs();
|
|
|
|
|
|
+
|
|
|
if(options.User || options.Group) {
|
|
|
if(switch_id(options.User, options.Group) != 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
if (options.RunAsDaemon) {
|
|
|
start_daemon(options.DataDirectory);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
if(!options.LogFile && !options.RunAsDaemon)
|
|
|
add_stream_log(options.loglevel, "<stdout>", stdout);
|
|
|
if(options.LogFile) {
|
|
@@ -520,21 +579,26 @@ static int init_from_config(int argc, char **argv) {
|
|
|
log_fn(LOG_DEBUG, "Successfully opened DebugLogFile '%s'.", options.DebugLogFile);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
connection_bucket_init();
|
|
|
stats_prev_global_read_bucket = global_read_bucket;
|
|
|
|
|
|
+
|
|
|
if(options.RunAsDaemon) {
|
|
|
|
|
|
finish_daemon();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ * will log a warning */
|
|
|
if(options.PidFile)
|
|
|
write_pidfile(options.PidFile);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * retry all connections, re-upload all descriptors, and so on. */
|
|
|
static int do_hup(void) {
|
|
|
char keydir[512];
|
|
|
|
|
@@ -580,6 +644,7 @@ static int do_hup(void) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static int do_main_loop(void) {
|
|
|
int i;
|
|
|
int timeout;
|
|
@@ -675,6 +740,7 @@ static int do_main_loop(void) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static void catch(int the_signal) {
|
|
|
|
|
|
#ifndef MS_WINDOWS
|