📄 main.c
字号:
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char main_c_id[] =
"$Id$";
/**
* \file main.c
* \brief Toplevel module. Handles signals, multiplexes between
* connections, implements main loop, and drives scheduled events.
**/
#define MAIN_PRIVATE
#include "or.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif
#include "memarea.h"
void evdns_shutdown(int);
/********* PROTOTYPES **********/
static void dumpmemusage(int severity);
static void dumpstats(int severity); /* log stats */
static void conn_read_callback(int fd, short event, void *_conn);
static void conn_write_callback(int fd, short event, void *_conn);
static void signal_callback(int fd, short events, void *arg);
static void second_elapsed_callback(int fd, short event, void *args);
static int conn_close_if_marked(int i);
static void connection_start_reading_from_linked_conn(connection_t *conn);
static int connection_should_read_from_linked_conn(connection_t *conn);
/********* START VARIABLES **********/
int global_read_bucket; /**< Max number of bytes I can read this second. */
int global_write_bucket; /**< Max number of bytes I can write this second. */
/** Max number of relayed (bandwidth class 1) bytes I can read this second. */
int global_relayed_read_bucket;
/** Max number of relayed (bandwidth class 1) bytes I can write this second. */
int global_relayed_write_bucket;
/** What was the read bucket before the last call to prepare_for_pool?
* (used to determine how many bytes we've read). */
static int stats_prev_global_read_bucket;
/** What was the write bucket before the last call to prepare_for_pool?
* (used to determine how many bytes we've written). */
static int stats_prev_global_write_bucket;
/* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/
/** How many bytes have we read/written since we started the process? */
static uint64_t stats_n_bytes_read = 0;
static uint64_t stats_n_bytes_written = 0;
/** What time did this process start up? */
time_t time_of_process_start = 0;
/** How many seconds have we been running? */
long stats_n_seconds_working = 0;
/** When do we next launch DNS wildcarding checks? */
static time_t time_to_check_for_correct_dns = 0;
/** How often will we honor SIGNEWNYM requests? */
#define MAX_SIGNEWNYM_RATE 10
/** When did we last process a SIGNEWNYM request? */
static time_t time_of_last_signewnym = 0;
/** Is there a signewnym request we're currently waiting to handle? */
static int signewnym_is_pending = 0;
/** Smartlist of all open connections. */
static smartlist_t *connection_array = NULL;
/** List of connections that have been marked for close and need to be freed
* and removed from connection_array. */
static smartlist_t *closeable_connection_lst = NULL;
/** List of linked connections that are currently reading data into their
* inbuf from their partner's outbuf. */
static smartlist_t *active_linked_connection_lst = NULL;
/** Flag: Set to true iff we entered the current libevent main loop via
* <b>loop_once</b>. If so, there's no need to trigger a loopexit in order
* to handle linked connections. */
static int called_loop_once = 0;
/** 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. */
int has_completed_circuit=0;
/** How often do we check for router descriptors that we should download
* when we have too little directory info? */
#define GREEDY_DESCRIPTOR_RETRY_INTERVAL (10)
/** How often do we check for router descriptors that we should download
* when we have enough directory info? */
#define LAZY_DESCRIPTOR_RETRY_INTERVAL (60)
/** How often do we 'forgive' undownloadable router descriptors and attempt
* to download them again? */
#define DESCRIPTOR_FAILURE_RESET_INTERVAL (60*60)
/** How long do we let a directory connection stall before expiring it? */
#define DIR_CONN_MAX_STALL (5*60)
/** How old do we let a connection to an OR get before deciding it's
* obsolete? */
#define TIME_BEFORE_OR_CONN_IS_OBSOLETE (60*60*24*7)
/** How long do we let OR connections handshake before we decide that
* they are obsolete? */
#define TLS_HANDSHAKE_TIMEOUT (60)
/********* END VARIABLES ************/
/****************************************************************************
*
* This section contains accessors and other methods on the connection_array
* variables (which are global within this file and unavailable outside it).
*
****************************************************************************/
/** Add <b>conn</b> to the array of connections that we can poll on. The
* connection's socket must be set; the connection starts out
* non-reading and non-writing.
*/
int
connection_add(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->s >= 0 ||
conn->linked ||
(conn->type == CONN_TYPE_AP &&
TO_EDGE_CONN(conn)->is_dns_request));
tor_assert(conn->conn_array_index == -1); /* can only connection_add once */
conn->conn_array_index = smartlist_len(connection_array);
smartlist_add(connection_array, conn);
if (conn->s >= 0 || conn->linked) {
conn->read_event = tor_malloc_zero(sizeof(struct event));
conn->write_event = tor_malloc_zero(sizeof(struct event));
event_set(conn->read_event, conn->s, EV_READ|EV_PERSIST,
conn_read_callback, conn);
event_set(conn->write_event, conn->s, EV_WRITE|EV_PERSIST,
conn_write_callback, conn);
}
log_debug(LD_NET,"new conn type %s, socket %d, n_conns %d.",
conn_type_to_string(conn->type), conn->s,
smartlist_len(connection_array));
return 0;
}
/** Remove the connection from the global list, and remove the
* corresponding poll entry. Calling this function will shift the last
* connection (if any) into the position occupied by conn.
*/
int
connection_remove(connection_t *conn)
{
int current_index;
connection_t *tmp;
tor_assert(conn);
log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d",
conn->s, conn_type_to_string(conn->type),
smartlist_len(connection_array));
tor_assert(conn->conn_array_index >= 0);
current_index = conn->conn_array_index;
connection_unregister_events(conn); /* This is redundant, but cheap. */
if (current_index == smartlist_len(connection_array)-1) { /* at the end */
smartlist_del(connection_array, current_index);
return 0;
}
/* replace this one with the one at the end */
smartlist_del(connection_array, current_index);
tmp = smartlist_get(connection_array, current_index);
tmp->conn_array_index = current_index;
return 0;
}
/** If <b>conn</b> is an edge conn, remove it from the list
* of conn's on this circuit. If it's not on an edge,
* flush and send destroys for all circuits on this conn.
*
* Remove it from connection_array (if applicable) and
* from closeable_connection_list.
*
* Then free it.
*/
static void
connection_unlink(connection_t *conn)
{
connection_about_to_close_connection(conn);
if (conn->conn_array_index >= 0) {
connection_remove(conn);
}
if (conn->linked_conn) {
conn->linked_conn->linked_conn = NULL;
if (! conn->linked_conn->marked_for_close &&
conn->linked_conn->reading_from_linked_conn)
connection_start_reading(conn->linked_conn);
conn->linked_conn = NULL;
}
smartlist_remove(closeable_connection_lst, conn);
smartlist_remove(active_linked_connection_lst, conn);
if (conn->type == CONN_TYPE_EXIT) {
assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn));
}
if (conn->type == CONN_TYPE_OR) {
if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest))
connection_or_remove_from_identity_map(TO_OR_CONN(conn));
}
connection_free(conn);
}
/** Schedule <b>conn</b> to be closed. **/
void
add_connection_to_closeable_list(connection_t *conn)
{
tor_assert(!smartlist_isin(closeable_connection_lst, conn));
tor_assert(conn->marked_for_close);
assert_connection_ok(conn, time(NULL));
smartlist_add(closeable_connection_lst, conn);
}
/** Return 1 if conn is on the closeable list, else return 0. */
int
connection_is_on_closeable_list(connection_t *conn)
{
return smartlist_isin(closeable_connection_lst, conn);
}
/** Return true iff conn is in the current poll array. */
int
connection_in_array(connection_t *conn)
{
return smartlist_isin(connection_array, conn);
}
/** Set <b>*array</b> to an array of all connections, and <b>*n</b>
* to the length of the array. <b>*array</b> and <b>*n</b> must not
* be modified.
*/
smartlist_t *
get_connection_array(void)
{
return connection_array;
}
/** Set the event mask on <b>conn</b> to <b>events</b>. (The event
* mask is a bitmask whose bits are EV_READ and EV_WRITE.)
*/
void
connection_watch_events(connection_t *conn, short events)
{
if (events & EV_READ)
connection_start_reading(conn);
else
connection_stop_reading(conn);
if (events & EV_WRITE)
connection_start_writing(conn);
else
connection_stop_writing(conn);
}
/** Return true iff <b>conn</b> is listening for read events. */
int
connection_is_reading(connection_t *conn)
{
tor_assert(conn);
return conn->reading_from_linked_conn ||
(conn->read_event && event_pending(conn->read_event, EV_READ, NULL));
}
/** Tell the main loop to stop notifying <b>conn</b> of any read events. */
void
connection_stop_reading(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->read_event);
if (conn->linked) {
conn->reading_from_linked_conn = 0;
connection_stop_reading_from_linked_conn(conn);
} else {
if (event_del(conn->read_event))
log_warn(LD_NET, "Error from libevent setting read event state for %d "
"to unwatched: %s",
conn->s,
tor_socket_strerror(tor_socket_errno(conn->s)));
}
}
/** Tell the main loop to start notifying <b>conn</b> of any read events. */
void
connection_start_reading(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->read_event);
if (conn->linked) {
conn->reading_from_linked_conn = 1;
if (connection_should_read_from_linked_conn(conn))
connection_start_reading_from_linked_conn(conn);
} else {
if (event_add(conn->read_event, NULL))
log_warn(LD_NET, "Error from libevent setting read event state for %d "
"to watched: %s",
conn->s,
tor_socket_strerror(tor_socket_errno(conn->s)));
}
}
/** Return true iff <b>conn</b> is listening for write events. */
int
connection_is_writing(connection_t *conn)
{
tor_assert(conn);
return conn->writing_to_linked_conn ||
(conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL));
}
/** Tell the main loop to stop notifying <b>conn</b> of any write events. */
void
connection_stop_writing(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->write_event);
if (conn->linked) {
conn->writing_to_linked_conn = 0;
if (conn->linked_conn)
connection_stop_reading_from_linked_conn(conn->linked_conn);
} else {
if (event_del(conn->write_event))
log_warn(LD_NET, "Error from libevent setting write event state for %d "
"to unwatched: %s",
conn->s,
tor_socket_strerror(tor_socket_errno(conn->s)));
}
}
/** Tell the main loop to start notifying <b>conn</b> of any write events. */
void
connection_start_writing(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->write_event);
if (conn->linked) {
conn->writing_to_linked_conn = 1;
if (conn->linked_conn &&
connection_should_read_from_linked_conn(conn->linked_conn))
connection_start_reading_from_linked_conn(conn->linked_conn);
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -