📄 rephist.c
字号:
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char rephist_c_id[] =
"$Id$";
/**
* \file rephist.c
* \brief Basic history and "reputation" functionality to remember
* which servers have worked in the past, how much bandwidth we've
* been using, which ports we tend to want, and so on.
**/
#include "or.h"
#include "ht.h"
static void bw_arrays_init(void);
static void predicted_ports_init(void);
static void hs_usage_init(void);
/** Total number of bytes currently allocated in fields used by rephist.c. */
uint64_t rephist_total_alloc=0;
/** Number of or_history_t objects currently allocated. */
uint32_t rephist_total_num=0;
/** If the total weighted run count of all runs for a router ever falls
* below this amount, the router can be treated as having 0 MTBF. */
#define STABILITY_EPSILON 0.0001
/** Value by which to discount all old intervals for MTBF purposses. This
* is compounded every STABILITY_INTERVAL. */
#define STABILITY_ALPHA 0.95
/** Interval at which to discount all old intervals for MTBF purposes. */
#define STABILITY_INTERVAL (12*60*60)
/* (This combination of ALPHA, INTERVAL, and EPSILON makes it so that an
* interval that just ended counts twice as much as one that ended a week ago,
* 20X as much as one that ended a month ago, and routers that have had no
* uptime data for about half a year will get forgotten.) */
/** History of an OR-\>OR link. */
typedef struct link_history_t {
/** When did we start tracking this list? */
time_t since;
/** When did we most recently note a change to this link */
time_t changed;
/** How many times did extending from OR1 to OR2 succeed? */
unsigned long n_extend_ok;
/** How many times did extending from OR1 to OR2 fail? */
unsigned long n_extend_fail;
} link_history_t;
/** History of an OR. */
typedef struct or_history_t {
/** When did we start tracking this OR? */
time_t since;
/** When did we most recently note a change to this OR? */
time_t changed;
/** How many times did we successfully connect? */
unsigned long n_conn_ok;
/** How many times did we try to connect and fail?*/
unsigned long n_conn_fail;
/** How many seconds have we been connected to this OR before
* 'up_since'? */
unsigned long uptime;
/** How many seconds have we been unable to connect to this OR before
* 'down_since'? */
unsigned long downtime;
/** If nonzero, we have been connected since this time. */
time_t up_since;
/** If nonzero, we have been unable to connect since this time. */
time_t down_since;
/* === For MTBF tracking: */
/** Weighted sum total of all times that this router has been online.
*/
unsigned long weighted_run_length;
/** If the router is now online (according to stability-checking rules),
* when did it come online? */
time_t start_of_run;
/** Sum of weights for runs in weighted_run_length. */
double total_run_weights;
/* === For fractional uptime tracking: */
time_t start_of_downtime;
unsigned long weighted_uptime;
unsigned long total_weighted_time;
/** Map from hex OR2 identity digest to a link_history_t for the link
* from this OR to OR2. */
digestmap_t *link_history_map;
} or_history_t;
/** When did we last multiply all routers' weighted_run_length and
* total_run_weights by STABILITY_ALPHA? */
static time_t stability_last_downrated = 0;
/** */
static time_t started_tracking_stability = 0;
/** Map from hex OR identity digest to or_history_t. */
static digestmap_t *history_map = NULL;
/** Return the or_history_t for the OR with identity digest <b>id</b>,
* creating it if necessary. */
static or_history_t *
get_or_history(const char* id)
{
or_history_t *hist;
if (tor_mem_is_zero(id, DIGEST_LEN))
return NULL;
hist = digestmap_get(history_map, id);
if (!hist) {
hist = tor_malloc_zero(sizeof(or_history_t));
rephist_total_alloc += sizeof(or_history_t);
rephist_total_num++;
hist->link_history_map = digestmap_new();
hist->since = hist->changed = time(NULL);
digestmap_set(history_map, id, hist);
}
return hist;
}
/** Return the link_history_t for the link from the first named OR to
* the second, creating it if necessary. (ORs are identified by
* identity digest.)
*/
static link_history_t *
get_link_history(const char *from_id, const char *to_id)
{
or_history_t *orhist;
link_history_t *lhist;
orhist = get_or_history(from_id);
if (!orhist)
return NULL;
if (tor_mem_is_zero(to_id, DIGEST_LEN))
return NULL;
lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id);
if (!lhist) {
lhist = tor_malloc_zero(sizeof(link_history_t));
rephist_total_alloc += sizeof(link_history_t);
lhist->since = lhist->changed = time(NULL);
digestmap_set(orhist->link_history_map, to_id, lhist);
}
return lhist;
}
/** Helper: free storage held by a single link history entry. */
static void
_free_link_history(void *val)
{
rephist_total_alloc -= sizeof(link_history_t);
tor_free(val);
}
/** Helper: free storage held by a single OR history entry. */
static void
free_or_history(void *_hist)
{
or_history_t *hist = _hist;
digestmap_free(hist->link_history_map, _free_link_history);
rephist_total_alloc -= sizeof(or_history_t);
rephist_total_num--;
tor_free(hist);
}
/** Update an or_history_t object <b>hist</b> so that its uptime/downtime
* count is up-to-date as of <b>when</b>.
*/
static void
update_or_history(or_history_t *hist, time_t when)
{
tor_assert(hist);
if (hist->up_since) {
tor_assert(!hist->down_since);
hist->uptime += (when - hist->up_since);
hist->up_since = when;
} else if (hist->down_since) {
hist->downtime += (when - hist->down_since);
hist->down_since = when;
}
}
/** Initialize the static data structures for tracking history. */
void
rep_hist_init(void)
{
history_map = digestmap_new();
bw_arrays_init();
predicted_ports_init();
hs_usage_init();
}
/** Helper: note that we are no longer connected to the router with history
* <b>hist</b>. If <b>failed</b>, the connection failed; otherwise, it was
* closed correctly. */
static void
mark_or_down(or_history_t *hist, time_t when, int failed)
{
if (hist->up_since) {
hist->uptime += (when - hist->up_since);
hist->up_since = 0;
}
if (failed && !hist->down_since) {
hist->down_since = when;
}
}
/** Helper: note that we are connected to the router with history
* <b>hist</b>. */
static void
mark_or_up(or_history_t *hist, time_t when)
{
if (hist->down_since) {
hist->downtime += (when - hist->down_since);
hist->down_since = 0;
}
if (!hist->up_since) {
hist->up_since = when;
}
}
/** Remember that an attempt to connect to the OR with identity digest
* <b>id</b> failed at <b>when</b>.
*/
void
rep_hist_note_connect_failed(const char* id, time_t when)
{
or_history_t *hist;
hist = get_or_history(id);
if (!hist)
return;
++hist->n_conn_fail;
mark_or_down(hist, when, 1);
hist->changed = when;
}
/** Remember that an attempt to connect to the OR with identity digest
* <b>id</b> succeeded at <b>when</b>.
*/
void
rep_hist_note_connect_succeeded(const char* id, time_t when)
{
or_history_t *hist;
hist = get_or_history(id);
if (!hist)
return;
++hist->n_conn_ok;
mark_or_up(hist, when);
hist->changed = when;
}
/** Remember that we intentionally closed our connection to the OR
* with identity digest <b>id</b> at <b>when</b>.
*/
void
rep_hist_note_disconnect(const char* id, time_t when)
{
or_history_t *hist;
hist = get_or_history(id);
if (!hist)
return;
mark_or_down(hist, when, 0);
hist->changed = when;
}
/** Remember that our connection to the OR with identity digest
* <b>id</b> had an error and stopped working at <b>when</b>.
*/
void
rep_hist_note_connection_died(const char* id, time_t when)
{
or_history_t *hist;
if (!id) {
/* If conn has no identity, it didn't complete its handshake, or something
* went wrong. Ignore it.
*/
return;
}
hist = get_or_history(id);
if (!hist)
return;
mark_or_down(hist, when, 1);
hist->changed = when;
}
/** We have just decided that this router is reachable, meaning
* we will give it a "Running" flag for the next while. */
void
rep_hist_note_router_reachable(const char *id, time_t when)
{
or_history_t *hist = get_or_history(id);
if (!started_tracking_stability)
started_tracking_stability = time(NULL);
if (hist && !hist->start_of_run) {
hist->start_of_run = when;
}
if (hist && hist->start_of_downtime) {
long down_length = when - hist->start_of_downtime;
hist->total_weighted_time += down_length;
hist->start_of_downtime = 0;
}
}
/** We have just decided that this router is unreachable, meaning
* we are taking away its "Running" flag. */
void
rep_hist_note_router_unreachable(const char *id, time_t when)
{
or_history_t *hist = get_or_history(id);
if (!started_tracking_stability)
started_tracking_stability = time(NULL);
if (hist && hist->start_of_run) {
/*XXXX We could treat failed connections differently from failed
* connect attempts. */
long run_length = when - hist->start_of_run;
hist->weighted_run_length += run_length;
hist->total_run_weights += 1.0;
hist->start_of_run = 0;
hist->weighted_uptime += run_length;
hist->total_weighted_time += run_length;
}
if (hist && !hist->start_of_downtime) {
hist->start_of_downtime = when;
}
}
/** Helper: Discount all old MTBF data, if it is time to do so. Return
* the time at which we should next discount MTBF data. */
time_t
rep_hist_downrate_old_runs(time_t now)
{
digestmap_iter_t *orhist_it;
const char *digest1;
or_history_t *hist;
void *hist_p;
double alpha = 1.0;
if (!history_map)
history_map = digestmap_new();
if (!stability_last_downrated)
stability_last_downrated = now;
if (stability_last_downrated + STABILITY_INTERVAL > now)
return stability_last_downrated + STABILITY_INTERVAL;
/* Okay, we should downrate the data. By how much? */
while (stability_last_downrated + STABILITY_INTERVAL < now) {
stability_last_downrated += STABILITY_INTERVAL;
alpha *= STABILITY_ALPHA;
}
/* Multiply every w_r_l, t_r_w pair by alpha. */
for (orhist_it = digestmap_iter_init(history_map);
!digestmap_iter_done(orhist_it);
orhist_it = digestmap_iter_next(history_map,orhist_it)) {
digestmap_iter_get(orhist_it, &digest1, &hist_p);
hist = hist_p;
hist->weighted_run_length =
(unsigned long)(hist->weighted_run_length * alpha);
hist->total_run_weights *= alpha;
hist->weighted_uptime = (unsigned long)(hist->weighted_uptime * alpha);
hist->total_weighted_time = (unsigned long)
(hist->total_weighted_time * alpha);
}
return stability_last_downrated + STABILITY_INTERVAL;
}
/** Helper: Return the weighted MTBF of the router with history <b>hist</b>. */
static double
get_stability(or_history_t *hist, time_t when)
{
unsigned long total = hist->weighted_run_length;
double total_weights = hist->total_run_weights;
if (hist->start_of_run) {
/* We're currently in a run. Let total and total_weights hold the values
* they would hold if the current run were to end now. */
total += (when-hist->start_of_run);
total_weights += 1.0;
}
if (total_weights < STABILITY_EPSILON) {
/* Round down to zero, and avoid divide-by-zero. */
return 0.0;
}
return total / total_weights;
}
/** Return the total amount of time we've been observing, with each run of
* time downrated by the appropriate factor. */
static long
get_total_weighted_time(or_history_t *hist, time_t when)
{
long total = hist->total_weighted_time;
if (hist->start_of_run) {
total += (when - hist->start_of_run);
} else if (hist->start_of_downtime) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -