mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Add bootstrap tracker subsystem
Add a tracker for bootstrap progress, tracking events related to origin circuit and ORCONN states. This uses the ocirc_event and orconn_event publish-subscribe subsystems. Part of ticket 27167.
This commit is contained in:
parent
b0f974633a
commit
b0ae6a332a
@ -10,6 +10,7 @@
|
||||
|
||||
#include "core/or/ocirc_event_sys.h"
|
||||
#include "core/or/orconn_event_sys.h"
|
||||
#include "feature/control/btrack_sys.h"
|
||||
#include "lib/compress/compress_sys.h"
|
||||
#include "lib/crypt_ops/crypto_sys.h"
|
||||
#include "lib/err/torerr_sys.h"
|
||||
@ -39,6 +40,7 @@ const subsys_fns_t *tor_subsystems[] = {
|
||||
&sys_tortls, /* -50 */
|
||||
&sys_orconn_event, /* -40 */
|
||||
&sys_ocirc_event, /* -39 */
|
||||
&sys_btrack, /* -30 */
|
||||
};
|
||||
|
||||
const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems);
|
||||
|
@ -63,6 +63,10 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/feature/client/dnsserv.c \
|
||||
src/feature/client/entrynodes.c \
|
||||
src/feature/client/transports.c \
|
||||
src/feature/control/btrack.c \
|
||||
src/feature/control/btrack_circuit.c \
|
||||
src/feature/control/btrack_orconn.c \
|
||||
src/feature/control/btrack_orconn_maps.c \
|
||||
src/feature/control/control.c \
|
||||
src/feature/control/control_bootstrap.c \
|
||||
src/feature/control/fmt_serverstatus.c \
|
||||
@ -274,6 +278,10 @@ noinst_HEADERS += \
|
||||
src/feature/client/dnsserv.h \
|
||||
src/feature/client/entrynodes.h \
|
||||
src/feature/client/transports.h \
|
||||
src/feature/control/btrack_circuit.h \
|
||||
src/feature/control/btrack_orconn.h \
|
||||
src/feature/control/btrack_orconn_maps.h \
|
||||
src/feature/control/btrack_sys.h \
|
||||
src/feature/control/control.h \
|
||||
src/feature/control/control_connection_st.h \
|
||||
src/feature/control/fmt_serverstatus.h \
|
||||
|
53
src/feature/control/btrack.c
Normal file
53
src/feature/control/btrack.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack.c
|
||||
* \brief Bootstrap trackers
|
||||
*
|
||||
* Initializes and shuts down the specific bootstrap trackers. These
|
||||
* trackers help the reporting of bootstrap progress by maintaining
|
||||
* state information about various subsystems within tor. When the
|
||||
* correct state changes happen, these trackers emit controller
|
||||
* events.
|
||||
*
|
||||
* These trackers avoid referring directly to the internals of state
|
||||
* objects of other subsystems.
|
||||
*
|
||||
* btrack_circuit.c contains the tracker for origin circuits.
|
||||
*
|
||||
* btrack_orconn.c contains the tracker for OR connections.
|
||||
*
|
||||
* Eventually there will be a tracker for directory downloads as well.
|
||||
**/
|
||||
|
||||
#include "feature/control/btrack_circuit.h"
|
||||
#include "feature/control/btrack_orconn.h"
|
||||
#include "feature/control/btrack_sys.h"
|
||||
#include "lib/subsys/subsys.h"
|
||||
|
||||
static int
|
||||
btrack_init(void)
|
||||
{
|
||||
if (btrack_orconn_init())
|
||||
return -1;
|
||||
if (btrack_circ_init())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
btrack_fini(void)
|
||||
{
|
||||
btrack_orconn_fini();
|
||||
btrack_circ_fini();
|
||||
}
|
||||
|
||||
const subsys_fns_t sys_btrack = {
|
||||
.name = "btrack",
|
||||
.supported = true,
|
||||
.level = -30,
|
||||
.initialize = btrack_init,
|
||||
.shutdown = btrack_fini,
|
||||
};
|
164
src/feature/control/btrack_circuit.c
Normal file
164
src/feature/control/btrack_circuit.c
Normal file
@ -0,0 +1,164 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_circuit.c
|
||||
* \brief Bootstrap tracker for origin circuits
|
||||
*
|
||||
* Track state changes of origin circuits, as published by the circuit
|
||||
* subsystem.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "core/or/ocirc_event.h"
|
||||
|
||||
#include "feature/control/btrack_circuit.h"
|
||||
#include "feature/control/control.h"
|
||||
#include "lib/log/log.h"
|
||||
|
||||
/** Pair of a best origin circuit GID with its state or status */
|
||||
typedef struct btc_best_t {
|
||||
uint32_t gid;
|
||||
int val;
|
||||
} btc_best_t;
|
||||
|
||||
/** GID and state of the best origin circuit we've seen so far */
|
||||
static btc_best_t best_any_state = { 0, -1 };
|
||||
/** GID and state of the best application circuit we've seen so far */
|
||||
static btc_best_t best_ap_state = { 0, -1 };
|
||||
/** GID and status of the best origin circuit we've seen so far */
|
||||
static btc_best_t best_any_evtype = { 0, -1 };
|
||||
/** GID and status of the best application circuit we've seen so far */
|
||||
static btc_best_t best_ap_evtype = { 0, -1 };
|
||||
|
||||
/** Reset cached "best" values */
|
||||
static void
|
||||
btc_reset_bests(void)
|
||||
{
|
||||
best_any_state.gid = best_ap_state.gid = 0;
|
||||
best_any_state.val = best_ap_state.val = -1;
|
||||
best_any_evtype.gid = best_ap_state.gid = 0;
|
||||
best_any_evtype.val = best_ap_evtype.val = -1;
|
||||
}
|
||||
|
||||
/** True if @a state is a "better" origin circuit state than @a best->val */
|
||||
static bool
|
||||
btc_state_better(int state, const btc_best_t *best)
|
||||
{
|
||||
return state > best->val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Definine an ordering on circuit status events
|
||||
*
|
||||
* The CIRC_EVENT_ constants aren't sorted in a useful order, so this
|
||||
* array helps to decode them. This approach depends on the statuses
|
||||
* being nonnegative and dense.
|
||||
**/
|
||||
static int circ_event_order[] = {
|
||||
[CIRC_EVENT_FAILED] = -1,
|
||||
[CIRC_EVENT_CLOSED] = -1,
|
||||
[CIRC_EVENT_LAUNCHED] = 1,
|
||||
[CIRC_EVENT_EXTENDED] = 2,
|
||||
[CIRC_EVENT_BUILT] = 3,
|
||||
};
|
||||
#define N_CIRC_EVENT_ORDER \
|
||||
(sizeof(circ_event_order) / sizeof(circ_event_order[0]))
|
||||
|
||||
/** True if @a state is a "better" origin circuit event status than @a
|
||||
best->val */
|
||||
static bool
|
||||
btc_evtype_better(int state, const btc_best_t *best)
|
||||
{
|
||||
if (state < 0)
|
||||
return false;
|
||||
if (best->val < 0)
|
||||
return true;
|
||||
|
||||
tor_assert(state >= 0 && (unsigned)state < N_CIRC_EVENT_ORDER);
|
||||
tor_assert(best->val >= 0 && (unsigned)best->val < N_CIRC_EVENT_ORDER);
|
||||
return circ_event_order[state] > circ_event_order[best->val];
|
||||
}
|
||||
|
||||
static bool
|
||||
btc_update_state(const ocirc_state_msg_t *msg, btc_best_t *best,
|
||||
const char *type)
|
||||
{
|
||||
if (btc_state_better(msg->state, best)) {
|
||||
log_info(LD_BTRACK, "CIRC BEST_%s state %d->%d gid=%"PRIu32, type,
|
||||
best->val, msg->state, msg->gid);
|
||||
best->gid = msg->gid;
|
||||
best->val = msg->state;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
btc_update_evtype(const ocirc_cevent_msg_t *msg, btc_best_t *best,
|
||||
const char *type)
|
||||
{
|
||||
if (btc_evtype_better(msg->evtype, best)) {
|
||||
log_info(LD_BTRACK, "CIRC BEST_%s evtype %d->%d gid=%"PRIu32, type,
|
||||
best->val, msg->evtype, msg->gid);
|
||||
best->gid = msg->gid;
|
||||
best->val = msg->evtype;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
btc_state_rcvr(const ocirc_state_msg_t *msg)
|
||||
{
|
||||
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" state=%d onehop=%d",
|
||||
msg->gid, msg->state, msg->onehop);
|
||||
|
||||
btc_update_state(msg, &best_any_state, "ANY");
|
||||
if (msg->onehop)
|
||||
return;
|
||||
btc_update_state(msg, &best_ap_state, "AP");
|
||||
}
|
||||
|
||||
static void
|
||||
btc_cevent_rcvr(const ocirc_cevent_msg_t *msg)
|
||||
{
|
||||
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" evtype=%d reason=%d onehop=%d",
|
||||
msg->gid, msg->evtype, msg->reason, msg->onehop);
|
||||
|
||||
btc_update_evtype(msg, &best_any_evtype, "ANY");
|
||||
if (msg->onehop)
|
||||
return;
|
||||
btc_update_evtype(msg, &best_ap_evtype, "AP");
|
||||
}
|
||||
|
||||
static void
|
||||
btc_event_rcvr(const ocirc_event_msg_t *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
case OCIRC_MSGTYPE_STATE:
|
||||
return btc_state_rcvr(&msg->u.state);
|
||||
case OCIRC_MSGTYPE_CHAN:
|
||||
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" chan=%"PRIu64" onehop=%d",
|
||||
msg->u.chan.gid, msg->u.chan.chan, msg->u.chan.onehop);
|
||||
break;
|
||||
case OCIRC_MSGTYPE_CEVENT:
|
||||
return btc_cevent_rcvr(&msg->u.cevent);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
btrack_circ_init(void)
|
||||
{
|
||||
ocirc_event_subscribe(btc_event_rcvr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
btrack_circ_fini(void)
|
||||
{
|
||||
btc_reset_bests();
|
||||
}
|
15
src/feature/control/btrack_circuit.h
Normal file
15
src/feature/control/btrack_circuit.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_circuit.h
|
||||
* \brief Header file for btrack_circuit.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_BTRACK_CIRCUIT_H
|
||||
#define TOR_BTRACK_CIRCUIT_H
|
||||
|
||||
int btrack_circ_init(void);
|
||||
void btrack_circ_fini(void);
|
||||
|
||||
#endif /* defined(TOR_BTRACK_CIRCUIT_H) */
|
196
src/feature/control/btrack_orconn.c
Normal file
196
src/feature/control/btrack_orconn.c
Normal file
@ -0,0 +1,196 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_orconn.c
|
||||
* \brief Bootstrap tracker for OR connections
|
||||
*
|
||||
* Track state changes of OR connections, as published by the
|
||||
* connection subsystem. Also track circuit launch events, because
|
||||
* they're one of the few ways to discover the association between a
|
||||
* channel (and OR connection) and a circuit.
|
||||
*
|
||||
* We track all OR connections that we receive events for, whether or
|
||||
* not they're carrying origin circuits. (An OR connection might
|
||||
* carry origin circuits only after we first find out about that
|
||||
* connection.)
|
||||
*
|
||||
* All origin ORCONN events update the "any" state variables, while
|
||||
* only application ORCONN events update the "ap" state variables (and
|
||||
* also update the "any") variables.
|
||||
*
|
||||
* We do this because we want to report the first increments of
|
||||
* connection progress as the earliest bootstrap phases. This results
|
||||
* in a better user experience because failures here translate into
|
||||
* zero or very small amounts of displayed progress, instead of
|
||||
* progress stuck near completion. The first connection to a relay
|
||||
* might be a one-hop circuit for directory lookups, or it might be a
|
||||
* connection for an application circuit because we already have
|
||||
* enough directory info to build an application circuit.
|
||||
**/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
#define BTRACK_ORCONN_PRIVATE
|
||||
|
||||
#include "core/or/ocirc_event.h"
|
||||
#include "core/or/orconn_event.h"
|
||||
#include "feature/control/btrack_orconn.h"
|
||||
#include "feature/control/btrack_orconn_maps.h"
|
||||
#include "lib/log/log.h"
|
||||
|
||||
/** Pair of a best ORCONN GID and with its state */
|
||||
typedef struct bto_best_t {
|
||||
uint64_t gid;
|
||||
int state;
|
||||
} bto_best_t;
|
||||
|
||||
/** GID and state of the best ORCONN we've seen so far */
|
||||
static bto_best_t best_any = { 0, -1 };
|
||||
/** GID and state of the best application circuit ORCONN we've seen so far */
|
||||
static bto_best_t best_ap = { 0, -1 };
|
||||
|
||||
/**
|
||||
* Update a cached state of a best ORCONN progress we've seen so far.
|
||||
*
|
||||
* Return true if the new state is better than the old.
|
||||
**/
|
||||
static bool
|
||||
bto_update_best(const bt_orconn_t *bto, bto_best_t *best, const char *type)
|
||||
{
|
||||
if (bto->state < best->state)
|
||||
return false;
|
||||
best->gid = bto->gid;
|
||||
if (bto->state > best->state) {
|
||||
log_info(LD_BTRACK, "ORCONN BEST_%s state %d->%d gid=%"PRIu64, type,
|
||||
best->state, bto->state, bto->gid);
|
||||
best->state = bto->state;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cached states of best ORCONN progress we've seen
|
||||
*
|
||||
* Only update the application ORCONN state if we know it's carrying
|
||||
* an application circuit.
|
||||
**/
|
||||
static void
|
||||
bto_update_bests(const bt_orconn_t *bto)
|
||||
{
|
||||
tor_assert(bto->is_orig);
|
||||
|
||||
bto_update_best(bto, &best_any, "ANY");
|
||||
if (!bto->is_onehop)
|
||||
bto_update_best(bto, &best_ap, "AP");
|
||||
}
|
||||
|
||||
/** Reset cached "best" values */
|
||||
static void
|
||||
bto_reset_bests(void)
|
||||
{
|
||||
best_any.gid = best_ap.gid = 0;
|
||||
best_any.state = best_ap.state = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cached states of ORCONNs from the incoming message. This
|
||||
* message comes from code in connection_or.c.
|
||||
**/
|
||||
static void
|
||||
bto_state_rcvr(const orconn_state_msg_t *msg)
|
||||
{
|
||||
bt_orconn_t *bto;
|
||||
|
||||
bto = bto_find_or_new(msg->gid, msg->chan);
|
||||
log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" chan=%"PRIu64
|
||||
" proxy_type=%d state=%d",
|
||||
msg->gid, msg->chan, msg->proxy_type, msg->state);
|
||||
bto->proxy_type = msg->proxy_type;
|
||||
bto->state = msg->state;
|
||||
if (bto->is_orig)
|
||||
bto_update_bests(bto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cached ORCONN state if we get an incoming message saying
|
||||
* the ORCONN is failed or closed. This message comes from code in
|
||||
* control.c.
|
||||
**/
|
||||
static void
|
||||
bto_status_rcvr(const orconn_status_msg_t *msg)
|
||||
{
|
||||
switch (msg->status) {
|
||||
case OR_CONN_EVENT_FAILED:
|
||||
case OR_CONN_EVENT_CLOSED:
|
||||
log_info(LD_BTRACK, "ORCONN DELETE gid=%"PRIu64" status=%d reason=%d",
|
||||
msg->gid, msg->status, msg->reason);
|
||||
return bto_delete(msg->gid);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatch to individual ORCONN message handlers */
|
||||
static void
|
||||
bto_event_rcvr(const orconn_event_msg_t *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
case ORCONN_MSGTYPE_STATE:
|
||||
return bto_state_rcvr(&msg->u.state);
|
||||
case ORCONN_MSGTYPE_STATUS:
|
||||
return bto_status_rcvr(&msg->u.status);
|
||||
default:
|
||||
tor_assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a cached ORCONN state for a newly launched
|
||||
* connection, including whether it's launched by an origin circuit
|
||||
* and whether it's a one-hop circuit.
|
||||
**/
|
||||
static void
|
||||
bto_chan_rcvr(const ocirc_event_msg_t *msg)
|
||||
{
|
||||
bt_orconn_t *bto;
|
||||
|
||||
/* Ignore other kinds of origin circuit events; we don't need them */
|
||||
if (msg->type != OCIRC_MSGTYPE_CHAN)
|
||||
return;
|
||||
|
||||
bto = bto_find_or_new(0, msg->u.chan.chan);
|
||||
if (!bto->is_orig || (bto->is_onehop && !msg->u.chan.onehop)) {
|
||||
log_debug(LD_BTRACK, "ORCONN LAUNCH chan=%"PRIu64" onehop=%d",
|
||||
msg->u.chan.chan, msg->u.chan.onehop);
|
||||
}
|
||||
bto->is_orig = true;
|
||||
if (!msg->u.chan.onehop)
|
||||
bto->is_onehop = false;
|
||||
bto_update_bests(bto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the hash maps and subscribe to ORCONN and origin
|
||||
* circuit events.
|
||||
**/
|
||||
int
|
||||
btrack_orconn_init(void)
|
||||
{
|
||||
bto_init_maps();
|
||||
orconn_event_subscribe(bto_event_rcvr);
|
||||
ocirc_event_subscribe(bto_chan_rcvr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Clear the hash maps and reset the "best" states */
|
||||
void
|
||||
btrack_orconn_fini(void)
|
||||
{
|
||||
bto_clear_maps();
|
||||
bto_reset_bests();
|
||||
}
|
38
src/feature/control/btrack_orconn.h
Normal file
38
src/feature/control/btrack_orconn.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_orconn.h
|
||||
* \brief Header file for btrack_orconn.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_BTRACK_ORCONN_H
|
||||
#define TOR_BTRACK_ORCONN_H
|
||||
|
||||
#ifdef BTRACK_ORCONN_PRIVATE
|
||||
|
||||
#include "ht.h"
|
||||
|
||||
/**
|
||||
* Structure for tracking OR connection states
|
||||
*
|
||||
* This gets linked into two hash maps: one with connection IDs, and
|
||||
* another with channel IDs.
|
||||
**/
|
||||
typedef struct bt_orconn_t {
|
||||
HT_ENTRY(bt_orconn_t) node; /**< Hash map entry indexed by gid */
|
||||
HT_ENTRY(bt_orconn_t) chan_node; /**< Hash map entry indexed by channel ID */
|
||||
uint64_t gid; /**< Global ID of this ORCONN */
|
||||
uint64_t chan; /**< Channel ID, if known */
|
||||
int proxy_type; /**< Proxy type */
|
||||
uint8_t state; /**< State of this ORCONN */
|
||||
bool is_orig; /**< Does this carry an origin circuit? */
|
||||
bool is_onehop; /**< Is this for a one-hop circuit? */
|
||||
} bt_orconn_t;
|
||||
|
||||
#endif /* defined(BTRACK_ORCONN_PRIVATE) */
|
||||
|
||||
int btrack_orconn_init(void);
|
||||
void btrack_orconn_fini(void);
|
||||
|
||||
#endif /* defined(TOR_BTRACK_ORCONN_H) */
|
223
src/feature/control/btrack_orconn_maps.c
Normal file
223
src/feature/control/btrack_orconn_maps.c
Normal file
@ -0,0 +1,223 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_orconn_maps.c
|
||||
* \brief Hash map implementation for btrack_orconn.c
|
||||
*
|
||||
* These functions manipulate the hash maps that contain bt_orconn
|
||||
* objects.
|
||||
**/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "core/or/or.h"
|
||||
|
||||
#include "ht.h"
|
||||
#include "siphash.h"
|
||||
|
||||
#define BTRACK_ORCONN_PRIVATE
|
||||
|
||||
#include "feature/control/btrack_orconn.h"
|
||||
#include "feature/control/btrack_orconn_maps.h"
|
||||
#include "lib/log/log.h"
|
||||
|
||||
static inline unsigned int
|
||||
bto_gid_hash_(bt_orconn_t *elm)
|
||||
{
|
||||
return (unsigned)siphash24g(&elm->gid, sizeof(elm->gid));
|
||||
}
|
||||
|
||||
static inline int
|
||||
bto_gid_eq_(bt_orconn_t *a, bt_orconn_t *b)
|
||||
{
|
||||
return a->gid == b->gid;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
bto_chan_hash_(bt_orconn_t *elm)
|
||||
{
|
||||
return (unsigned)siphash24g(&elm->chan, sizeof(elm->chan));
|
||||
}
|
||||
|
||||
static inline int
|
||||
bto_chan_eq_(bt_orconn_t *a, bt_orconn_t *b)
|
||||
{
|
||||
return a->chan == b->chan;
|
||||
}
|
||||
|
||||
HT_HEAD(bto_gid_ht, bt_orconn_t);
|
||||
HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_)
|
||||
HT_GENERATE2(bto_gid_ht, bt_orconn_t, node,
|
||||
bto_gid_hash_, bto_gid_eq_, 0.6,
|
||||
tor_reallocarray_, tor_free_)
|
||||
static struct bto_gid_ht *bto_gid_map;
|
||||
|
||||
HT_HEAD(bto_chan_ht, bt_orconn_t);
|
||||
HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_, bto_chan_eq_)
|
||||
HT_GENERATE2(bto_chan_ht, bt_orconn_t, chan_node,
|
||||
bto_chan_hash_, bto_chan_eq_, 0.6,
|
||||
tor_reallocarray_, tor_free_)
|
||||
static struct bto_chan_ht *bto_chan_map;
|
||||
|
||||
/** Clear the GID hash map, freeing any bt_orconn_t objects that become
|
||||
* unreferenced */
|
||||
static void
|
||||
bto_gid_clear_map(void)
|
||||
{
|
||||
bt_orconn_t **elt, **next, *c;
|
||||
|
||||
for (elt = HT_START(bto_gid_ht, bto_gid_map);
|
||||
elt;
|
||||
elt = next) {
|
||||
c = *elt;
|
||||
next = HT_NEXT_RMV(bto_gid_ht, bto_gid_map, elt);
|
||||
|
||||
c->gid = 0;
|
||||
/* Don't delete if chan ID isn't zero: it's still in the chan hash map */
|
||||
if (!c->chan)
|
||||
tor_free(c);
|
||||
}
|
||||
HT_CLEAR(bto_gid_ht, bto_gid_map);
|
||||
tor_free(bto_gid_map);
|
||||
}
|
||||
|
||||
/** Clear the chan ID hash map, freeing any bt_orconn_t objects that
|
||||
* become unreferenced */
|
||||
static void
|
||||
bto_chan_clear_map(void)
|
||||
{
|
||||
bt_orconn_t **elt, **next, *c;
|
||||
|
||||
for (elt = HT_START(bto_chan_ht, bto_chan_map);
|
||||
elt;
|
||||
elt = next) {
|
||||
c = *elt;
|
||||
next = HT_NEXT_RMV(bto_chan_ht, bto_chan_map, elt);
|
||||
|
||||
c->chan = 0;
|
||||
/* Don't delete if GID isn't zero, it's still in the GID hash map */
|
||||
if (!c->gid)
|
||||
tor_free(c);
|
||||
}
|
||||
HT_CLEAR(bto_chan_ht, bto_chan_map);
|
||||
tor_free(bto_chan_map);
|
||||
}
|
||||
|
||||
/** Delete a bt_orconn from the hash maps by GID */
|
||||
void
|
||||
bto_delete(uint64_t gid)
|
||||
{
|
||||
bt_orconn_t key, *bto;
|
||||
|
||||
key.gid = gid;
|
||||
key.chan = 0;
|
||||
bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
|
||||
if (!bto) {
|
||||
/* The orconn might be unregistered because it's an EXT_OR_CONN? */
|
||||
log_debug(LD_BTRACK, "tried to delete unregistered ORCONN gid=%"PRIu64,
|
||||
gid);
|
||||
return;
|
||||
}
|
||||
HT_REMOVE(bto_gid_ht, bto_gid_map, &key);
|
||||
if (bto->chan) {
|
||||
key.chan = bto->chan;
|
||||
HT_REMOVE(bto_chan_ht, bto_chan_map, &key);
|
||||
}
|
||||
tor_free(bto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for bto_find_or_new().
|
||||
*
|
||||
* Update GID and chan ID of an existing bt_orconn object if needed,
|
||||
* given a search key previously used within bto_find_or_new().
|
||||
**/
|
||||
static bt_orconn_t *
|
||||
bto_update(bt_orconn_t *bto, const bt_orconn_t *key)
|
||||
{
|
||||
/* ORCONN GIDs shouldn't change once assigned */
|
||||
tor_assert(!bto->gid || !key->gid || bto->gid == key->gid);
|
||||
if (!bto->gid && key->gid) {
|
||||
/* Got a gid when we didn't already have one; insert into gid map */
|
||||
log_debug(LD_BTRACK, "ORCONN chan=%"PRIu64" newgid=%"PRIu64, key->chan,
|
||||
key->gid);
|
||||
bto->gid = key->gid;
|
||||
HT_INSERT(bto_gid_ht, bto_gid_map, bto);
|
||||
}
|
||||
/* association of ORCONN with channel shouldn't change */
|
||||
tor_assert(!bto->chan || !key->chan || bto->chan == key->chan);
|
||||
if (!bto->chan && key->chan) {
|
||||
/* Got a chan when we didn't already have one; insert into chan map */
|
||||
log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" newchan=%"PRIu64,
|
||||
bto->gid, key->chan);
|
||||
bto->chan = key->chan;
|
||||
HT_INSERT(bto_chan_ht, bto_chan_map, bto);
|
||||
}
|
||||
return bto;
|
||||
}
|
||||
|
||||
/** Helper for bto_find_or_new() */
|
||||
static bt_orconn_t *
|
||||
bto_new(const bt_orconn_t *key)
|
||||
{
|
||||
struct bt_orconn_t *bto = tor_malloc(sizeof(*bto));
|
||||
|
||||
bto->gid = key->gid;
|
||||
bto->chan = key->chan;
|
||||
bto->state = 0;
|
||||
bto->proxy_type = 0;
|
||||
bto->is_orig = false;
|
||||
bto->is_onehop = true;
|
||||
|
||||
if (bto->gid)
|
||||
HT_INSERT(bto_gid_ht, bto_gid_map, bto);
|
||||
if (bto->chan)
|
||||
HT_INSERT(bto_chan_ht, bto_chan_map, bto);
|
||||
|
||||
return bto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new bt_orconn with the given GID and chan ID, or update
|
||||
* the GID and chan ID if one already exists.
|
||||
*
|
||||
* Return the found or allocated bt_orconn.
|
||||
**/
|
||||
bt_orconn_t *
|
||||
bto_find_or_new(uint64_t gid, uint64_t chan)
|
||||
{
|
||||
bt_orconn_t key, *bto = NULL;
|
||||
|
||||
tor_assert(gid || chan);
|
||||
key.gid = gid;
|
||||
key.chan = chan;
|
||||
if (key.gid)
|
||||
bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
|
||||
if (!bto && key.chan) {
|
||||
/* Not found by GID; look up by chan ID */
|
||||
bto = HT_FIND(bto_chan_ht, bto_chan_map, &key);
|
||||
}
|
||||
if (bto)
|
||||
return bto_update(bto, &key);
|
||||
else
|
||||
return bto_new(&key);
|
||||
}
|
||||
|
||||
/** Initialize the hash maps */
|
||||
void
|
||||
bto_init_maps(void)
|
||||
{
|
||||
bto_gid_map = tor_malloc(sizeof(*bto_gid_map));
|
||||
HT_INIT(bto_gid_ht, bto_gid_map);
|
||||
bto_chan_map = tor_malloc(sizeof(*bto_chan_map));
|
||||
HT_INIT(bto_chan_ht, bto_chan_map);
|
||||
}
|
||||
|
||||
/** Clear the hash maps, freeing all associated storage */
|
||||
void
|
||||
bto_clear_maps(void)
|
||||
{
|
||||
bto_gid_clear_map();
|
||||
bto_chan_clear_map();
|
||||
}
|
17
src/feature/control/btrack_orconn_maps.h
Normal file
17
src/feature/control/btrack_orconn_maps.h
Normal file
@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_orconn_maps.h
|
||||
* \brief Header file for btrack_orconn_maps.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_BTRACK_ORCONN_MAPS_H
|
||||
|
||||
void bto_delete(uint64_t);
|
||||
bt_orconn_t *bto_find_or_new(uint64_t, uint64_t);
|
||||
|
||||
void bto_init_maps(void);
|
||||
void bto_clear_maps(void);
|
||||
|
||||
#endif /* defined(TOR_BTRACK_ORCONN_MAPS_H) */
|
14
src/feature/control/btrack_sys.h
Normal file
14
src/feature/control/btrack_sys.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file btrack_sys.h
|
||||
* \brief Declare subsystem object for the bootstrap tracker susbystem.
|
||||
**/
|
||||
|
||||
#ifndef TOR_BTRACK_SYS_H
|
||||
#define TOR_BTRACK_SYS_H
|
||||
|
||||
extern const struct subsys_fns_t sys_btrack;
|
||||
|
||||
#endif /* defined(TOR_BTRACK_SYS_H) */
|
Loading…
Reference in New Issue
Block a user