mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Comments for nearly all non-tricky files
svn:r1796
This commit is contained in:
parent
6cfdc90d92
commit
682a805092
@ -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) {
|
|||||||
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 @@
|
|||||||
/* 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 */
|
|||||||
|
|
||||||
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);
|
|||||||
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)
|
|||||||
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:
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
79
src/or/dns.c
79
src/or/dns.c
@ -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 @@
|
|||||||
|
|
||||||
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 */
|
|||||||
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 {
|
|||||||
#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);
|
|||||||
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,
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* 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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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 @@
|
|||||||
/* 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);
|
|||||||
|
|
||||||
/********* 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 */
|
|||||||
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;
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
int connection_add(connection_t *conn) {
|
int connection_add(connection_t *conn) {
|
||||||
tor_assert(conn);
|
tor_assert(conn);
|
||||||
tor_assert(conn->s >= 0);
|
tor_assert(conn->s >= 0);
|
||||||
@ -112,11 +128,17 @@ int connection_remove(connection_t *conn) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set *array to an array of all connections, and *n to the length
|
||||||
|
* of the array. *array and *n must not be modified.
|
||||||
|
*/
|
||||||
void get_connection_array(connection_t ***array, int *n) {
|
void get_connection_array(connection_t ***array, int *n) {
|
||||||
*array = connection_array;
|
*array = connection_array;
|
||||||
*n = nfds;
|
*n = nfds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the event mask on 'conn' to 'events'. (The form of the event mask is
|
||||||
|
* as for poll().)
|
||||||
|
*/
|
||||||
void connection_watch_events(connection_t *conn, short events) {
|
void connection_watch_events(connection_t *conn, short events) {
|
||||||
|
|
||||||
tor_assert(conn && conn->poll_index < nfds);
|
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;
|
poll_array[conn->poll_index].events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true iff the 'conn' is listening for read events. */
|
||||||
int connection_is_reading(connection_t *conn) {
|
int connection_is_reading(connection_t *conn) {
|
||||||
return poll_array[conn->poll_index].events & POLLIN;
|
return poll_array[conn->poll_index].events & POLLIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the main loop to stop notifying 'conn' of any read events. */
|
||||||
void connection_stop_reading(connection_t *conn) {
|
void connection_stop_reading(connection_t *conn) {
|
||||||
|
|
||||||
tor_assert(conn && conn->poll_index < nfds);
|
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;
|
poll_array[conn->poll_index].events -= POLLIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the main loop to start notifying 'conn' of any read events. */
|
||||||
void connection_start_reading(connection_t *conn) {
|
void connection_start_reading(connection_t *conn) {
|
||||||
|
|
||||||
tor_assert(conn && conn->poll_index < nfds);
|
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;
|
poll_array[conn->poll_index].events |= POLLIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true iff the 'conn' is listening for write events. */
|
||||||
int connection_is_writing(connection_t *conn) {
|
int connection_is_writing(connection_t *conn) {
|
||||||
return poll_array[conn->poll_index].events & POLLOUT;
|
return poll_array[conn->poll_index].events & POLLOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the main loop to stop notifying 'conn' of any write events. */
|
||||||
void connection_stop_writing(connection_t *conn) {
|
void connection_stop_writing(connection_t *conn) {
|
||||||
|
|
||||||
tor_assert(conn && conn->poll_index < nfds);
|
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;
|
poll_array[conn->poll_index].events -= POLLOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the main loop to start notifying 'conn' of any write events. */
|
||||||
void connection_start_writing(connection_t *conn) {
|
void connection_start_writing(connection_t *conn) {
|
||||||
|
|
||||||
tor_assert(conn && conn->poll_index < nfds);
|
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;
|
poll_array[conn->poll_index].events |= POLLOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called when the connection at connection_array[i] has a read event:
|
||||||
|
* checks for validity, catches numerous errors, and dispatches to
|
||||||
|
* connection_handle_read.
|
||||||
|
*/
|
||||||
static void conn_read(int i) {
|
static void conn_read(int i) {
|
||||||
connection_t *conn = connection_array[i];
|
connection_t *conn = connection_array[i];
|
||||||
|
|
||||||
@ -200,6 +232,10 @@ static void conn_read(int i) {
|
|||||||
assert_all_pending_dns_resolves_ok();
|
assert_all_pending_dns_resolves_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called when the connection at connection_array[i] has a write event:
|
||||||
|
* checks for validity, catches numerous errors, and dispatches to
|
||||||
|
* connection_handle_write.
|
||||||
|
*/
|
||||||
static void conn_write(int i) {
|
static void conn_write(int i) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
|
||||||
@ -227,6 +263,15 @@ static void conn_write(int i) {
|
|||||||
assert_all_pending_dns_resolves_ok();
|
assert_all_pending_dns_resolves_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the connection at connection_array[i] is marked for close, then:
|
||||||
|
* - 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) {
|
static void conn_close_if_marked(int i) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
int retval;
|
int retval;
|
||||||
@ -280,8 +325,7 @@ static void conn_close_if_marked(int i) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called whenever we successfully pull
|
/* This function is called whenever we successfully pull down a directory */
|
||||||
* down a directory */
|
|
||||||
void directory_has_arrived(void) {
|
void directory_has_arrived(void) {
|
||||||
|
|
||||||
log_fn(LOG_INFO, "A directory has arrived.");
|
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;
|
cell_t cell;
|
||||||
connection_t *conn = connection_array[i];
|
connection_t *conn = connection_array[i];
|
||||||
|
|
||||||
|
/* Expire any directory connections that haven't sent anything for 5 min */
|
||||||
if(conn->type == CONN_TYPE_DIR &&
|
if(conn->type == CONN_TYPE_DIR &&
|
||||||
!conn->marked_for_close &&
|
!conn->marked_for_close &&
|
||||||
conn->timestamp_lastwritten + 5*60 < now) {
|
conn->timestamp_lastwritten + 5*60 < now) {
|
||||||
log_fn(LOG_WARN,"Expiring wedged directory conn (purpose %d)", conn->purpose);
|
log_fn(LOG_WARN,"Expiring wedged directory conn (purpose %d)", conn->purpose);
|
||||||
connection_mark_for_close(conn,0);
|
connection_mark_for_close(conn,0);
|
||||||
|
/* XXXX Does this next part make sense, really? */
|
||||||
conn->hold_open_until_flushed = 1; /* give it a last chance */
|
conn->hold_open_until_flushed = 1; /* give it a last chance */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -317,6 +363,8 @@ static void run_connection_housekeeping(int i, time_t now) {
|
|||||||
if(!connection_speaks_cells(conn))
|
if(!connection_speaks_cells(conn))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* If we haven't written to an OR connection for a while, then either nuke
|
||||||
|
the connection or send a keepalive, depending. */
|
||||||
if(now >= conn->timestamp_lastwritten + options.KeepalivePeriod) {
|
if(now >= conn->timestamp_lastwritten + options.KeepalivePeriod) {
|
||||||
if((!options.ORPort && !circuit_get_by_conn(conn)) ||
|
if((!options.ORPort && !circuit_get_by_conn(conn)) ||
|
||||||
(!connection_state_is_open(conn))) {
|
(!connection_state_is_open(conn))) {
|
||||||
@ -450,6 +498,10 @@ static void run_scheduled_events(time_t now) {
|
|||||||
conn_close_if_marked(i);
|
conn_close_if_marked(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called every time we're about to call tor_poll. Increments statistics,
|
||||||
|
* and adjusts token buckets. Returns the number of milliseconds to use for
|
||||||
|
* the poll() timeout.
|
||||||
|
*/
|
||||||
static int prepare_for_poll(void) {
|
static int prepare_for_poll(void) {
|
||||||
static long current_second = 0; /* from previous calls to gettimeofday */
|
static long current_second = 0; /* from previous calls to gettimeofday */
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
@ -458,8 +510,8 @@ static int prepare_for_poll(void) {
|
|||||||
|
|
||||||
tor_gettimeofday(&now);
|
tor_gettimeofday(&now);
|
||||||
|
|
||||||
/* Check how much bandwidth we've consumed,
|
/* Check how much bandwidth we've consumed, and increment the token
|
||||||
* and increment the token buckets. */
|
* buckets. */
|
||||||
stats_n_bytes_read += stats_prev_global_read_bucket-global_read_bucket;
|
stats_n_bytes_read += stats_prev_global_read_bucket-global_read_bucket;
|
||||||
connection_bucket_refill(&now);
|
connection_bucket_refill(&now);
|
||||||
stats_prev_global_read_bucket = global_read_bucket;
|
stats_prev_global_read_bucket = global_read_bucket;
|
||||||
@ -486,23 +538,30 @@ static int prepare_for_poll(void) {
|
|||||||
return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
|
return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Configure the Tor process from the command line arguments and from the
|
||||||
|
* configuration file.
|
||||||
|
*/
|
||||||
static int init_from_config(int argc, char **argv) {
|
static int init_from_config(int argc, char **argv) {
|
||||||
|
/* read the configuration file. */
|
||||||
if(getconfig(argc,argv,&options)) {
|
if(getconfig(argc,argv,&options)) {
|
||||||
log_fn(LOG_ERR,"Reading config failed. For usage, try -h.");
|
log_fn(LOG_ERR,"Reading config failed. For usage, try -h.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close_logs(); /* we'll close, then open with correct loglevel if necessary */
|
close_logs(); /* we'll close, then open with correct loglevel if necessary */
|
||||||
|
|
||||||
|
/* Setuid/setgid as appropriate */
|
||||||
if(options.User || options.Group) {
|
if(options.User || options.Group) {
|
||||||
if(switch_id(options.User, options.Group) != 0) {
|
if(switch_id(options.User, options.Group) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start backgrounding the process, if requested. */
|
||||||
if (options.RunAsDaemon) {
|
if (options.RunAsDaemon) {
|
||||||
start_daemon(options.DataDirectory);
|
start_daemon(options.DataDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Configure the log(s) */
|
||||||
if(!options.LogFile && !options.RunAsDaemon)
|
if(!options.LogFile && !options.RunAsDaemon)
|
||||||
add_stream_log(options.loglevel, "<stdout>", stdout);
|
add_stream_log(options.loglevel, "<stdout>", stdout);
|
||||||
if(options.LogFile) {
|
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);
|
log_fn(LOG_DEBUG, "Successfully opened DebugLogFile '%s'.", options.DebugLogFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up our buckets */
|
||||||
connection_bucket_init();
|
connection_bucket_init();
|
||||||
stats_prev_global_read_bucket = global_read_bucket;
|
stats_prev_global_read_bucket = global_read_bucket;
|
||||||
|
|
||||||
|
/* Finish backgrounding the process */
|
||||||
if(options.RunAsDaemon) {
|
if(options.RunAsDaemon) {
|
||||||
/* XXXX Can we delay this any more? */
|
/* XXXX Can we delay this any more? */
|
||||||
finish_daemon();
|
finish_daemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write our pid to the pid file, if we do not have write permissions we will log a warning */
|
/* Write our pid to the pid file. if we do not have write permissions we
|
||||||
|
* will log a warning */
|
||||||
if(options.PidFile)
|
if(options.PidFile)
|
||||||
write_pidfile(options.PidFile);
|
write_pidfile(options.PidFile);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called when we get a SIGHUP: reload configuration files and keys,
|
||||||
|
* retry all connections, re-upload all descriptors, and so on. */
|
||||||
static int do_hup(void) {
|
static int do_hup(void) {
|
||||||
char keydir[512];
|
char keydir[512];
|
||||||
|
|
||||||
@ -580,6 +644,7 @@ static int do_hup(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tor main loop. */
|
||||||
static int do_main_loop(void) {
|
static int do_main_loop(void) {
|
||||||
int i;
|
int i;
|
||||||
int timeout;
|
int timeout;
|
||||||
@ -675,6 +740,7 @@ static int do_main_loop(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unix signal handler. */
|
||||||
static void catch(int the_signal) {
|
static void catch(int the_signal) {
|
||||||
|
|
||||||
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
||||||
|
12
src/or/or.h
12
src/or/or.h
@ -1046,8 +1046,8 @@ void rep_hist_dump_stats(time_t now, int severity);
|
|||||||
void rend_client_introcirc_is_open(circuit_t *circ);
|
void rend_client_introcirc_is_open(circuit_t *circ);
|
||||||
void rend_client_rendcirc_is_open(circuit_t *circ);
|
void rend_client_rendcirc_is_open(circuit_t *circ);
|
||||||
int rend_client_introduction_acked(circuit_t *circ, const char *request, int request_len);
|
int rend_client_introduction_acked(circuit_t *circ, const char *request, int request_len);
|
||||||
void rend_client_refetch_renddesc(char *query);
|
void rend_client_refetch_renddesc(const char *query);
|
||||||
int rend_client_remove_intro_point(char *failed_intro, char *query);
|
int rend_client_remove_intro_point(char *failed_intro, const char *query);
|
||||||
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_len);
|
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_len);
|
||||||
int rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len);
|
int rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len);
|
||||||
void rend_client_desc_fetched(char *query, int success);
|
void rend_client_desc_fetched(char *query, int success);
|
||||||
@ -1088,10 +1088,10 @@ typedef struct rend_cache_entry_t {
|
|||||||
|
|
||||||
void rend_cache_init(void);
|
void rend_cache_init(void);
|
||||||
void rend_cache_clean(void);
|
void rend_cache_clean(void);
|
||||||
int rend_valid_service_id(char *query);
|
int rend_valid_service_id(const char *query);
|
||||||
int rend_cache_lookup_desc(char *query, const char **desc, int *desc_len);
|
int rend_cache_lookup_desc(const char *query, const char **desc, int *desc_len);
|
||||||
int rend_cache_lookup_entry(char *query, rend_cache_entry_t **entry_out);
|
int rend_cache_lookup_entry(const char *query, rend_cache_entry_t **entry_out);
|
||||||
int rend_cache_store(char *desc, int desc_len);
|
int rend_cache_store(const char *desc, int desc_len);
|
||||||
|
|
||||||
/********************************* rendservice.c ***************************/
|
/********************************* rendservice.c ***************************/
|
||||||
|
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* rendclient.c: Client code to access location-hiddenn services.
|
||||||
|
*****/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
/* send the introduce cell */
|
/* Called when we've established a circuit to an introduction point:
|
||||||
|
* send the introduction request. */
|
||||||
void
|
void
|
||||||
rend_client_introcirc_is_open(circuit_t *circ)
|
rend_client_introcirc_is_open(circuit_t *circ)
|
||||||
{
|
{
|
||||||
@ -15,8 +20,8 @@ rend_client_introcirc_is_open(circuit_t *circ)
|
|||||||
connection_ap_attach_pending();
|
connection_ap_attach_pending();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send the establish-rendezvous cell. if it fails, mark
|
/* Send the establish-rendezvous cell along a rendezvous circuit. if
|
||||||
* the circ for close and return -1. else return 0.
|
* it fails, mark the circ for close and return -1. else return 0.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rend_client_send_establish_rendezvous(circuit_t *circ)
|
rend_client_send_establish_rendezvous(circuit_t *circ)
|
||||||
@ -124,7 +129,8 @@ err:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send the rendezvous cell */
|
/* Called when a rendezvous circuit is open; sends a establish
|
||||||
|
* rendezvous circuit as appropriate. */
|
||||||
void
|
void
|
||||||
rend_client_rendcirc_is_open(circuit_t *circ)
|
rend_client_rendcirc_is_open(circuit_t *circ)
|
||||||
{
|
{
|
||||||
@ -209,8 +215,13 @@ rend_client_introduction_acked(circuit_t *circ,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If we are not currently fetching a rendezvous service descriptor
|
||||||
|
* for the service ID 'query', start a directory connection to fetch a
|
||||||
|
* new one.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rend_client_refetch_renddesc(char *query)
|
rend_client_refetch_renddesc(const char *query)
|
||||||
{
|
{
|
||||||
if(connection_get_by_type_rendquery(CONN_TYPE_DIR, query)) {
|
if(connection_get_by_type_rendquery(CONN_TYPE_DIR, query)) {
|
||||||
log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", query);
|
log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", query);
|
||||||
@ -229,7 +240,7 @@ rend_client_refetch_renddesc(char *query)
|
|||||||
* unrecognized, 1 if recognized and some intro points remain.
|
* unrecognized, 1 if recognized and some intro points remain.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rend_client_remove_intro_point(char *failed_intro, char *query)
|
rend_client_remove_intro_point(char *failed_intro, const char *query)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
rend_cache_entry_t *ent;
|
rend_cache_entry_t *ent;
|
||||||
@ -280,7 +291,7 @@ rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_l
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bob sent us a rendezvous cell, join the circs. */
|
/* Bob sent us a rendezvous cell; join the circuits. */
|
||||||
int
|
int
|
||||||
rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len)
|
rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len)
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* rendcommon.c: Rendezvous implementation: shared code between
|
||||||
|
* introducers, services, clients, and rendezvous points.
|
||||||
|
*****/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
/* Free the storage held by 'desc'.
|
/* Free the storage held by the service descriptor 'desc'.
|
||||||
*/
|
*/
|
||||||
void rend_service_descriptor_free(rend_service_descriptor_t *desc)
|
void rend_service_descriptor_free(rend_service_descriptor_t *desc)
|
||||||
{
|
{
|
||||||
@ -66,8 +71,10 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* malloc a service_descriptor_t and return it.
|
/* Parse a service descriptor at 'str' (len bytes). On success,
|
||||||
* return NULL if invalid descriptor or error */
|
* return a newly alloced service_descriptor_t. On failure, return
|
||||||
|
* NULL.
|
||||||
|
*/
|
||||||
rend_service_descriptor_t *rend_parse_service_descriptor(
|
rend_service_descriptor_t *rend_parse_service_descriptor(
|
||||||
const char *str, int len)
|
const char *str, int len)
|
||||||
{
|
{
|
||||||
@ -121,8 +128,9 @@ rend_service_descriptor_t *rend_parse_service_descriptor(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets out to the first 10 bytes of the digest of 'pk', base32 encoded.
|
/* Sets out to the first 10 bytes of the digest of 'pk', base32
|
||||||
* NUL-terminates out.
|
* encoded. NUL-terminates out. (We use this string to identify
|
||||||
|
* services in directory requests and .onion URLs.)
|
||||||
*/
|
*/
|
||||||
int rend_get_service_id(crypto_pk_env_t *pk, char *out)
|
int rend_get_service_id(crypto_pk_env_t *pk, char *out)
|
||||||
{
|
{
|
||||||
@ -139,6 +147,8 @@ int rend_get_service_id(crypto_pk_env_t *pk, char *out)
|
|||||||
#define REND_CACHE_MAX_AGE (24*60*60)
|
#define REND_CACHE_MAX_AGE (24*60*60)
|
||||||
#define REND_CACHE_MAX_SKEW (90*60)
|
#define REND_CACHE_MAX_SKEW (90*60)
|
||||||
|
|
||||||
|
/* Map from service id (as generated by rend_get_service_id) to
|
||||||
|
* rend_cache_entry_t. */
|
||||||
static strmap_t *rend_cache = NULL;
|
static strmap_t *rend_cache = NULL;
|
||||||
|
|
||||||
/* Initializes the service descriptor cache.
|
/* Initializes the service descriptor cache.
|
||||||
@ -172,8 +182,9 @@ void rend_cache_clean(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return 1 if query is a valid service id, else return 0. */
|
/* Return true iff 'query' is a syntactically valid service ID (as
|
||||||
int rend_valid_service_id(char *query) {
|
* generated by rend_get_service_id). */
|
||||||
|
int rend_valid_service_id(const char *query) {
|
||||||
if(strlen(query) != REND_SERVICE_ID_LEN)
|
if(strlen(query) != REND_SERVICE_ID_LEN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -183,7 +194,10 @@ int rend_valid_service_id(char *query) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rend_cache_lookup_entry(char *query, rend_cache_entry_t **e)
|
/* If we have a cached rend_cache_entry_t for the service ID 'query', set
|
||||||
|
* *e to that entry and return 1. Else return 0.
|
||||||
|
*/
|
||||||
|
int rend_cache_lookup_entry(const char *query, rend_cache_entry_t **e)
|
||||||
{
|
{
|
||||||
tor_assert(rend_cache);
|
tor_assert(rend_cache);
|
||||||
if (!rend_valid_service_id(query))
|
if (!rend_valid_service_id(query))
|
||||||
@ -199,8 +213,10 @@ int rend_cache_lookup_entry(char *query, rend_cache_entry_t **e)
|
|||||||
* If it is found, point *desc to it, and write its length into
|
* If it is found, point *desc to it, and write its length into
|
||||||
* *desc_len, and return 1.
|
* *desc_len, and return 1.
|
||||||
* If it is not found, return 0.
|
* If it is not found, return 0.
|
||||||
|
* Note: calls to rend_cache_clean or rend_cache_store may invalidate
|
||||||
|
* *desc.
|
||||||
*/
|
*/
|
||||||
int rend_cache_lookup_desc(char *query, const char **desc, int *desc_len)
|
int rend_cache_lookup_desc(const char *query, const char **desc, int *desc_len)
|
||||||
{
|
{
|
||||||
rend_cache_entry_t *e;
|
rend_cache_entry_t *e;
|
||||||
int r;
|
int r;
|
||||||
@ -211,12 +227,12 @@ int rend_cache_lookup_desc(char *query, const char **desc, int *desc_len)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse *desc, calculate its service id, and store it in the cache.
|
||||||
/* Calculate desc's service id, and store it.
|
* If we have a newer descriptor with the same ID, ignore this one.
|
||||||
* Return -1 if it's malformed or otherwise rejected and you
|
* If we have an older descriptor with the same ID, replace it.
|
||||||
* want the caller to fail, else return 0.
|
* Returns -1 if it's malformed or otherwise rejected, else return 0.
|
||||||
*/
|
*/
|
||||||
int rend_cache_store(char *desc, int desc_len)
|
int rend_cache_store(const char *desc, int desc_len)
|
||||||
{
|
{
|
||||||
rend_cache_entry_t *e;
|
rend_cache_entry_t *e;
|
||||||
rend_service_descriptor_t *parsed;
|
rend_service_descriptor_t *parsed;
|
||||||
@ -273,7 +289,8 @@ int rend_cache_store(char *desc, int desc_len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dispatch on rendezvous relay command. */
|
/* Called when we get a rendezvous-related relay cell on circuit
|
||||||
|
* *circ. Dispatch on rendezvous relay command. */
|
||||||
void rend_process_relay_cell(circuit_t *circ, int command, int length,
|
void rend_process_relay_cell(circuit_t *circ, int command, int length,
|
||||||
const char *payload)
|
const char *payload)
|
||||||
{
|
{
|
||||||
|
@ -2,10 +2,14 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* rendmid.c: Implement introductions points and rendezvous points.
|
||||||
|
*****/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
/* Respond to an ESTABLISH_INTRO cell by setting the circuit's purpose and
|
/* Respond to an ESTABLISH_INTRO cell by checking the signed data and
|
||||||
* service pk digest..
|
* setting the circuit's purpose and service pk digest.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rend_mid_establish_intro(circuit_t *circ, const char *request, int request_len)
|
rend_mid_establish_intro(circuit_t *circ, const char *request, int request_len)
|
||||||
@ -219,8 +223,9 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request, int request_
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process a RENDEZVOUS1 cell by looking up the correct rendezvous circuit by its
|
/* Process a RENDEZVOUS1 cell by looking up the correct rendezvous
|
||||||
* relaying the cell's body in a RENDEZVOUS2 cell, and connecting the two circuits.
|
* circuit by its relaying the cell's body in a RENDEZVOUS2 cell, and
|
||||||
|
* connecting the two circuits.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rend_mid_rendezvous(circuit_t *circ, const char *request, int request_len)
|
rend_mid_rendezvous(circuit_t *circ, const char *request, int request_len)
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
/* This module implements the hidden-service side of rendezvous functionality.
|
/*****
|
||||||
*/
|
* rendservice.c: The hidden-service side of rendezvous functionality.
|
||||||
|
*****/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
@ -27,14 +28,15 @@ typedef struct rend_service_port_config_t {
|
|||||||
typedef struct rend_service_t {
|
typedef struct rend_service_t {
|
||||||
/* Fields specified in config file */
|
/* Fields specified in config file */
|
||||||
char *directory; /* where in the filesystem it stores it */
|
char *directory; /* where in the filesystem it stores it */
|
||||||
smartlist_t *ports;
|
smartlist_t *ports; /* List of rend_service_port_config_t */
|
||||||
char *intro_prefer_nodes;
|
char *intro_prefer_nodes; /* comma-separated list of nicknames */
|
||||||
char *intro_exclude_nodes;
|
char *intro_exclude_nodes; /* comma-separated list of nicknames */
|
||||||
/* Other fields */
|
/* Other fields */
|
||||||
crypto_pk_env_t *private_key;
|
crypto_pk_env_t *private_key;
|
||||||
char service_id[REND_SERVICE_ID_LEN+1];
|
char service_id[REND_SERVICE_ID_LEN+1];
|
||||||
char pk_digest[DIGEST_LEN];
|
char pk_digest[DIGEST_LEN];
|
||||||
smartlist_t *intro_nodes; /* list of nicknames for intro points we _want_ */
|
smartlist_t *intro_nodes; /* list of nicknames for intro points we have,
|
||||||
|
* or are trying to establish. */
|
||||||
rend_service_descriptor_t *desc;
|
rend_service_descriptor_t *desc;
|
||||||
int desc_is_dirty;
|
int desc_is_dirty;
|
||||||
} rend_service_t;
|
} rend_service_t;
|
||||||
@ -457,7 +459,11 @@ rend_service_introduce(circuit_t *circuit, const char *request, int request_len)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define MAX_REND_FAILURES 3
|
#define MAX_REND_FAILURES 3
|
||||||
|
/* Called when we fail building a rendezvous circuit at some point other
|
||||||
|
* than the last hop: launches a new circuit to the same rendezvous point.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rend_service_relaunch_rendezvous(circuit_t *oldcirc)
|
rend_service_relaunch_rendezvous(circuit_t *oldcirc)
|
||||||
{
|
{
|
||||||
@ -495,10 +501,11 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc)
|
|||||||
memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN);
|
memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Launch a circuit to serve as an introduction point.
|
/* Launch a circuit to serve as an introduction point for the service
|
||||||
|
* 'service' at the introduction point 'nickname'
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
rend_service_launch_establish_intro(rend_service_t *service, char *nickname)
|
rend_service_launch_establish_intro(rend_service_t *service, const char *nickname)
|
||||||
{
|
{
|
||||||
circuit_t *launched;
|
circuit_t *launched;
|
||||||
|
|
||||||
@ -578,7 +585,9 @@ rend_service_intro_is_ready(circuit_t *circuit)
|
|||||||
circuit_mark_for_close(circuit);
|
circuit_mark_for_close(circuit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle an INTRO_ESTABLISHED cell. */
|
/* Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
|
||||||
|
* live introduction point, and note that the service descriptor is
|
||||||
|
* now out-of-date.*/
|
||||||
int
|
int
|
||||||
rend_service_intro_established(circuit_t *circuit, const char *request, int request_len)
|
rend_service_intro_established(circuit_t *circuit, const char *request, int request_len)
|
||||||
{
|
{
|
||||||
@ -603,7 +612,7 @@ rend_service_intro_established(circuit_t *circuit, const char *request, int requ
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called once a circuit to a rendezvous point is ready: sends a
|
/* Called once a circuit to a rendezvous point is established: sends a
|
||||||
* RELAY_COMMAND_RENDEZVOUS1 cell.
|
* RELAY_COMMAND_RENDEZVOUS1 cell.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -711,6 +720,10 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the directory servers don't have an up-to-date descriptor for
|
||||||
|
* 'service', Encode and sign the service descriptor for 'service',
|
||||||
|
* and upload it to all the dirservers.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
upload_service_descriptor(rend_service_t *service)
|
upload_service_descriptor(rend_service_t *service)
|
||||||
{
|
{
|
||||||
@ -827,6 +840,11 @@ void rend_services_introduce(void) {
|
|||||||
smartlist_free(exclude_routers);
|
smartlist_free(exclude_routers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Regenerate and upload rendezvous service descriptors for all
|
||||||
|
* services. If 'force' is false, skip services where we've already
|
||||||
|
* uploaded an up-to-date copy; if 'force' is true, regenerate and
|
||||||
|
* upload everything.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rend_services_upload(int force)
|
rend_services_upload(int force)
|
||||||
{
|
{
|
||||||
@ -842,6 +860,9 @@ rend_services_upload(int force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Log the status of introduction points for all rendezvous services
|
||||||
|
* at log severity 'serverity'.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rend_service_dump_stats(int severity)
|
rend_service_dump_stats(int severity)
|
||||||
{
|
{
|
||||||
@ -872,9 +893,10 @@ rend_service_dump_stats(int severity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a beginning rendezvous stream. Look up conn->port,
|
/* 'conn' is a rendezvous exit stream. Look up the hidden service for
|
||||||
* and assign the actual conn->addr and conn->port. Return -1
|
* 'circ', and look up the port and address based on conn->port.
|
||||||
* if failure, or 0 for success.
|
* Assign the actual conn->addr and conn->port. Return -1 if failure,
|
||||||
|
* or 0 for success.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
|
rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
|
||||||
|
@ -2,26 +2,47 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* rephist.c: Basic history functionality for reputation module.
|
||||||
|
*****/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
|
|
||||||
|
/* History of an or->or link. */
|
||||||
typedef struct link_history_t {
|
typedef struct link_history_t {
|
||||||
|
/* When did we start tracking this list? */
|
||||||
time_t since;
|
time_t since;
|
||||||
|
/* How many times did extending from OR1 to OR2 succeeed? */
|
||||||
unsigned long n_extend_ok;
|
unsigned long n_extend_ok;
|
||||||
|
/* How many times did extending from OR1 to OR2 fail? */
|
||||||
unsigned long n_extend_fail;
|
unsigned long n_extend_fail;
|
||||||
} link_history_t;
|
} link_history_t;
|
||||||
|
|
||||||
|
/* History of an OR. */
|
||||||
typedef struct or_history_t {
|
typedef struct or_history_t {
|
||||||
|
/* When did we start tracking this OR? */
|
||||||
time_t since;
|
time_t since;
|
||||||
|
/* How many times did we successfully connect? */
|
||||||
unsigned long n_conn_ok;
|
unsigned long n_conn_ok;
|
||||||
|
/*How many times did we try to connect and fail?*/
|
||||||
unsigned long n_conn_fail;
|
unsigned long n_conn_fail;
|
||||||
|
/* How many seconds have we been connected to this OR before
|
||||||
|
* 'up_since'? */
|
||||||
unsigned long uptime;
|
unsigned long uptime;
|
||||||
|
/* How many seconds have we been unable to connect to this OR before
|
||||||
|
* 'down_since'? */
|
||||||
unsigned long downtime;
|
unsigned long downtime;
|
||||||
|
/* If nonzero, we have been connected since this time. */
|
||||||
time_t up_since;
|
time_t up_since;
|
||||||
|
/* If nonzero, we have been unable to connect since this time. */
|
||||||
time_t down_since;
|
time_t down_since;
|
||||||
|
/* Map from lowercased OR2 name to a link_history_t for the link
|
||||||
|
* from this OR to OR2. */
|
||||||
strmap_t *link_history_map;
|
strmap_t *link_history_map;
|
||||||
} or_history_t;
|
} or_history_t;
|
||||||
|
|
||||||
static strmap_t *history_map;
|
/* Map from lowercased OR nickname to or_history_t. */
|
||||||
|
static strmap_t *history_map = NULL;
|
||||||
|
|
||||||
/* Return the or_history_t for the named OR, creating it if necessary.
|
/* Return the or_history_t for the named OR, creating it if necessary.
|
||||||
*/
|
*/
|
||||||
@ -57,7 +78,7 @@ static link_history_t *get_link_history(const char *from_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update an or_history_t object so that its uptime/downtime count is
|
/* Update an or_history_t object so that its uptime/downtime count is
|
||||||
* up-to-date.
|
* up-to-date as of 'when'.
|
||||||
*/
|
*/
|
||||||
static void update_or_history(or_history_t *hist, time_t when)
|
static void update_or_history(or_history_t *hist, time_t when)
|
||||||
{
|
{
|
||||||
@ -227,8 +248,6 @@ void rep_hist_dump_stats(time_t now, int severity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
mode:c
|
mode:c
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* tor_main.c: Entry point for tor binary. (We keep main() in a
|
||||||
|
* separate file so that our unit tests can use functions from main.c)
|
||||||
|
*****/
|
||||||
|
|
||||||
int tor_main(int argc, char *argv[]);
|
int tor_main(int argc, char *argv[]);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
Loading…
Reference in New Issue
Block a user