Commit 682a8050 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Comments for nearly all non-tricky files


svn:r1796
parent 6cfdc90d
...@@ -219,8 +219,9 @@ int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) { ...@@ -219,8 +219,9 @@ int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) {
tor_assert(tls); tor_assert(tls);
assert_buf_ok(buf); assert_buf_ok(buf);
log_fn(LOG_DEBUG,"start: %d on buf, %d pending, at_most %d.",(int)buf_datalen(buf), log_fn(LOG_DEBUG,"start: %d on buf, %d pending, at_most %d.",
tor_tls_get_pending_bytes(tls), at_most); (int)buf_datalen(buf), (int)tor_tls_get_pending_bytes(tls),
(int)at_most);
if (buf_ensure_capacity(buf, at_most+buf->datalen)) if (buf_ensure_capacity(buf, at_most+buf->datalen))
return TOR_TLS_ERROR; return TOR_TLS_ERROR;
...@@ -231,8 +232,9 @@ int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) { ...@@ -231,8 +232,9 @@ int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) {
if (at_most == 0) if (at_most == 0)
return 0; return 0;
log_fn(LOG_DEBUG,"before: %d on buf, %d pending, at_most %d.",(int)buf_datalen(buf), log_fn(LOG_DEBUG,"before: %d on buf, %d pending, at_most %d.",
tor_tls_get_pending_bytes(tls), at_most); (int)buf_datalen(buf), (int)tor_tls_get_pending_bytes(tls),
(int)at_most);
assert_no_tls_errors(); assert_no_tls_errors();
r = tor_tls_read(tls, buf->mem+buf->datalen, at_most); r = tor_tls_read(tls, buf->mem+buf->datalen, at_most);
......
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
/* See LICENSE for licensing information */ /* See LICENSE for licensing information */
/* $Id$ */ /* $Id$ */
/*****
* cpuworker.c: Run computation-intensive tasks (generally for crypto) in
* a separate execution context. [OR only.]
*
* Right now, we only use this for processing onionskins.
*****/
#include "or.h" #include "or.h"
extern or_options_t options; /* command-line and config-file options */ extern or_options_t options; /* command-line and config-file options */
...@@ -14,6 +21,9 @@ extern or_options_t options; /* command-line and config-file options */ ...@@ -14,6 +21,9 @@ extern or_options_t options; /* command-line and config-file options */
static int num_cpuworkers=0; static int num_cpuworkers=0;
static int num_cpuworkers_busy=0; static int num_cpuworkers_busy=0;
/* We need to spawn new cpuworkers whenever we rotate the onion keys
* on platforms where execution contexts==processes. This variable stores
* the last time we got a key rotation event.*/
static time_t last_rotation_time=0; static time_t last_rotation_time=0;
int cpuworker_main(void *data); int cpuworker_main(void *data);
...@@ -21,34 +31,45 @@ static int spawn_cpuworker(void); ...@@ -21,34 +31,45 @@ static int spawn_cpuworker(void);
static void spawn_enough_cpuworkers(void); static void spawn_enough_cpuworkers(void);
static void process_pending_task(connection_t *cpuworker); static void process_pending_task(connection_t *cpuworker);
/* Initialize the cpuworker subsystem.
*/
void cpu_init(void) { void cpu_init(void) {
last_rotation_time=time(NULL); last_rotation_time=time(NULL);
spawn_enough_cpuworkers(); spawn_enough_cpuworkers();
} }
/* Called when we're done sending a request to a cpuworker. */
int connection_cpu_finished_flushing(connection_t *conn) { int connection_cpu_finished_flushing(connection_t *conn) {
tor_assert(conn && conn->type == CONN_TYPE_CPUWORKER); tor_assert(conn && conn->type == CONN_TYPE_CPUWORKER);
connection_stop_writing(conn); connection_stop_writing(conn);
return 0; return 0;
} }
/* Pack addr,port,and circ_id; set *tag to the result. (See note on
* cpuworker_main for wire format.) */
static void tag_pack(char *tag, uint32_t addr, uint16_t port, uint16_t circ_id) { static void tag_pack(char *tag, uint32_t addr, uint16_t port, uint16_t circ_id) {
*(uint32_t *)tag = addr; *(uint32_t *)tag = addr;
*(uint16_t *)(tag+4) = port; *(uint16_t *)(tag+4) = port;
*(uint16_t *)(tag+6) = circ_id; *(uint16_t *)(tag+6) = circ_id;
} }
static void tag_unpack(char *tag, uint32_t *addr, uint16_t *port, uint16_t *circ_id) { /* Unpack 'tag' into addr, port, and circ_id.
*/
static void tag_unpack(const char *tag, uint32_t *addr, uint16_t *port, uint16_t *circ_id) {
struct in_addr in; struct in_addr in;
*addr = *(uint32_t *)tag; *addr = *(const uint32_t *)tag;
*port = *(uint16_t *)(tag+4); *port = *(const uint16_t *)(tag+4);
*circ_id = *(uint16_t *)(tag+6); *circ_id = *(const uint16_t *)(tag+6);
in.s_addr = htonl(*addr); in.s_addr = htonl(*addr);
log_fn(LOG_DEBUG,"onion was from %s:%d, circ_id %d.", inet_ntoa(in), *port, *circ_id); log_fn(LOG_DEBUG,"onion was from %s:%d, circ_id %d.", inet_ntoa(in), *port, *circ_id);
} }
/* Called when the onion key has changed and we need to spawn new
* cpuworkers. Close all currently idle cpuworkers, and mark the last
* rotation time as now.
*/
void cpuworkers_rotate(void) void cpuworkers_rotate(void)
{ {
connection_t *cpuworker; connection_t *cpuworker;
...@@ -61,6 +82,11 @@ void cpuworkers_rotate(void) ...@@ -61,6 +82,11 @@ void cpuworkers_rotate(void)
spawn_enough_cpuworkers(); spawn_enough_cpuworkers();
} }
/* Called when we get data from a cpuworker. If the answer is not complete,
* wait for a complete answer. If the cpuworker closes the connection,
* mark it as closed and spawn a new one as needed. If the answer is complete,
* process it as appropriate.
*/
int connection_cpu_process_inbuf(connection_t *conn) { int connection_cpu_process_inbuf(connection_t *conn) {
char success; char success;
unsigned char buf[LEN_ONION_RESPONSE]; unsigned char buf[LEN_ONION_RESPONSE];
...@@ -136,6 +162,20 @@ done_processing: ...@@ -136,6 +162,20 @@ done_processing:
return 0; return 0;
} }
/* Implement a cpuworker. 'data' is an fdarray as returned by socketpair.
* Read and writes from fdarray[1]. Reads requests, writes answers.
*
* Request format:
* Task type [1 byte, always ONIONSKIN_CHALLENGE_LEN]
* Opaque tag TAG_LEN
* Onionskin challenge ONIONSKIN_CHALLENGE_LEN
* Response format:
* Success/failure [1 byte, boolean.]
* Opaque tag TAG_LEN
* Onionskin challenge ONIONSKIN_REPLY_LEN
* Negotiated keys KEY_LEN*2+DIGEST_LEN*2
*/
int cpuworker_main(void *data) { int cpuworker_main(void *data) {
unsigned char question[ONIONSKIN_CHALLENGE_LEN]; unsigned char question[ONIONSKIN_CHALLENGE_LEN];
unsigned char question_type; unsigned char question_type;
...@@ -209,6 +249,8 @@ int cpuworker_main(void *data) { ...@@ -209,6 +249,8 @@ int cpuworker_main(void *data) {
return 0; /* windows wants this function to return an int */ return 0; /* windows wants this function to return an int */
} }
/* Launch a new cpuworker.
*/
static int spawn_cpuworker(void) { static int spawn_cpuworker(void) {
int fd[2]; int fd[2];
connection_t *conn; connection_t *conn;
...@@ -243,6 +285,9 @@ static int spawn_cpuworker(void) { ...@@ -243,6 +285,9 @@ static int spawn_cpuworker(void) {
return 0; /* success */ return 0; /* success */
} }
/* If we have too few or too many active cpuworkers, try to spawn new ones
* or kill idle ones.
*/
static void spawn_enough_cpuworkers(void) { static void spawn_enough_cpuworkers(void) {
int num_cpuworkers_needed = options.NumCpus; int num_cpuworkers_needed = options.NumCpus;
...@@ -260,6 +305,7 @@ static void spawn_enough_cpuworkers(void) { ...@@ -260,6 +305,7 @@ static void spawn_enough_cpuworkers(void) {
} }
} }
/* Take a pending task from the queue and assign it to 'cpuworker' */
static void process_pending_task(connection_t *cpuworker) { static void process_pending_task(connection_t *cpuworker) {
circuit_t *circ; circuit_t *circ;
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
/* See LICENSE for licensing information */ /* See LICENSE for licensing information */
/* $Id$ */ /* $Id$ */
/*****
* dns.c: Resolve hostnames in separate processes.
*****/
/* See http://elvin.dstc.com/ListArchive/elvin-dev/archive/2001/09/msg00027.html /* See http://elvin.dstc.com/ListArchive/elvin-dev/archive/2001/09/msg00027.html
* for some approaches to asynchronous dns. We will want to switch once one of * for some approaches to asynchronous dns. We will want to switch once one of
* them becomes more commonly available. * them becomes more commonly available.
...@@ -12,12 +16,19 @@ ...@@ -12,12 +16,19 @@
extern or_options_t options; /* command-line and config-file options */ extern or_options_t options; /* command-line and config-file options */
/* Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256 #define MAX_ADDRESSLEN 256
/* Maximum DNS processes to spawn. */
#define MAX_DNSWORKERS 50 #define MAX_DNSWORKERS 50
/* Minimum DNS processes to spawn. */
#define MIN_DNSWORKERS 3 #define MIN_DNSWORKERS 3
/* If more than this many processes are idle, shut down the extras. */
#define MAX_IDLE_DNSWORKERS 10 #define MAX_IDLE_DNSWORKERS 10
/* Possible outcomes from hostname lookup: permanent failure,
* transient (retryable) failure, and success */
#define DNS_RESOLVE_FAILED_TRANSIENT 1 #define DNS_RESOLVE_FAILED_TRANSIENT 1
#define DNS_RESOLVE_FAILED_PERMANENT 2 #define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3 #define DNS_RESOLVE_SUCCEEDED 3
...@@ -25,11 +36,16 @@ extern or_options_t options; /* command-line and config-file options */ ...@@ -25,11 +36,16 @@ extern or_options_t options; /* command-line and config-file options */
int num_dnsworkers=0; int num_dnsworkers=0;
int num_dnsworkers_busy=0; int num_dnsworkers_busy=0;
/* Linked list of connections waiting for a DNS answer. */
struct pending_connection_t { struct pending_connection_t {
struct connection_t *conn; struct connection_t *conn;
struct pending_connection_t *next; struct pending_connection_t *next;
}; };
/* A DNS request: possibly completed, possibly pending; cached_resolve
* structs are stored at the OR side in a splay tree, and as a linked
* list from oldest to newest.
*/
struct cached_resolve { struct cached_resolve {
SPLAY_ENTRY(cached_resolve) node; SPLAY_ENTRY(cached_resolve) node;
char address[MAX_ADDRESSLEN]; /* the hostname to be resolved */ char address[MAX_ADDRESSLEN]; /* the hostname to be resolved */
...@@ -38,7 +54,7 @@ struct cached_resolve { ...@@ -38,7 +54,7 @@ struct cached_resolve {
#define CACHE_STATE_PENDING 0 #define CACHE_STATE_PENDING 0
#define CACHE_STATE_VALID 1 #define CACHE_STATE_VALID 1
#define CACHE_STATE_FAILED 2 #define CACHE_STATE_FAILED 2
uint32_t expire; /* remove untouched items from cache after some time? */ uint32_t expire; /* remove items from cache after this time */
struct pending_connection_t *pending_connections; struct pending_connection_t *pending_connections;
struct cached_resolve *next; struct cached_resolve *next;
}; };
...@@ -51,8 +67,11 @@ int dnsworker_main(void *data); ...@@ -51,8 +67,11 @@ int dnsworker_main(void *data);
static int spawn_dnsworker(void); static int spawn_dnsworker(void);
static void spawn_enough_dnsworkers(void); static void spawn_enough_dnsworkers(void);
/* Splay tree of cached_resolve objects */
static SPLAY_HEAD(cache_tree, cached_resolve) cache_root; static SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
/* Function to compare hashed resolves on their addresses; used to
* implement splay trees. */
static int compare_cached_resolves(struct cached_resolve *a, static int compare_cached_resolves(struct cached_resolve *a,
struct cached_resolve *b) { struct cached_resolve *b) {
/* make this smarter one day? */ /* make this smarter one day? */
...@@ -62,10 +81,12 @@ static int compare_cached_resolves(struct cached_resolve *a, ...@@ -62,10 +81,12 @@ static int compare_cached_resolves(struct cached_resolve *a,
SPLAY_PROTOTYPE(cache_tree, cached_resolve, node, compare_cached_resolves); SPLAY_PROTOTYPE(cache_tree, cached_resolve, node, compare_cached_resolves);
SPLAY_GENERATE(cache_tree, cached_resolve, node, compare_cached_resolves); SPLAY_GENERATE(cache_tree, cached_resolve, node, compare_cached_resolves);
/* Initialize the DNS cache */
static void init_cache_tree(void) { static void init_cache_tree(void) {
SPLAY_INIT(&cache_root); SPLAY_INIT(&cache_root);
} }
/* Initialize the DNS subsystem; called by the OR process. */
void dns_init(void) { void dns_init(void) {
init_cache_tree(); init_cache_tree();
spawn_enough_dnsworkers(); spawn_enough_dnsworkers();
...@@ -74,6 +95,8 @@ void dns_init(void) { ...@@ -74,6 +95,8 @@ void dns_init(void) {
static struct cached_resolve *oldest_cached_resolve = NULL; /* linked list, */ static struct cached_resolve *oldest_cached_resolve = NULL; /* linked list, */
static struct cached_resolve *newest_cached_resolve = NULL; /* oldest to newest */ static struct cached_resolve *newest_cached_resolve = NULL; /* oldest to newest */
/* Remove every cached_resolve whose 'expire' time is before 'now'
* from the cache. */
static void purge_expired_resolves(uint32_t now) { static void purge_expired_resolves(uint32_t now) {
struct cached_resolve *resolve; struct cached_resolve *resolve;
...@@ -178,6 +201,9 @@ int dns_resolve(connection_t *exitconn) { ...@@ -178,6 +201,9 @@ int dns_resolve(connection_t *exitconn) {
return assign_to_dnsworker(exitconn); return assign_to_dnsworker(exitconn);
} }
/* Find or spawn a dns worker process to handle resolving
* exitconn->address; tell that dns worker to begin resolving.
*/
static int assign_to_dnsworker(connection_t *exitconn) { static int assign_to_dnsworker(connection_t *exitconn) {
connection_t *dnsconn; connection_t *dnsconn;
unsigned char len; unsigned char len;
...@@ -210,6 +236,8 @@ static int assign_to_dnsworker(connection_t *exitconn) { ...@@ -210,6 +236,8 @@ static int assign_to_dnsworker(connection_t *exitconn) {
return 0; return 0;
} }
/* Remove 'conn' from the list of connections waiting for conn->address.
*/
void connection_dns_remove(connection_t *conn) void connection_dns_remove(connection_t *conn)
{ {
struct pending_connection_t *pend, *victim; struct pending_connection_t *pend, *victim;
...@@ -251,6 +279,8 @@ void connection_dns_remove(connection_t *conn) ...@@ -251,6 +279,8 @@ void connection_dns_remove(connection_t *conn)
} }
} }
/* Log an error and abort if conn is waiting for a DNS resolve.
*/
void assert_connection_edge_not_dns_pending(connection_t *conn) { void assert_connection_edge_not_dns_pending(connection_t *conn) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
struct cached_resolve *resolve; struct cached_resolve *resolve;
...@@ -264,6 +294,8 @@ void assert_connection_edge_not_dns_pending(connection_t *conn) { ...@@ -264,6 +294,8 @@ void assert_connection_edge_not_dns_pending(connection_t *conn) {
} }
} }
/* Log an error and abort if any connection waiting for a DNS resolve is
* corrupted. */
void assert_all_pending_dns_resolves_ok(void) { void assert_all_pending_dns_resolves_ok(void) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
struct cached_resolve *resolve; struct cached_resolve *resolve;
...@@ -277,8 +309,9 @@ void assert_all_pending_dns_resolves_ok(void) { ...@@ -277,8 +309,9 @@ void assert_all_pending_dns_resolves_ok(void) {
} }
} }
/* Cancel all pending connections. Then cancel the resolve itself, /* Mark all connections waiting for 'address' for close. Then cancel
* and remove the 'struct cached_resolve' from the cache. * the resolve for 'address' itself, and remove any cached results for
* 'address' from the cache.
*/ */
void dns_cancel_pending_resolve(char *address) { void dns_cancel_pending_resolve(char *address) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
...@@ -314,6 +347,8 @@ void dns_cancel_pending_resolve(char *address) { ...@@ -314,6 +347,8 @@ void dns_cancel_pending_resolve(char *address) {
dns_purge_resolve(resolve); dns_purge_resolve(resolve);
} }
/* Remove 'resolve' from the cache.
*/
static void dns_purge_resolve(struct cached_resolve *resolve) { static void dns_purge_resolve(struct cached_resolve *resolve) {
struct cached_resolve *tmp; struct cached_resolve *tmp;
...@@ -338,6 +373,12 @@ static void dns_purge_resolve(struct cached_resolve *resolve) { ...@@ -338,6 +373,12 @@ static void dns_purge_resolve(struct cached_resolve *resolve) {
tor_free(resolve); tor_free(resolve);
} }
/* Called on the OR side when a DNS worker tells us the outcome of a DNS
* resolve: tell all pending connections about the result of the lookup, and
* cache the value. ('address' is a NUL-terminated string containing the
* address to look up; 'addr' is an IPv4 address in host order; 'outcome' is
* one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
*/
static void dns_found_answer(char *address, uint32_t addr, char outcome) { static void dns_found_answer(char *address, uint32_t addr, char outcome) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
struct cached_resolve search; struct cached_resolve search;
...@@ -356,6 +397,8 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { ...@@ -356,6 +397,8 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) {
} }
if (resolve->state != CACHE_STATE_PENDING) { if (resolve->state != CACHE_STATE_PENDING) {
/* XXXX Maybe update addr? or check addr for consistency? Or let
* VALID replace FAILED? */
log_fn(LOG_WARN, "Resolved '%s' which was already resolved; ignoring", log_fn(LOG_WARN, "Resolved '%s' which was already resolved; ignoring",
address); address);
tor_assert(resolve->pending_connections == NULL); tor_assert(resolve->pending_connections == NULL);
...@@ -401,12 +444,21 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { ...@@ -401,12 +444,21 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) {
/******************************************************************/ /******************************************************************/
/*****
* Connection between OR and dnsworker
*****/
/* Write handler: called when we've pushed a request to a dnsworker. */
int connection_dns_finished_flushing(connection_t *conn) { int connection_dns_finished_flushing(connection_t *conn) {
tor_assert(conn && conn->type == CONN_TYPE_DNSWORKER); tor_assert(conn && conn->type == CONN_TYPE_DNSWORKER);
connection_stop_writing(conn); connection_stop_writing(conn);
return 0; return 0;
} }
/* Read handler: called when we get data from a dnsworker. If the
* connection is closed, mark the dnsworker as dead. Otherwise, see
* if we have a complete answer. If so, call dns_found_answer on the
* result. If not, wait. Returns 0. */
int connection_dns_process_inbuf(connection_t *conn) { int connection_dns_process_inbuf(connection_t *conn) {
char success; char success;
uint32_t addr; uint32_t addr;
...@@ -447,6 +499,23 @@ int connection_dns_process_inbuf(connection_t *conn) { ...@@ -447,6 +499,23 @@ int connection_dns_process_inbuf(connection_t *conn) {
return 0; return 0;
} }
/* Implementation for DNS workers; this code runs in a separate
* execution context. It takes as its argument an fdarray as returned
* by socketpair(), and communicates via fdarray[1]. The protocol is
* as follows:
* The OR says:
* ADDRESSLEN [1 byte]
* ADDRESS [ADDRESSLEN bytes]
* The DNS worker does the lookup, and replies:
* OUTCOME [1 byte]
* IP [4 bytes]
*
* OUTCOME is one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
* IP is in host order.
*
* The dnsworker runs indefinitely, until its connection is closed or an error
* occurs.
*/
int dnsworker_main(void *data) { int dnsworker_main(void *data) {
char address[MAX_ADDRESSLEN]; char address[MAX_ADDRESSLEN];
unsigned char address_len; unsigned char address_len;
...@@ -498,6 +567,8 @@ int dnsworker_main(void *data) { ...@@ -498,6 +567,8 @@ int dnsworker_main(void *data) {
return 0; /* windows wants this function to return an int */ return 0; /* windows wants this function to return an int */
} }
/* Launch a new DNS worker; return 0 on success, -1 on failure.
*/
static int spawn_dnsworker(void) { static int spawn_dnsworker(void) {
int fd[2]; int fd[2];
connection_t *conn; connection_t *conn;
...@@ -532,6 +603,8 @@ static int spawn_dnsworker(void) { ...@@ -532,6 +603,8 @@ static int spawn_dnsworker(void) {
return 0; /* success */ return 0; /* success */
} }
/* If we have too many or too few DNS workers, spawn or kill some.
*/
static void spawn_enough_dnsworkers(void) { static void spawn_enough_dnsworkers(void) {
int num_dnsworkers_needed; /* aim to have 1 more than needed, int num_dnsworkers_needed; /* aim to have 1 more than needed,
* but no less than min and no more than max */ * but no less than min and no more than max */
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
/* See LICENSE for licensing information */ /* See LICENSE for licensing information */
/* $Id$ */ /* $Id$ */
/*****
* main.c: Tor main loop and startup functions.
*****/
#include "or.h" #include "or.h"
/********* PROTOTYPES **********/ /********* PROTOTYPES **********/
...@@ -11,18 +15,26 @@ static int init_from_config(int argc, char **argv); ...@@ -11,18 +15,26 @@ static int init_from_config(int argc, char **argv);
/********* START VARIABLES **********/ /********* START VARIABLES **********/
/* declared in connection.c */
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; extern char *conn_state_to_string[][_CONN_TYPE_MAX+1];
or_options_t options; /* command-line and config-file options */ or_options_t options; /* command-line and config-file options */
int global_read_bucket; /* max number of bytes I can read this second */ int global_read_bucket; /* max number of bytes I can read this second */
/* What was the read bucket before the last call to prepare_for_pool?
* (used to determine how many bytes we've read). */
static int stats_prev_global_read_bucket; static int stats_prev_global_read_bucket;
/* How many bytes have we read since we started the process? */
static uint64_t stats_n_bytes_read = 0; static uint64_t stats_n_bytes_read = 0;
/* How many seconds have we been running? */
static long stats_n_seconds_reading = 0; static long stats_n_seconds_reading = 0;
/* Array of all open connections; each element corresponds to the element of
* poll_array in the same position. The first nfds elements are valid. */
static connection_t *connection_array[MAXCONNECTIONS] = static connection_t *connection_array[MAXCONNECTIONS] =
{ NULL }; { NULL };
/* Array of pollfd objects for calls to poll(). */
static struct pollfd poll_array[MAXCONNECTIONS]; static struct pollfd poll_array[MAXCONNECTIONS];
static int nfds=0; /* number of connections currently active */ static int nfds=0; /* number of connections currently active */
...@@ -33,14 +45,14 @@ static int please_reset=0; /* whether we just got a sighup */ ...@@ -33,14 +45,14 @@ static int please_reset=0; /* whether we just got a sighup */
static int please_reap_children=0; /* whether we should waitpid for exited children */ static int please_reap_children=0; /* whether we should waitpid for exited children */
#endif /* signal stuff */ #endif /* signal stuff */
int has_fetched_directory=0;
/* we set this to 1 when we've fetched a dir, to know whether to complain /* we set this to 1 when we've fetched a dir, to know whether to complain
* yet about unrecognized nicknames in entrynodes, exitnodes, etc. * yet about unrecognized nicknames in entrynodes, exitnodes, etc.
* Also, we don't try building circuits unless this is 1. */ * Also, we don't try building circuits unless this is 1. */
int has_fetched_directory=0;
int has_completed_circuit=0;
/* we set this to 1 when we've opened a circuit, so we can print a log /* we set this to 1 when we've opened a circuit, so we can print a log
* entry to inform the user that Tor is working. */ * entry to inform the user that Tor is working. */
int has_completed_circuit=0;
/********* END VARIABLES ************/ /********* END VARIABLES ************/
...@@ -52,6 +64,10 @@ int has_completed_circuit=0; ...@@ -52,6 +64,10 @@ int has_completed_circuit=0;
* *
****************************************************************************/ ****************************************************************************/
/* Add 'conn' 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.