Move literally everything out of src/or

This commit won't build yet -- it just puts everything in a slightly
more logical place.

The reasoning here is that "src/core" will hold the stuff that every (or
nearly every) tor instance will need in order to do onion routing.
Other features (including some necessary ones) will live in
"src/feature".  The "src/app" directory will hold the stuff needed
to have Tor be an application you can actually run.

This commit DOES NOT refactor the former contents of src/or into a
logical set of acyclic libraries, or change any code at all.  That
will have to come in the future.

We will continue to move things around and split them in the future,
but I hope this lays a reasonable groundwork for doing so.
This commit is contained in:
Nick Mathewson
2018-07-05 16:31:38 -04:00
parent ce84200542
commit 63b4ea22af
256 changed files with 3 additions and 82 deletions
File diff suppressed because it is too large Load Diff
+343
View File
@@ -0,0 +1,343 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file connection.h
* \brief Header file for connection.c.
**/
#ifndef TOR_CONNECTION_H
#define TOR_CONNECTION_H
listener_connection_t *TO_LISTENER_CONN(connection_t *);
struct buf_t;
#define CONN_TYPE_MIN_ 3
/** Type for sockets listening for OR connections. */
#define CONN_TYPE_OR_LISTENER 3
/** A bidirectional TLS connection transmitting a sequence of cells.
* May be from an OR to an OR, or from an OP to an OR. */
#define CONN_TYPE_OR 4
/** A TCP connection from an onion router to a stream's destination. */
#define CONN_TYPE_EXIT 5
/** Type for sockets listening for SOCKS connections. */
#define CONN_TYPE_AP_LISTENER 6
/** A SOCKS proxy connection from the user application to the onion
* proxy. */
#define CONN_TYPE_AP 7
/** Type for sockets listening for HTTP connections to the directory server. */
#define CONN_TYPE_DIR_LISTENER 8
/** Type for HTTP connections to the directory server. */
#define CONN_TYPE_DIR 9
/* Type 10 is unused. */
/** Type for listening for connections from user interface process. */
#define CONN_TYPE_CONTROL_LISTENER 11
/** Type for connections from user interface process. */
#define CONN_TYPE_CONTROL 12
/** Type for sockets listening for transparent connections redirected by pf or
* netfilter. */
#define CONN_TYPE_AP_TRANS_LISTENER 13
/** Type for sockets listening for transparent connections redirected by
* natd. */
#define CONN_TYPE_AP_NATD_LISTENER 14
/** Type for sockets listening for DNS requests. */
#define CONN_TYPE_AP_DNS_LISTENER 15
/** Type for connections from the Extended ORPort. */
#define CONN_TYPE_EXT_OR 16
/** Type for sockets listening for Extended ORPort connections. */
#define CONN_TYPE_EXT_OR_LISTENER 17
/** Type for sockets listening for HTTP CONNECT tunnel connections. */
#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18
#define CONN_TYPE_MAX_ 19
/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
* connection_t. */
/* Proxy client handshake states */
/* We use a proxy but we haven't even connected to it yet. */
#define PROXY_INFANT 1
/* We use an HTTP proxy and we've sent the CONNECT command. */
#define PROXY_HTTPS_WANT_CONNECT_OK 2
/* We use a SOCKS4 proxy and we've sent the CONNECT command. */
#define PROXY_SOCKS4_WANT_CONNECT_OK 3
/* We use a SOCKS5 proxy and we try to negotiate without
any authentication . */
#define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4
/* We use a SOCKS5 proxy and we try to negotiate with
Username/Password authentication . */
#define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5
/* We use a SOCKS5 proxy and we just sent our credentials. */
#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6
/* We use a SOCKS5 proxy and we just sent our CONNECT command. */
#define PROXY_SOCKS5_WANT_CONNECT_OK 7
/* We use a proxy and we CONNECTed successfully!. */
#define PROXY_CONNECTED 8
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
int conn_listener_type_supports_af_unix(int type);
dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int type, int socket_family);
edge_connection_t *edge_connection_new(int type, int socket_family);
entry_connection_t *entry_connection_new(int type, int socket_family);
control_connection_t *control_connection_new(int socket_family);
listener_connection_t *listener_connection_new(int type, int socket_family);
connection_t *connection_new(int type, int socket_family);
int connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
MOCK_DECL(void,connection_free_,(connection_t *conn));
#define connection_free(conn) \
FREE_AND_NULL(connection_t, connection_free_, (conn))
void connection_free_all(void);
void connection_about_to_close_connection(connection_t *conn);
void connection_close_immediate(connection_t *conn);
void connection_mark_for_close_(connection_t *conn,
int line, const char *file);
MOCK_DECL(void, connection_mark_for_close_internal_,
(connection_t *conn, int line, const char *file));
#define connection_mark_for_close(c) \
connection_mark_for_close_((c), __LINE__, SHORT_FILE__)
#define connection_mark_for_close_internal(c) \
connection_mark_for_close_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
* Use the _internal versions of connection_mark_for_close; this should be
* called when you either are sure that if this is an or_connection_t the
* controlling channel has been notified (e.g. with
* connection_or_notify_error()), or you actually are the
* connection_or_close_for_error() or connection_or_close_normally function.
* For all other cases, use connection_mark_and_flush() instead, which
* checks for or_connection_t properly, instead. See below.
*/
#define connection_mark_and_flush_internal_(c,line,file) \
do { \
connection_t *tmp_conn__ = (c); \
connection_mark_for_close_internal_(tmp_conn__, (line), (file)); \
tmp_conn__->hold_open_until_flushed = 1; \
} while (0)
#define connection_mark_and_flush_internal(c) \
connection_mark_and_flush_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
*/
#define connection_mark_and_flush_(c,line,file) \
do { \
connection_t *tmp_conn_ = (c); \
if (tmp_conn_->type == CONN_TYPE_OR) { \
log_warn(LD_CHANNEL | LD_BUG, \
"Something tried to close (and flush) an or_connection_t" \
" without going through channels at %s:%d", \
file, line); \
connection_or_close_for_error(TO_OR_CONN(tmp_conn_), 1); \
} else { \
connection_mark_and_flush_internal_(c, line, file); \
} \
} while (0)
#define connection_mark_and_flush(c) \
connection_mark_and_flush_((c), __LINE__, SHORT_FILE__)
void connection_expire_held_open(void);
int connection_connect(connection_t *conn, const char *address,
const tor_addr_t *addr,
uint16_t port, int *socket_error);
#ifdef HAVE_SYS_UN_H
int connection_connect_unix(connection_t *conn, const char *socket_path,
int *socket_error);
#endif /* defined(HAVE_SYS_UN_H) */
/** Maximum size of information that we can fit into SOCKS5 username
or password fields. */
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
/** Total maximum size of information that we can fit into SOCKS5
username and password fields. */
#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE
int connection_proxy_connect(connection_t *conn, int type);
int connection_read_proxy_handshake(connection_t *conn);
void log_failed_proxy_connection(connection_t *conn);
int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
const connection_t *conn);
int retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns,
int close_all_noncontrol);
void connection_mark_all_noncontrol_listeners(void);
void connection_mark_all_noncontrol_connections(void);
ssize_t connection_bucket_write_limit(connection_t *conn, time_t now);
int global_write_bucket_low(connection_t *conn, size_t attempt, int priority);
void connection_bucket_init(void);
void connection_bucket_adjust(const or_options_t *options);
void connection_bucket_refill_all(time_t now,
uint32_t now_ts);
void connection_read_bw_exhausted(connection_t *conn, bool is_global_bw);
void connection_write_bw_exhausted(connection_t *conn, bool is_global_bw);
void connection_consider_empty_read_buckets(connection_t *conn);
void connection_consider_empty_write_buckets(connection_t *conn);
int connection_handle_read(connection_t *conn);
int connection_buf_get_bytes(char *string, size_t len, connection_t *conn);
int connection_buf_get_line(connection_t *conn, char *data,
size_t *data_len);
int connection_fetch_from_buf_http(connection_t *conn,
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used,
size_t max_bodylen, int force_complete);
int connection_wants_to_flush(connection_t *conn);
int connection_outbuf_too_full(connection_t *conn);
int connection_handle_write(connection_t *conn, int force);
int connection_flush(connection_t *conn);
MOCK_DECL(void, connection_write_to_buf_impl_,
(const char *string, size_t len, connection_t *conn, int zlib));
/* DOCDOC connection_write_to_buf */
static void connection_buf_add(const char *string, size_t len,
connection_t *conn);
static inline void
connection_buf_add(const char *string, size_t len, connection_t *conn)
{
connection_write_to_buf_impl_(string, len, conn, 0);
}
void connection_buf_add_compress(const char *string, size_t len,
dir_connection_t *conn, int done);
void connection_buf_add_buf(connection_t *conn, struct buf_t *buf);
size_t connection_get_inbuf_len(connection_t *conn);
size_t connection_get_outbuf_len(connection_t *conn);
connection_t *connection_get_by_global_id(uint64_t id);
connection_t *connection_get_by_type(int type);
MOCK_DECL(connection_t *,connection_get_by_type_addr_port_purpose,(int type,
const tor_addr_t *addr,
uint16_t port, int purpose));
connection_t *connection_get_by_type_state(int type, int state);
connection_t *connection_get_by_type_state_rendquery(int type, int state,
const char *rendquery);
smartlist_t *connection_list_by_type_state(int type, int state);
smartlist_t *connection_list_by_type_purpose(int type, int purpose);
smartlist_t *connection_dir_list_by_purpose_and_resource(
int purpose,
const char *resource);
smartlist_t *connection_dir_list_by_purpose_resource_and_state(
int purpose,
const char *resource,
int state);
#define CONN_LEN_AND_FREE_TEMPLATE(sl) \
STMT_BEGIN \
int len = smartlist_len(sl); \
smartlist_free(sl); \
return len; \
STMT_END
/** Return a count of directory connections that are fetching the item
* described by <b>purpose</b>/<b>resource</b>. */
static inline int
connection_dir_count_by_purpose_and_resource(
int purpose,
const char *resource)
{
smartlist_t *conns = connection_dir_list_by_purpose_and_resource(
purpose,
resource);
CONN_LEN_AND_FREE_TEMPLATE(conns);
}
/** Return a count of directory connections that are fetching the item
* described by <b>purpose</b>/<b>resource</b>/<b>state</b>. */
static inline int
connection_dir_count_by_purpose_resource_and_state(
int purpose,
const char *resource,
int state)
{
smartlist_t *conns =
connection_dir_list_by_purpose_resource_and_state(
purpose,
resource,
state);
CONN_LEN_AND_FREE_TEMPLATE(conns);
}
#undef CONN_LEN_AND_FREE_TEMPLATE
int any_other_active_or_conns(const or_connection_t *this_conn);
/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define connection_speaks_cells(conn) (((conn)->type == CONN_TYPE_OR) || 0)
int connection_is_listener(connection_t *conn);
int connection_state_is_open(connection_t *conn);
int connection_state_is_connecting(connection_t *conn);
char *alloc_http_authenticator(const char *authenticator);
void assert_connection_ok(connection_t *conn, time_t now);
int connection_or_nonopen_was_started_here(or_connection_t *conn);
void connection_dump_buffer_mem_stats(int severity);
MOCK_DECL(void, clock_skew_warning,
(const connection_t *conn, long apparent_skew, int trusted,
log_domain_mask_t domain, const char *received,
const char *source));
int connection_is_moribund(connection_t *conn);
void connection_check_oos(int n_socks, int failed);
/** Execute the statement <b>stmt</b>, which may log events concerning the
* connection <b>conn</b>. To prevent infinite loops, disable log messages
* being sent to controllers if <b>conn</b> is a control connection.
*
* Stmt must not contain any return or goto statements.
*/
#define CONN_LOG_PROTECT(conn, stmt) \
STMT_BEGIN \
int _log_conn_is_control; \
tor_assert(conn); \
_log_conn_is_control = (conn->type == CONN_TYPE_CONTROL); \
if (_log_conn_is_control) \
disable_control_logging(); \
STMT_BEGIN stmt; STMT_END; \
if (_log_conn_is_control) \
enable_control_logging(); \
STMT_END
#ifdef CONNECTION_PRIVATE
STATIC void connection_free_minimal(connection_t *conn);
/* Used only by connection.c and test*.c */
MOCK_DECL(STATIC int,connection_connect_sockaddr,
(connection_t *conn,
const struct sockaddr *sa,
socklen_t sa_len,
const struct sockaddr *bindaddr,
socklen_t bindaddr_len,
int *socket_error));
MOCK_DECL(STATIC void, kill_conn_list_for_oos, (smartlist_t *conns));
MOCK_DECL(STATIC smartlist_t *, pick_oos_victims, (int n));
#endif /* defined(CONNECTION_PRIVATE) */
#endif /* !defined(TOR_CONNECTION_H) */
+599
View File
@@ -0,0 +1,599 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file cpuworker.c
* \brief Uses the workqueue/threadpool code to farm CPU-intensive activities
* out to subprocesses.
*
* The multithreading backend for this module is in workqueue.c; this module
* specializes workqueue.c.
*
* Right now, we use this infrastructure
* <ul><li>for processing onionskins in onion.c
* <li>for compressing consensuses in consdiffmgr.c,
* <li>and for calculating diffs and compressing them in consdiffmgr.c.
* </ul>
**/
#include "or/or.h"
#include "or/channel.h"
#include "or/circuitbuild.h"
#include "or/circuitlist.h"
#include "or/connection_or.h"
#include "or/config.h"
#include "or/cpuworker.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "or/main.h"
#include "or/onion.h"
#include "or/rephist.h"
#include "or/router.h"
#include "lib/evloop/workqueue.h"
#include "or/or_circuit_st.h"
#include "lib/intmath/weakrng.h"
static void queue_pending_tasks(void);
typedef struct worker_state_s {
int generation;
server_onion_keys_t *onion_keys;
} worker_state_t;
static void *
worker_state_new(void *arg)
{
worker_state_t *ws;
(void)arg;
ws = tor_malloc_zero(sizeof(worker_state_t));
ws->onion_keys = server_onion_keys_new();
return ws;
}
#define worker_state_free(ws) \
FREE_AND_NULL(worker_state_t, worker_state_free_, (ws))
static void
worker_state_free_(worker_state_t *ws)
{
if (!ws)
return;
server_onion_keys_free(ws->onion_keys);
tor_free(ws);
}
static void
worker_state_free_void(void *arg)
{
worker_state_free_(arg);
}
static replyqueue_t *replyqueue = NULL;
static threadpool_t *threadpool = NULL;
static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
static int total_pending_tasks = 0;
static int max_pending_tasks = 128;
/** Initialize the cpuworker subsystem. It is OK to call this more than once
* during Tor's lifetime.
*/
void
cpu_init(void)
{
if (!replyqueue) {
replyqueue = replyqueue_new(0);
}
if (!threadpool) {
/*
In our threadpool implementation, half the threads are permissive and
half are strict (when it comes to running lower-priority tasks). So we
always make sure we have at least two threads, so that there will be at
least one thread of each kind.
*/
const int n_threads = get_num_cpus(get_options()) + 1;
threadpool = threadpool_new(n_threads,
replyqueue,
worker_state_new,
worker_state_free_void,
NULL);
int r = threadpool_register_reply_event(threadpool, NULL);
tor_assert(r == 0);
}
/* Total voodoo. Can we make this more sensible? */
max_pending_tasks = get_num_cpus(get_options()) * 64;
crypto_seed_weak_rng(&request_sample_rng);
}
/** Magic numbers to make sure our cpuworker_requests don't grow any
* mis-framing bugs. */
#define CPUWORKER_REQUEST_MAGIC 0xda4afeed
#define CPUWORKER_REPLY_MAGIC 0x5eedf00d
/** A request sent to a cpuworker. */
typedef struct cpuworker_request_t {
/** Magic number; must be CPUWORKER_REQUEST_MAGIC. */
uint32_t magic;
/** Flag: Are we timing this request? */
unsigned timed : 1;
/** If we're timing this request, when was it sent to the cpuworker? */
struct timeval started_at;
/** A create cell for the cpuworker to process. */
create_cell_t create_cell;
/* Turn the above into a tagged union if needed. */
} cpuworker_request_t;
/** A reply sent by a cpuworker. */
typedef struct cpuworker_reply_t {
/** Magic number; must be CPUWORKER_REPLY_MAGIC. */
uint32_t magic;
/** True iff we got a successful request. */
uint8_t success;
/** Are we timing this request? */
unsigned int timed : 1;
/** What handshake type was the request? (Used for timing) */
uint16_t handshake_type;
/** When did we send the request to the cpuworker? */
struct timeval started_at;
/** Once the cpuworker received the request, how many microseconds did it
* take? (This shouldn't overflow; 4 billion micoseconds is over an hour,
* and we'll never have an onion handshake that takes so long.) */
uint32_t n_usec;
/** Output of processing a create cell
*
* @{
*/
/** The created cell to send back. */
created_cell_t created_cell;
/** The keys to use on this circuit. */
uint8_t keys[CPATH_KEY_MATERIAL_LEN];
/** Input to use for authenticating introduce1 cells. */
uint8_t rend_auth_material[DIGEST_LEN];
} cpuworker_reply_t;
typedef struct cpuworker_job_u {
or_circuit_t *circ;
union {
cpuworker_request_t request;
cpuworker_reply_t reply;
} u;
} cpuworker_job_t;
static workqueue_reply_t
update_state_threadfn(void *state_, void *work_)
{
worker_state_t *state = state_;
worker_state_t *update = work_;
server_onion_keys_free(state->onion_keys);
state->onion_keys = update->onion_keys;
update->onion_keys = NULL;
worker_state_free(update);
++state->generation;
return WQ_RPL_REPLY;
}
/** Called when the onion key has changed so update all CPU worker(s) with
* new function pointers with which a new state will be generated.
*/
void
cpuworkers_rotate_keyinfo(void)
{
if (!threadpool) {
/* If we're a client, then we won't have cpuworkers, and we won't need
* to tell them to rotate their state.
*/
return;
}
if (threadpool_queue_update(threadpool,
worker_state_new,
update_state_threadfn,
worker_state_free_void,
NULL)) {
log_warn(LD_OR, "Failed to queue key update for worker threads.");
}
}
/** Indexed by handshake type: how many onionskins have we processed and
* counted of that type? */
static uint64_t onionskins_n_processed[MAX_ONION_HANDSHAKE_TYPE+1];
/** Indexed by handshake type, corresponding to the onionskins counted in
* onionskins_n_processed: how many microseconds have we spent in cpuworkers
* processing that kind of onionskin? */
static uint64_t onionskins_usec_internal[MAX_ONION_HANDSHAKE_TYPE+1];
/** Indexed by handshake type, corresponding to onionskins counted in
* onionskins_n_processed: how many microseconds have we spent waiting for
* cpuworkers to give us answers for that kind of onionskin?
*/
static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1];
/** If any onionskin takes longer than this, we clip them to this
* time. (microseconds) */
#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
/** Return true iff we'd like to measure a handshake of type
* <b>onionskin_type</b>. Call only from the main thread. */
static int
should_time_request(uint16_t onionskin_type)
{
/* If we've never heard of this type, we shouldn't even be here. */
if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE)
return 0;
/* Measure the first N handshakes of each type, to ensure we have a
* sample */
if (onionskins_n_processed[onionskin_type] < 4096)
return 1;
/** Otherwise, measure with P=1/128. We avoid doing this for every
* handshake, since the measurement itself can take a little time. */
return tor_weak_random_one_in_n(&request_sample_rng, 128);
}
/** Return an estimate of how many microseconds we will need for a single
* cpuworker to process <b>n_requests</b> onionskins of type
* <b>onionskin_type</b>. */
uint64_t
estimated_usec_for_onionskins(uint32_t n_requests, uint16_t onionskin_type)
{
if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */
return 1000 * (uint64_t)n_requests;
if (PREDICT_UNLIKELY(onionskins_n_processed[onionskin_type] < 100)) {
/* Until we have 100 data points, just asssume everything takes 1 msec. */
return 1000 * (uint64_t)n_requests;
} else {
/* This can't overflow: we'll never have more than 500000 onionskins
* measured in onionskin_usec_internal, and they won't take anything near
* 1 sec each, and we won't have anything like 1 million queued
* onionskins. But that's 5e5 * 1e6 * 1e6, which is still less than
* UINT64_MAX. */
return (onionskins_usec_internal[onionskin_type] * n_requests) /
onionskins_n_processed[onionskin_type];
}
}
/** Compute the absolute and relative overhead of using the cpuworker
* framework for onionskins of type <b>onionskin_type</b>.*/
static int
get_overhead_for_onionskins(uint32_t *usec_out, double *frac_out,
uint16_t onionskin_type)
{
uint64_t overhead;
*usec_out = 0;
*frac_out = 0.0;
if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */
return -1;
if (onionskins_n_processed[onionskin_type] == 0 ||
onionskins_usec_internal[onionskin_type] == 0 ||
onionskins_usec_roundtrip[onionskin_type] == 0)
return -1;
overhead = onionskins_usec_roundtrip[onionskin_type] -
onionskins_usec_internal[onionskin_type];
*usec_out = (uint32_t)(overhead / onionskins_n_processed[onionskin_type]);
*frac_out = ((double)overhead) / onionskins_usec_internal[onionskin_type];
return 0;
}
/** If we've measured overhead for onionskins of type <b>onionskin_type</b>,
* log it. */
void
cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
const char *onionskin_type_name)
{
uint32_t overhead;
double relative_overhead;
int r;
r = get_overhead_for_onionskins(&overhead, &relative_overhead,
onionskin_type);
if (!overhead || r<0)
return;
log_fn(severity, LD_OR,
"%s onionskins have averaged %u usec overhead (%.2f%%) in "
"cpuworker code ",
onionskin_type_name, (unsigned)overhead, relative_overhead*100);
}
/** Handle a reply from the worker threads. */
static void
cpuworker_onion_handshake_replyfn(void *work_)
{
cpuworker_job_t *job = work_;
cpuworker_reply_t rpl;
or_circuit_t *circ = NULL;
tor_assert(total_pending_tasks > 0);
--total_pending_tasks;
/* Could avoid this, but doesn't matter. */
memcpy(&rpl, &job->u.reply, sizeof(rpl));
tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);
if (rpl.timed && rpl.success &&
rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
/* Time how long this request took. The handshake_type check should be
needless, but let's leave it in to be safe. */
struct timeval tv_end, tv_diff;
int64_t usec_roundtrip;
tor_gettimeofday(&tv_end);
timersub(&tv_end, &rpl.started_at, &tv_diff);
usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
if (usec_roundtrip >= 0 &&
usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
++onionskins_n_processed[rpl.handshake_type];
onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
/* Scale down every 500000 handshakes. On a busy server, that's
* less impressive than it sounds. */
onionskins_n_processed[rpl.handshake_type] /= 2;
onionskins_usec_internal[rpl.handshake_type] /= 2;
onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
}
}
}
circ = job->circ;
log_debug(LD_OR,
"Unpacking cpuworker reply %p, circ=%p, success=%d",
job, circ, rpl.success);
if (circ->base_.magic == DEAD_CIRCUIT_MAGIC) {
/* The circuit was supposed to get freed while the reply was
* pending. Instead, it got left for us to free so that we wouldn't freak
* out when the job->circ field wound up pointing to nothing. */
log_debug(LD_OR, "Circuit died while reply was pending. Freeing memory.");
circ->base_.magic = 0;
tor_free(circ);
goto done_processing;
}
circ->workqueue_entry = NULL;
if (TO_CIRCUIT(circ)->marked_for_close) {
/* We already marked this circuit; we can't call it open. */
log_debug(LD_OR,"circuit is already marked.");
goto done_processing;
}
if (rpl.success == 0) {
log_debug(LD_OR,
"decoding onionskin failed. "
"(Old key or bad software.) Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
goto done_processing;
}
if (onionskin_answer(circ,
&rpl.created_cell,
(const char*)rpl.keys, sizeof(rpl.keys),
rpl.rend_auth_material) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
goto done_processing;
}
log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
done_processing:
memwipe(&rpl, 0, sizeof(rpl));
memwipe(job, 0, sizeof(*job));
tor_free(job);
queue_pending_tasks();
}
/** Implementation function for onion handshake requests. */
static workqueue_reply_t
cpuworker_onion_handshake_threadfn(void *state_, void *work_)
{
worker_state_t *state = state_;
cpuworker_job_t *job = work_;
/* variables for onion processing */
server_onion_keys_t *onion_keys = state->onion_keys;
cpuworker_request_t req;
cpuworker_reply_t rpl;
memcpy(&req, &job->u.request, sizeof(req));
tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);
memset(&rpl, 0, sizeof(rpl));
const create_cell_t *cc = &req.create_cell;
created_cell_t *cell_out = &rpl.created_cell;
struct timeval tv_start = {0,0}, tv_end;
int n;
rpl.timed = req.timed;
rpl.started_at = req.started_at;
rpl.handshake_type = cc->handshake_type;
if (req.timed)
tor_gettimeofday(&tv_start);
n = onion_skin_server_handshake(cc->handshake_type,
cc->onionskin, cc->handshake_len,
onion_keys,
cell_out->reply,
rpl.keys, CPATH_KEY_MATERIAL_LEN,
rpl.rend_auth_material);
if (n < 0) {
/* failure */
log_debug(LD_OR,"onion_skin_server_handshake failed.");
memset(&rpl, 0, sizeof(rpl));
rpl.success = 0;
} else {
/* success */
log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
cell_out->handshake_len = n;
switch (cc->cell_type) {
case CELL_CREATE:
cell_out->cell_type = CELL_CREATED; break;
case CELL_CREATE2:
cell_out->cell_type = CELL_CREATED2; break;
case CELL_CREATE_FAST:
cell_out->cell_type = CELL_CREATED_FAST; break;
default:
tor_assert(0);
return WQ_RPL_SHUTDOWN;
}
rpl.success = 1;
}
rpl.magic = CPUWORKER_REPLY_MAGIC;
if (req.timed) {
struct timeval tv_diff;
int64_t usec;
tor_gettimeofday(&tv_end);
timersub(&tv_end, &tv_start, &tv_diff);
usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
else
rpl.n_usec = (uint32_t) usec;
}
memcpy(&job->u.reply, &rpl, sizeof(rpl));
memwipe(&req, 0, sizeof(req));
memwipe(&rpl, 0, sizeof(req));
return WQ_RPL_REPLY;
}
/** Take pending tasks from the queue and assign them to cpuworkers. */
static void
queue_pending_tasks(void)
{
or_circuit_t *circ;
create_cell_t *onionskin = NULL;
while (total_pending_tasks < max_pending_tasks) {
circ = onion_next_task(&onionskin);
if (!circ)
return;
if (assign_onionskin_to_cpuworker(circ, onionskin) < 0)
log_info(LD_OR,"assign_to_cpuworker failed. Ignoring.");
}
}
/** DOCDOC */
MOCK_IMPL(workqueue_entry_t *,
cpuworker_queue_work,(workqueue_priority_t priority,
workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
void *arg))
{
tor_assert(threadpool);
return threadpool_queue_work_priority(threadpool,
priority,
fn,
reply_fn,
arg);
}
/** Try to tell a cpuworker to perform the public key operations necessary to
* respond to <b>onionskin</b> for the circuit <b>circ</b>.
*
* Return 0 if we successfully assign the task, or -1 on failure.
*/
int
assign_onionskin_to_cpuworker(or_circuit_t *circ,
create_cell_t *onionskin)
{
workqueue_entry_t *queue_entry;
cpuworker_job_t *job;
cpuworker_request_t req;
int should_time;
tor_assert(threadpool);
if (!circ->p_chan) {
log_info(LD_OR,"circ->p_chan gone. Failing circ.");
tor_free(onionskin);
return -1;
}
if (total_pending_tasks >= max_pending_tasks) {
log_debug(LD_OR,"No idle cpuworkers. Queuing.");
if (onion_pending_add(circ, onionskin) < 0) {
tor_free(onionskin);
return -1;
}
return 0;
}
if (!channel_is_client(circ->p_chan))
rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);
should_time = should_time_request(onionskin->handshake_type);
memset(&req, 0, sizeof(req));
req.magic = CPUWORKER_REQUEST_MAGIC;
req.timed = should_time;
memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));
tor_free(onionskin);
if (should_time)
tor_gettimeofday(&req.started_at);
job = tor_malloc_zero(sizeof(cpuworker_job_t));
job->circ = circ;
memcpy(&job->u.request, &req, sizeof(req));
memwipe(&req, 0, sizeof(req));
++total_pending_tasks;
queue_entry = threadpool_queue_work_priority(threadpool,
WQ_PRI_HIGH,
cpuworker_onion_handshake_threadfn,
cpuworker_onion_handshake_replyfn,
job);
if (!queue_entry) {
log_warn(LD_BUG, "Couldn't queue work on threadpool");
tor_free(job);
return -1;
}
log_debug(LD_OR, "Queued task %p (qe=%p, circ=%p)",
job, queue_entry, job->circ);
circ->workqueue_entry = queue_entry;
return 0;
}
/** If <b>circ</b> has a pending handshake that hasn't been processed yet,
* remove it from the worker queue. */
void
cpuworker_cancel_circ_handshake(or_circuit_t *circ)
{
cpuworker_job_t *job;
if (circ->workqueue_entry == NULL)
return;
job = workqueue_entry_cancel(circ->workqueue_entry);
if (job) {
/* It successfully cancelled. */
memwipe(job, 0xe0, sizeof(*job));
tor_free(job);
tor_assert(total_pending_tasks > 0);
--total_pending_tasks;
/* if (!job), this is done in cpuworker_onion_handshake_replyfn. */
circ->workqueue_entry = NULL;
}
}
+37
View File
@@ -0,0 +1,37 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file cpuworker.h
* \brief Header file for cpuworker.c.
**/
#ifndef TOR_CPUWORKER_H
#define TOR_CPUWORKER_H
void cpu_init(void);
void cpuworkers_rotate_keyinfo(void);
struct workqueue_entry_s;
enum workqueue_reply_t;
enum workqueue_priority_t;
MOCK_DECL(struct workqueue_entry_s *, cpuworker_queue_work, (
enum workqueue_priority_t priority,
enum workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
void *arg));
struct create_cell_t;
int assign_onionskin_to_cpuworker(or_circuit_t *circ,
struct create_cell_t *onionskin);
uint64_t estimated_usec_for_onionskins(uint32_t n_requests,
uint16_t onionskin_type);
void cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
const char *onionskin_type_name);
void cpuworker_cancel_circ_handshake(or_circuit_t *circ);
#endif /* !defined(TOR_CPUWORKER_H) */
File diff suppressed because it is too large Load Diff
+122
View File
@@ -0,0 +1,122 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file main.h
* \brief Header file for main.c.
**/
#ifndef TOR_MAIN_H
#define TOR_MAIN_H
int have_completed_a_circuit(void);
void note_that_we_completed_a_circuit(void);
void note_that_we_maybe_cant_complete_circuits(void);
int connection_add_impl(connection_t *conn, int is_connecting);
#define connection_add(conn) connection_add_impl((conn), 0)
#define connection_add_connecting(conn) connection_add_impl((conn), 1)
int connection_remove(connection_t *conn);
void connection_unregister_events(connection_t *conn);
int connection_in_array(connection_t *conn);
void add_connection_to_closeable_list(connection_t *conn);
int connection_is_on_closeable_list(connection_t *conn);
MOCK_DECL(smartlist_t *, get_connection_array, (void));
MOCK_DECL(uint64_t,get_bytes_read,(void));
MOCK_DECL(uint64_t,get_bytes_written,(void));
void stats_increment_bytes_read_and_written(uint64_t r, uint64_t w);
/** Bitmask for events that we can turn on and off with
* connection_watch_events. */
typedef enum watchable_events {
/* Yes, it is intentional that these match Libevent's EV_READ and EV_WRITE */
READ_EVENT=0x02, /**< We want to know when a connection is readable */
WRITE_EVENT=0x04 /**< We want to know when a connection is writable */
} watchable_events_t;
void connection_watch_events(connection_t *conn, watchable_events_t events);
int connection_is_reading(connection_t *conn);
MOCK_DECL(void,connection_stop_reading,(connection_t *conn));
MOCK_DECL(void,connection_start_reading,(connection_t *conn));
int connection_is_writing(connection_t *conn);
MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
MOCK_DECL(void,connection_start_writing,(connection_t *conn));
void tor_shutdown_event_loop_and_exit(int exitcode);
int tor_event_loop_shutdown_is_pending(void);
void connection_stop_reading_from_linked_conn(connection_t *conn);
MOCK_DECL(int, connection_count_moribund, (void));
void directory_all_unreachable(time_t now);
void directory_info_has_arrived(time_t now, int from_cache, int suppress_logs);
void ip_address_changed(int at_interface);
void dns_servers_relaunch_checks(void);
void reset_all_main_loop_timers(void);
void reschedule_descriptor_update_check(void);
void reschedule_directory_downloads(void);
void reschedule_or_state_save(void);
void reschedule_dirvote(const or_options_t *options);
void mainloop_schedule_postloop_cleanup(void);
void rescan_periodic_events(const or_options_t *options);
void update_current_time(time_t now);
MOCK_DECL(long,get_uptime,(void));
MOCK_DECL(void,reset_uptime,(void));
unsigned get_signewnym_epoch(void);
void handle_signals(void);
void activate_signal(int signal_num);
int try_locking(const or_options_t *options, int err_if_locked);
int have_lockfile(void);
void release_lockfile(void);
void tor_remove_file(const char *filename);
void tor_cleanup(void);
void tor_free_all(int postfork);
int do_main_loop(void);
int tor_init(int argc, char **argv);
void reset_main_loop_counters(void);
uint64_t get_main_loop_success_count(void);
uint64_t get_main_loop_error_count(void);
uint64_t get_main_loop_idle_count(void);
void periodic_events_on_new_options(const or_options_t *options);
void reschedule_per_second_timer(void);
struct token_bucket_rw_t;
extern time_t time_of_process_start;
extern int quiet_level;
extern struct token_bucket_rw_t global_bucket;
extern struct token_bucket_rw_t global_relayed_bucket;
#ifdef MAIN_PRIVATE
STATIC void init_connection_lists(void);
STATIC void initialize_mainloop_events(void);
STATIC void close_closeable_connections(void);
STATIC void initialize_periodic_events(void);
STATIC void teardown_periodic_events(void);
STATIC int get_my_roles(const or_options_t *options);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *connection_array;
/* We need the periodic_event_item_t definition. */
#include "or/periodic.h"
extern periodic_event_item_t periodic_events[];
#endif
#endif /* defined(MAIN_PRIVATE) */
#endif /* !defined(TOR_MAIN_H) */
+172
View File
@@ -0,0 +1,172 @@
/* Copyright (c) 2015-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file periodic.c
*
* \brief Generic backend for handling periodic events.
*
* The events in this module are used by main.c to track items that need
* to fire once every N seconds, possibly picking a new interval each time
* that they fire. See periodic_events[] in main.c for examples.
*/
#include "or/or.h"
#include "lib/evloop/compat_libevent.h"
#include "or/config.h"
#include "or/main.h"
#include "or/periodic.h"
#include "lib/evloop/compat_libevent.h"
/** We disable any interval greater than this number of seconds, on the
* grounds that it is probably an absolute time mistakenly passed in as a
* relative time.
*/
static const int MAX_INTERVAL = 10 * 365 * 86400;
/** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
* now. */
static void
periodic_event_set_interval(periodic_event_item_t *event,
time_t next_interval)
{
tor_assert(next_interval < MAX_INTERVAL);
struct timeval tv;
tv.tv_sec = next_interval;
tv.tv_usec = 0;
mainloop_event_schedule(event->ev, &tv);
}
/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
* event that needs to be called */
static void
periodic_event_dispatch(mainloop_event_t *ev, void *data)
{
periodic_event_item_t *event = data;
tor_assert(ev == event->ev);
if (BUG(!periodic_event_is_enabled(event))) {
return;
}
time_t now = time(NULL);
update_current_time(now);
const or_options_t *options = get_options();
// log_debug(LD_GENERAL, "Dispatching %s", event->name);
int r = event->fn(now, options);
int next_interval = 0;
if (!periodic_event_is_enabled(event)) {
/* The event got disabled from inside its callback; no need to
* reschedule. */
return;
}
/* update the last run time if action was taken */
if (r==0) {
log_err(LD_BUG, "Invalid return value for periodic event from %s.",
event->name);
tor_assert(r != 0);
} else if (r > 0) {
event->last_action_time = now;
/* If the event is meant to happen after ten years, that's likely
* a bug, and somebody gave an absolute time rather than an interval.
*/
tor_assert(r < MAX_INTERVAL);
next_interval = r;
} else {
/* no action was taken, it is likely a precondition failed,
* we should reschedule for next second incase the precondition
* passes then */
next_interval = 1;
}
// log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
// next_interval);
struct timeval tv = { next_interval , 0 };
mainloop_event_schedule(ev, &tv);
}
/** Schedules <b>event</b> to run as soon as possible from now. */
void
periodic_event_reschedule(periodic_event_item_t *event)
{
/* Don't reschedule a disabled event. */
if (periodic_event_is_enabled(event)) {
periodic_event_set_interval(event, 1);
}
}
/** Initializes the libevent backend for a periodic event. */
void
periodic_event_setup(periodic_event_item_t *event)
{
if (event->ev) { /* Already setup? This is a bug */
log_err(LD_BUG, "Initial dispatch should only be done once.");
tor_assert(0);
}
event->ev = mainloop_event_new(periodic_event_dispatch,
event);
tor_assert(event->ev);
}
/** Handles initial dispatch for periodic events. It should happen 1 second
* after the events are created to mimic behaviour before #3199's refactor */
void
periodic_event_launch(periodic_event_item_t *event)
{
if (! event->ev) { /* Not setup? This is a bug */
log_err(LD_BUG, "periodic_event_launch without periodic_event_setup");
tor_assert(0);
}
/* Event already enabled? This is a bug */
if (periodic_event_is_enabled(event)) {
log_err(LD_BUG, "periodic_event_launch on an already enabled event");
tor_assert(0);
}
// Initial dispatch
event->enabled = 1;
periodic_event_dispatch(event->ev, event);
}
/** Release all storage associated with <b>event</b> */
void
periodic_event_destroy(periodic_event_item_t *event)
{
if (!event)
return;
mainloop_event_free(event->ev);
event->last_action_time = 0;
}
/** Enable the given event which means the event is launched and then the
* event's enabled flag is set. This can be called for an event that is
* already enabled. */
void
periodic_event_enable(periodic_event_item_t *event)
{
tor_assert(event);
/* Safely and silently ignore if this event is already enabled. */
if (periodic_event_is_enabled(event)) {
return;
}
periodic_event_launch(event);
}
/** Disable the given event which means the event is destroyed and then the
* event's enabled flag is unset. This can be called for an event that is
* already disabled. */
void
periodic_event_disable(periodic_event_item_t *event)
{
tor_assert(event);
/* Safely and silently ignore if this event is already disabled. */
if (!periodic_event_is_enabled(event)) {
return;
}
mainloop_event_cancel(event->ev);
event->enabled = 0;
}
+88
View File
@@ -0,0 +1,88 @@
/* Copyright (c) 2015-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_PERIODIC_H
#define TOR_PERIODIC_H
#define PERIODIC_EVENT_NO_UPDATE (-1)
/* Tor roles for which a periodic event item is for. An event can be for
* multiple roles, they can be combined. */
#define PERIODIC_EVENT_ROLE_CLIENT (1U << 0)
#define PERIODIC_EVENT_ROLE_RELAY (1U << 1)
#define PERIODIC_EVENT_ROLE_BRIDGE (1U << 2)
#define PERIODIC_EVENT_ROLE_DIRAUTH (1U << 3)
#define PERIODIC_EVENT_ROLE_BRIDGEAUTH (1U << 4)
#define PERIODIC_EVENT_ROLE_HS_SERVICE (1U << 5)
#define PERIODIC_EVENT_ROLE_DIRSERVER (1U << 6)
/* Helper macro to make it a bit less annoying to defined groups of roles that
* are often used. */
/* Router that is a Bridge or Relay. */
#define PERIODIC_EVENT_ROLE_ROUTER \
(PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_RELAY)
/* Authorities that is both bridge and directory. */
#define PERIODIC_EVENT_ROLE_AUTHORITIES \
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_DIRAUTH)
/* All roles. */
#define PERIODIC_EVENT_ROLE_ALL \
(PERIODIC_EVENT_ROLE_AUTHORITIES | PERIODIC_EVENT_ROLE_CLIENT | \
PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_ROUTER)
/*
* Event flags which can change the behavior of an event.
*/
/* Indicate that the event needs the network meaning that if we are in
* DisableNetwork or hibernation mode, the event won't be enabled. This obey
* the net_is_disabled() check. */
#define PERIODIC_EVENT_FLAG_NEED_NET (1U << 0)
/** Callback function for a periodic event to take action. The return value
* influences the next time the function will get called. Return
* PERIODIC_EVENT_NO_UPDATE to not update <b>last_action_time</b> and be polled
* again in the next second. If a positive value is returned it will update the
* interval time. */
typedef int (*periodic_event_helper_t)(time_t now,
const or_options_t *options);
struct mainloop_event_t;
/** A single item for the periodic-events-function table. */
typedef struct periodic_event_item_t {
periodic_event_helper_t fn; /**< The function to run the event */
time_t last_action_time; /**< The last time the function did something */
struct mainloop_event_t *ev; /**< Libevent callback we're using to implement
* this */
const char *name; /**< Name of the function -- for debug */
/* Bitmask of roles define above for which this event applies. */
uint32_t roles;
/* Bitmask of flags which can change the behavior of the event. */
uint32_t flags;
/* Indicate that this event has been enabled that is scheduled. */
unsigned int enabled : 1;
} periodic_event_item_t;
/** events will get their interval from first execution */
#define PERIODIC_EVENT(fn, r, f) { fn##_callback, 0, NULL, #fn, r, f, 0 }
#define END_OF_PERIODIC_EVENTS { NULL, 0, NULL, NULL, 0, 0, 0 }
/* Return true iff the given event was setup before thus is enabled to be
* scheduled. */
static inline int
periodic_event_is_enabled(const periodic_event_item_t *item)
{
return item->enabled;
}
void periodic_event_launch(periodic_event_item_t *event);
void periodic_event_setup(periodic_event_item_t *event);
void periodic_event_destroy(periodic_event_item_t *event);
void periodic_event_reschedule(periodic_event_item_t *event);
void periodic_event_enable(periodic_event_item_t *event);
void periodic_event_disable(periodic_event_item_t *event);
#endif /* !defined(TOR_PERIODIC_H) */