mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 15:43:32 +01:00
Merge remote branch 'public/cbt-status'
Conflicts: ChangeLog
This commit is contained in:
commit
0eb03bc6dd
18
ChangeLog
18
ChangeLog
@ -22,7 +22,9 @@ Changes in version 0.2.2.9-alpha - 2010-??-??
|
||||
"memcpyfail".
|
||||
- Make the DNSPort option work with libevent 2.x. Don't alter the
|
||||
behaviour for libevent 1.x. Fixes bug 1143. Found by SwissTorExit.
|
||||
|
||||
- Emit an GUARD DROPPED event for a case we missed.
|
||||
- Make more fields in the controller protocol case-insensitive as
|
||||
documented in control-spec.txt.
|
||||
|
||||
o Code simplifications and refactoring:
|
||||
- Generate our manpage and HTML documentation using Asciidoc. This
|
||||
@ -35,6 +37,20 @@ Changes in version 0.2.2.9-alpha - 2010-??-??
|
||||
AUTHORS file had its content merged into the people page on the
|
||||
website. The roadmaps and design doc can now be found in the
|
||||
projects directory in svn.
|
||||
- Enabled various circuit build timeout constants to be controlled
|
||||
by consensus parameters. Also set better defaults for these
|
||||
parameters based on experimentation on broadband and simulated
|
||||
high latency links.
|
||||
|
||||
o Minor features:
|
||||
- The 'EXTENDCIRCUIT' control port command can now be used with
|
||||
a circ id of 0 and no path. This will cause Tor to build a new
|
||||
'fast' general purpose circuit using its own path selection
|
||||
algorithms.
|
||||
- Added a BUILDTIMEOUT_SET control port event to describe changes
|
||||
to the circuit build timeout.
|
||||
- Future-proof the controller protocol a bit by ignoring keyword
|
||||
arguments we do not recognize.
|
||||
|
||||
o Removed features:
|
||||
- Stop shipping parts of the website and the design paper in the
|
||||
|
@ -219,7 +219,7 @@
|
||||
"INFO" / "NOTICE" / "WARN" / "ERR" / "NEWDESC" / "ADDRMAP" /
|
||||
"AUTHDIR_NEWDESCS" / "DESCCHANGED" / "STATUS_GENERAL" /
|
||||
"STATUS_CLIENT" / "STATUS_SERVER" / "GUARD" / "NS" / "STREAM_BW" /
|
||||
"CLIENTS_SEEN" / "NEWCONSENSUS"
|
||||
"CLIENTS_SEEN" / "NEWCONSENSUS" / "BUILDTIMEOUT_SET"
|
||||
|
||||
Any events *not* listed in the SETEVENTS line are turned off; thus, sending
|
||||
SETEVENTS with an empty body turns off all event reporting.
|
||||
@ -606,15 +606,20 @@
|
||||
3.10. EXTENDCIRCUIT
|
||||
|
||||
Sent from the client to the server. The format is:
|
||||
"EXTENDCIRCUIT" SP CircuitID SP
|
||||
ServerSpec *("," ServerSpec)
|
||||
[SP "purpose=" Purpose] CRLF
|
||||
"EXTENDCIRCUIT" SP CircuitID
|
||||
[SP ServerSpec *("," ServerSpec)
|
||||
SP "purpose=" Purpose] CRLF
|
||||
|
||||
This request takes one of two forms: either the CircuitID is zero, in
|
||||
which case it is a request for the server to build a new circuit according
|
||||
to the specified path, or the CircuitID is nonzero, in which case it is a
|
||||
request for the server to extend an existing circuit with that ID according
|
||||
to the specified path.
|
||||
which case it is a request for the server to build a new circuit,
|
||||
or the CircuitID is nonzero, in which case it is a request for the
|
||||
server to extend an existing circuit with that ID according to the
|
||||
specified path.
|
||||
|
||||
If the CircuitID is 0, the controller has the option of providing
|
||||
a path for Tor to use to build the circuit. If it does not provide
|
||||
a path, Tor will select one automatically from high capacity nodes
|
||||
according to path-spec.txt.
|
||||
|
||||
If CircuitID is 0 and "purpose=" is specified, then the circuit's
|
||||
purpose is set. Two choices are recognized: "general" and
|
||||
@ -1656,6 +1661,38 @@
|
||||
|
||||
[First added in 0.2.1.13-alpha]
|
||||
|
||||
4.1.16. New circuit buildtime has been set.
|
||||
|
||||
The syntax is:
|
||||
"650" SP "BUILDTIMEOUT_SET" SP Type SP "TOTAL_TIMES=" Total SP
|
||||
"TIMEOUT_MS=" Timeout SP "XM=" Xm SP "ALPHA=" Alpha SP
|
||||
"CUTOFF_QUANTILE=" Quantile CRLF
|
||||
Type = "COMPUTED" / "RESET" / "SUSPENDED" / "DISCARD" / "RESUME"
|
||||
Total = Integer count of timeouts stored
|
||||
Timeout = Integer timeout in milliseconds
|
||||
Xm = Estimated integer Pareto parameter Xm in milliseconds
|
||||
Alpha = Estimated floating point Paredo paremter alpha
|
||||
Quantile = Floating point CDF quantile cutoff point for this timeout
|
||||
|
||||
A new circuit build timeout time has been set. If Type is "COMPUTED",
|
||||
Tor has computed the value based on historical data. If Type is "RESET",
|
||||
initialization or drastic network changes have caused Tor to reset
|
||||
the timeout back to the default, to relearn again. If Type is
|
||||
"SUSPENDED", Tor has detected a loss of network connectivity and has
|
||||
temporarily changed the timeout value to the default until the network
|
||||
recovers. If type is "DISCARD", Tor has decided to discard timeout
|
||||
values that likely happened while the network was down. If type is
|
||||
"RESUME", Tor has decided to resume timeout calculation.
|
||||
|
||||
The Total value is the count of circuit build times Tor used in
|
||||
computing this value. It is capped internally at the maximum number
|
||||
of build times Tor stores (NCIRCUITS_TO_OBSERVE).
|
||||
|
||||
The Timeout itself is provided in milliseconds. Internally, Tor rounds
|
||||
this value to the nearest second before using it.
|
||||
|
||||
[First added in 0.2.2.7-alpha]
|
||||
|
||||
5. Implementation notes
|
||||
|
||||
5.1. Authentication
|
||||
|
@ -79,6 +79,111 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
|
||||
|
||||
static void entry_guards_changed(void);
|
||||
|
||||
static int32_t
|
||||
circuit_build_times_max_timeouts(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtmaxtimeouts",
|
||||
CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
circuit_build_times_min_circs_to_observe(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
|
||||
CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE);
|
||||
return num;
|
||||
}
|
||||
|
||||
double
|
||||
circuit_build_times_quantile_cutoff(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtquantile",
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF);
|
||||
return num/100.0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
circuit_build_times_test_frequency(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
|
||||
CBT_DEFAULT_TEST_FREQUENCY);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
circuit_build_times_min_timeout(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
|
||||
CBT_DEFAULT_TIMEOUT_MIN_VALUE);
|
||||
return num;
|
||||
}
|
||||
|
||||
int32_t
|
||||
circuit_build_times_initial_timeout(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtinitialtimeout",
|
||||
CBT_DEFAULT_TIMEOUT_INITIAL_VALUE);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
circuit_build_times_recent_circuit_count(void)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(NULL, "cbtrecentcount",
|
||||
CBT_DEFAULT_RECENT_CIRCUITS);
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when we get a consensus update.
|
||||
*
|
||||
* It checks to see if we have changed any consensus parameters
|
||||
* that require reallocation or discard of previous stats.
|
||||
*/
|
||||
void
|
||||
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
|
||||
networkstatus_t *ns)
|
||||
{
|
||||
int32_t num = networkstatus_get_param(ns, "cbtrecentcount",
|
||||
CBT_DEFAULT_RECENT_CIRCUITS);
|
||||
|
||||
if (num != cbt->liveness.num_recent_circs) {
|
||||
int8_t *recent_circs;
|
||||
log_notice(LD_CIRC, "Changing recent timeout size from %d to %d",
|
||||
cbt->liveness.num_recent_circs, num);
|
||||
|
||||
tor_assert(num > 0);
|
||||
tor_assert(cbt->liveness.timeouts_after_firsthop);
|
||||
|
||||
/*
|
||||
* Technically this is a circular array that we are reallocating
|
||||
* and memcopying. However, since it only consists of either 1s
|
||||
* or 0s, and is only used in a statistical test to determine when
|
||||
* we should discard our history after a sufficient number of 1's
|
||||
* have been reached, it is fine if order is not preserved or
|
||||
* elements are lost.
|
||||
*
|
||||
* cbtrecentcount should only be changing in cases of severe network
|
||||
* distress anyway, so memory correctness here is paramount over
|
||||
* doing acrobatics to preserve the array.
|
||||
*/
|
||||
recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
|
||||
memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
|
||||
sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));
|
||||
|
||||
// Adjust the index if it needs it.
|
||||
if (num < cbt->liveness.num_recent_circs) {
|
||||
cbt->liveness.after_firsthop_idx = MIN(num-1,
|
||||
cbt->liveness.after_firsthop_idx);
|
||||
}
|
||||
|
||||
tor_free(cbt->liveness.timeouts_after_firsthop);
|
||||
cbt->liveness.timeouts_after_firsthop = recent_circs;
|
||||
cbt->liveness.num_recent_circs = num;
|
||||
}
|
||||
}
|
||||
|
||||
/** Make a note that we're running unit tests (rather than running Tor
|
||||
* itself), so we avoid clobbering our state file. */
|
||||
void
|
||||
@ -96,13 +201,13 @@ circuit_build_times_get_initial_timeout(void)
|
||||
double timeout;
|
||||
if (!unit_tests && get_options()->CircuitBuildTimeout) {
|
||||
timeout = get_options()->CircuitBuildTimeout*1000;
|
||||
if (timeout < BUILD_TIMEOUT_MIN_VALUE) {
|
||||
if (timeout < circuit_build_times_min_timeout()) {
|
||||
log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
|
||||
BUILD_TIMEOUT_MIN_VALUE/1000);
|
||||
timeout = BUILD_TIMEOUT_MIN_VALUE;
|
||||
circuit_build_times_min_timeout()/1000);
|
||||
timeout = circuit_build_times_min_timeout();
|
||||
}
|
||||
} else {
|
||||
timeout = BUILD_TIMEOUT_INITIAL_VALUE;
|
||||
timeout = circuit_build_times_initial_timeout();
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
@ -133,7 +238,11 @@ void
|
||||
circuit_build_times_init(circuit_build_times_t *cbt)
|
||||
{
|
||||
memset(cbt, 0, sizeof(*cbt));
|
||||
cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count();
|
||||
cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)*
|
||||
cbt->liveness.num_recent_circs);
|
||||
cbt->timeout_ms = circuit_build_times_get_initial_timeout();
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,10 +270,11 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
|
||||
}
|
||||
|
||||
cbt->build_times_idx -= n;
|
||||
cbt->build_times_idx %= NCIRCUITS_TO_OBSERVE;
|
||||
cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
cbt->circuit_build_times[(i+cbt->build_times_idx)%NCIRCUITS_TO_OBSERVE]=0;
|
||||
cbt->circuit_build_times[(i+cbt->build_times_idx)
|
||||
%CBT_NCIRCUITS_TO_OBSERVE]=0;
|
||||
}
|
||||
|
||||
if (cbt->total_build_times > n) {
|
||||
@ -188,7 +298,7 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
|
||||
int
|
||||
circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
|
||||
{
|
||||
tor_assert(time <= BUILD_TIME_MAX);
|
||||
tor_assert(time <= CBT_BUILD_TIME_MAX);
|
||||
if (time <= 0) {
|
||||
log_warn(LD_CIRC, "Circuit build time is %u!", time);
|
||||
return -1;
|
||||
@ -198,11 +308,11 @@ circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
|
||||
log_info(LD_CIRC, "Adding circuit build time %u", time);
|
||||
|
||||
cbt->circuit_build_times[cbt->build_times_idx] = time;
|
||||
cbt->build_times_idx = (cbt->build_times_idx + 1) % NCIRCUITS_TO_OBSERVE;
|
||||
if (cbt->total_build_times < NCIRCUITS_TO_OBSERVE)
|
||||
cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
|
||||
if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
|
||||
cbt->total_build_times++;
|
||||
|
||||
if ((cbt->total_build_times % BUILD_TIMES_SAVE_STATE_EVERY) == 0) {
|
||||
if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
|
||||
/* Save state every n circuit builds */
|
||||
if (!unit_tests && !get_options()->AvoidDiskWrites)
|
||||
or_state_mark_dirty(get_or_state(), 0);
|
||||
@ -219,7 +329,7 @@ circuit_build_times_max(circuit_build_times_t *cbt)
|
||||
{
|
||||
int i = 0;
|
||||
build_time_t max_build_time = 0;
|
||||
for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
|
||||
for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
|
||||
if (cbt->circuit_build_times[i] > max_build_time)
|
||||
max_build_time = cbt->circuit_build_times[i];
|
||||
}
|
||||
@ -232,14 +342,14 @@ build_time_t
|
||||
circuit_build_times_min(circuit_build_times_t *cbt)
|
||||
{
|
||||
int i = 0;
|
||||
build_time_t min_build_time = BUILD_TIME_MAX;
|
||||
for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
|
||||
build_time_t min_build_time = CBT_BUILD_TIME_MAX;
|
||||
for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
|
||||
if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
|
||||
cbt->circuit_build_times[i] < min_build_time)
|
||||
min_build_time = cbt->circuit_build_times[i];
|
||||
}
|
||||
if (min_build_time == BUILD_TIME_MAX) {
|
||||
log_warn(LD_CIRC, "No build times less than BUILD_TIME_MAX!");
|
||||
if (min_build_time == CBT_BUILD_TIME_MAX) {
|
||||
log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
|
||||
}
|
||||
return min_build_time;
|
||||
}
|
||||
@ -249,7 +359,7 @@ circuit_build_times_min(circuit_build_times_t *cbt)
|
||||
* Calculate and return a histogram for the set of build times.
|
||||
*
|
||||
* Returns an allocated array of histrogram bins representing
|
||||
* the frequency of index*BUILDTIME_BIN_WIDTH millisecond
|
||||
* the frequency of index*CBT_BIN_WIDTH millisecond
|
||||
* build times. Also outputs the number of bins in nbins.
|
||||
*
|
||||
* The return value must be freed by the caller.
|
||||
@ -262,14 +372,14 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt,
|
||||
build_time_t max_build_time = circuit_build_times_max(cbt);
|
||||
int i, c;
|
||||
|
||||
*nbins = 1 + (max_build_time / BUILDTIME_BIN_WIDTH);
|
||||
*nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
|
||||
histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
|
||||
|
||||
// calculate histogram
|
||||
for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
|
||||
for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
|
||||
if (cbt->circuit_build_times[i] == 0) continue; /* 0 <-> uninitialized */
|
||||
|
||||
c = (cbt->circuit_build_times[i] / BUILDTIME_BIN_WIDTH);
|
||||
c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
|
||||
histogram[c]++;
|
||||
}
|
||||
|
||||
@ -277,7 +387,7 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt,
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the most frequent build time (rounded to BUILDTIME_BIN_WIDTH ms).
|
||||
* Return the most frequent build time (rounded to CBT_BIN_WIDTH ms).
|
||||
*
|
||||
* Ties go in favor of the slower time.
|
||||
*/
|
||||
@ -295,7 +405,7 @@ circuit_build_times_mode(circuit_build_times_t *cbt)
|
||||
|
||||
tor_free(histogram);
|
||||
|
||||
return max_bin*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2;
|
||||
return max_bin*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,7 +436,7 @@ circuit_build_times_update_state(circuit_build_times_t *cbt,
|
||||
line->key = tor_strdup("CircuitBuildTimeBin");
|
||||
line->value = tor_malloc(25);
|
||||
tor_snprintf(line->value, 25, "%d %d",
|
||||
i*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2, histogram[i]);
|
||||
i*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2, histogram[i]);
|
||||
next = &(line->next);
|
||||
}
|
||||
|
||||
@ -349,9 +459,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
|
||||
int num_times)
|
||||
{
|
||||
int n = num_times;
|
||||
if (num_times > NCIRCUITS_TO_OBSERVE) {
|
||||
if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
|
||||
log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d",
|
||||
num_times, NCIRCUITS_TO_OBSERVE);
|
||||
num_times, CBT_NCIRCUITS_TO_OBSERVE);
|
||||
}
|
||||
|
||||
/* This code can only be run on a compact array */
|
||||
@ -362,9 +472,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
|
||||
raw_times[n] = tmp;
|
||||
}
|
||||
|
||||
/* Since the times are now shuffled, take a random NCIRCUITS_TO_OBSERVE
|
||||
* subset (ie the first NCIRCUITS_TO_OBSERVE values) */
|
||||
for (n = 0; n < MIN(num_times, NCIRCUITS_TO_OBSERVE); n++) {
|
||||
/* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
|
||||
* subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
|
||||
for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
|
||||
circuit_build_times_add_time(cbt, raw_times[n]);
|
||||
}
|
||||
}
|
||||
@ -406,7 +516,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
|
||||
build_time_t ms;
|
||||
int ok;
|
||||
ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
|
||||
BUILD_TIME_MAX, &ok, NULL);
|
||||
CBT_BUILD_TIME_MAX, &ok, NULL);
|
||||
if (!ok) {
|
||||
*msg = tor_strdup("Unable to parse circuit build times: "
|
||||
"Unparsable bin number");
|
||||
@ -452,7 +562,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
|
||||
circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
|
||||
|
||||
/* Verify that we didn't overwrite any indexes */
|
||||
for (i=0; i < NCIRCUITS_TO_OBSERVE; i++) {
|
||||
for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
|
||||
if (!cbt->circuit_build_times[i])
|
||||
break;
|
||||
tot_values++;
|
||||
@ -461,7 +571,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
|
||||
"Loaded %d/%d values from %d lines in circuit time histogram",
|
||||
tot_values, cbt->total_build_times, N);
|
||||
tor_assert(cbt->total_build_times == tot_values);
|
||||
tor_assert(cbt->total_build_times <= NCIRCUITS_TO_OBSERVE);
|
||||
tor_assert(cbt->total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
|
||||
circuit_build_times_set_timeout(cbt);
|
||||
tor_free(loaded_times);
|
||||
return *msg ? -1 : 0;
|
||||
@ -488,7 +598,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
|
||||
* and less frechet-like. */
|
||||
cbt->Xm = circuit_build_times_mode(cbt);
|
||||
|
||||
for (i=0; i< NCIRCUITS_TO_OBSERVE; i++) {
|
||||
for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
|
||||
if (!x[i]) {
|
||||
continue;
|
||||
}
|
||||
@ -593,19 +703,22 @@ void
|
||||
circuit_build_times_add_timeout_worker(circuit_build_times_t *cbt,
|
||||
double quantile_cutoff)
|
||||
{
|
||||
// XXX: This may be failing when the number of samples is small?
|
||||
// Keep getting values for the largest timeout bucket over and over
|
||||
// again... Probably because alpha is very very large in that case..
|
||||
build_time_t gentime = circuit_build_times_generate_sample(cbt,
|
||||
quantile_cutoff, MAX_SYNTHETIC_QUANTILE);
|
||||
quantile_cutoff, CBT_MAX_SYNTHETIC_QUANTILE);
|
||||
|
||||
if (gentime < (build_time_t)tor_lround(cbt->timeout_ms)) {
|
||||
log_warn(LD_CIRC,
|
||||
"Generated a synthetic timeout LESS than the current timeout: "
|
||||
"%ums vs %lfms using Xm: %d a: %lf, q: %lf",
|
||||
gentime, cbt->timeout_ms, cbt->Xm, cbt->alpha, quantile_cutoff);
|
||||
} else if (gentime > BUILD_TIME_MAX) {
|
||||
} else if (gentime > CBT_BUILD_TIME_MAX) {
|
||||
log_info(LD_CIRC,
|
||||
"Generated a synthetic timeout larger than the max: %u",
|
||||
gentime);
|
||||
gentime = BUILD_TIME_MAX;
|
||||
gentime = CBT_BUILD_TIME_MAX;
|
||||
} else {
|
||||
log_info(LD_CIRC, "Generated synthetic circuit build time %u for timeout",
|
||||
gentime);
|
||||
@ -649,7 +762,7 @@ circuit_build_times_count_pretimeouts(circuit_build_times_t *cbt)
|
||||
((double)cbt->pre_timeouts)/
|
||||
(cbt->pre_timeouts+cbt->total_build_times);
|
||||
/* Make sure it doesn't exceed the synthetic max */
|
||||
timeout_quantile *= MAX_SYNTHETIC_QUANTILE;
|
||||
timeout_quantile *= CBT_MAX_SYNTHETIC_QUANTILE;
|
||||
cbt->Xm = circuit_build_times_mode(cbt);
|
||||
tor_assert(cbt->Xm > 0);
|
||||
/* Use current timeout to get an estimate on alpha */
|
||||
@ -669,7 +782,7 @@ int
|
||||
circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
|
||||
{
|
||||
/* Return true if < MIN_CIRCUITS_TO_OBSERVE */
|
||||
if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE)
|
||||
if (cbt->total_build_times < circuit_build_times_min_circs_to_observe())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -682,11 +795,14 @@ int
|
||||
circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
|
||||
{
|
||||
return circuit_build_times_needs_circuits(cbt) &&
|
||||
approx_time()-cbt->last_circ_at > BUILD_TIMES_TEST_FREQUENCY;
|
||||
approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to indicate that the network showed some signs of liveness.
|
||||
*
|
||||
* This function is called every time we receive a cell. Avoid
|
||||
* syscalls, events, and other high-intensity work.
|
||||
*/
|
||||
void
|
||||
circuit_build_times_network_is_live(circuit_build_times_t *cbt)
|
||||
@ -705,7 +821,7 @@ circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
|
||||
{
|
||||
cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0;
|
||||
cbt->liveness.after_firsthop_idx++;
|
||||
cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS;
|
||||
cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -736,7 +852,7 @@ circuit_build_times_network_timeout(circuit_build_times_t *cbt,
|
||||
/* Count a one-hop timeout */
|
||||
cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1;
|
||||
cbt->liveness.after_firsthop_idx++;
|
||||
cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS;
|
||||
cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
|
||||
}
|
||||
}
|
||||
|
||||
@ -751,7 +867,7 @@ int
|
||||
circuit_build_times_network_check_live(circuit_build_times_t *cbt)
|
||||
{
|
||||
time_t now = approx_time();
|
||||
if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_DISCARD_COUNT) {
|
||||
if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_DISCARD_COUNT) {
|
||||
if (!cbt->liveness.nonlive_discarded) {
|
||||
cbt->liveness.nonlive_discarded = 1;
|
||||
log_notice(LD_CIRC, "Network is no longer live (too many recent "
|
||||
@ -759,10 +875,13 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt)
|
||||
(long int)(now - cbt->liveness.network_last_live));
|
||||
/* Only discard NETWORK_NONLIVE_TIMEOUT_COUNT-1 because we stopped
|
||||
* counting after that */
|
||||
circuit_build_times_rewind_history(cbt, NETWORK_NONLIVE_TIMEOUT_COUNT-1);
|
||||
circuit_build_times_rewind_history(cbt,
|
||||
CBT_NETWORK_NONLIVE_TIMEOUT_COUNT-1);
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_DISCARD);
|
||||
}
|
||||
return 0;
|
||||
} else if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_TIMEOUT_COUNT) {
|
||||
} else if (cbt->liveness.nonlive_timeouts >=
|
||||
CBT_NETWORK_NONLIVE_TIMEOUT_COUNT) {
|
||||
if (cbt->timeout_ms < circuit_build_times_get_initial_timeout()) {
|
||||
log_notice(LD_CIRC,
|
||||
"Network is flaky. No activity for %ld seconds. "
|
||||
@ -770,9 +889,17 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt)
|
||||
(long int)(now - cbt->liveness.network_last_live),
|
||||
tor_lround(circuit_build_times_get_initial_timeout()/1000));
|
||||
cbt->timeout_ms = circuit_build_times_get_initial_timeout();
|
||||
cbt->liveness.net_suspended = 1;
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_SUSPENDED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (cbt->liveness.net_suspended) {
|
||||
log_notice(LD_CIRC,
|
||||
"Network activity has resumed. "
|
||||
"Resuming circuit timeout calculations.");
|
||||
cbt->liveness.net_suspended = 0;
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESUME);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -796,19 +923,20 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
|
||||
|
||||
/* how many of our recent circuits made it to the first hop but then
|
||||
* timed out? */
|
||||
for (i = 0; i < RECENT_CIRCUITS; i++) {
|
||||
for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
|
||||
timeout_count += cbt->liveness.timeouts_after_firsthop[i];
|
||||
}
|
||||
|
||||
/* If 80% of our recent circuits are timing out after the first hop,
|
||||
* we need to re-estimate a new initial alpha and timeout. */
|
||||
if (timeout_count < MAX_RECENT_TIMEOUT_COUNT) {
|
||||
if (timeout_count < circuit_build_times_max_timeouts()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
circuit_build_times_reset(cbt);
|
||||
memset(cbt->liveness.timeouts_after_firsthop, 0,
|
||||
sizeof(cbt->liveness.timeouts_after_firsthop));
|
||||
sizeof(*cbt->liveness.timeouts_after_firsthop)*
|
||||
cbt->liveness.num_recent_circs);
|
||||
cbt->liveness.after_firsthop_idx = 0;
|
||||
|
||||
/* Check to see if this has happened before. If so, double the timeout
|
||||
@ -819,6 +947,8 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
|
||||
cbt->timeout_ms = circuit_build_times_get_initial_timeout();
|
||||
}
|
||||
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
|
||||
|
||||
log_notice(LD_CIRC,
|
||||
"Network connection speed appears to have changed. Resetting "
|
||||
"timeout to %lds after %d timeouts and %d buildtimes.",
|
||||
@ -857,13 +987,14 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt,
|
||||
cbt->pre_timeouts++;
|
||||
log_info(LD_CIRC,
|
||||
"Not enough circuits yet to calculate a new build timeout."
|
||||
" Need %d more.",
|
||||
MIN_CIRCUITS_TO_OBSERVE-cbt->total_build_times);
|
||||
" Need %d more.", circuit_build_times_min_circs_to_observe()
|
||||
- cbt->total_build_times);
|
||||
return 0;
|
||||
}
|
||||
|
||||
circuit_build_times_count_pretimeouts(cbt);
|
||||
circuit_build_times_add_timeout_worker(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF);
|
||||
circuit_build_times_add_timeout_worker(cbt,
|
||||
circuit_build_times_quantile_cutoff());
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -875,7 +1006,7 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt,
|
||||
void
|
||||
circuit_build_times_set_timeout(circuit_build_times_t *cbt)
|
||||
{
|
||||
if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) {
|
||||
if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -883,16 +1014,18 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
|
||||
circuit_build_times_update_alpha(cbt);
|
||||
|
||||
cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
|
||||
BUILDTIMEOUT_QUANTILE_CUTOFF);
|
||||
circuit_build_times_quantile_cutoff());
|
||||
|
||||
cbt->have_computed_timeout = 1;
|
||||
|
||||
if (cbt->timeout_ms < BUILD_TIMEOUT_MIN_VALUE) {
|
||||
if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
|
||||
log_warn(LD_CIRC, "Set buildtimeout to low value %lfms. Setting to %dms",
|
||||
cbt->timeout_ms, BUILD_TIMEOUT_MIN_VALUE);
|
||||
cbt->timeout_ms = BUILD_TIMEOUT_MIN_VALUE;
|
||||
cbt->timeout_ms, circuit_build_times_min_timeout());
|
||||
cbt->timeout_ms = circuit_build_times_min_timeout();
|
||||
}
|
||||
|
||||
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
|
||||
|
||||
log_info(LD_CIRC,
|
||||
"Set circuit build timeout to %lds (%lfms, Xm: %d, a: %lf) "
|
||||
"based on %d circuit times", tor_lround(cbt->timeout_ms/1000),
|
||||
@ -3296,6 +3429,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded,
|
||||
"Removing from the list. %d/%d entry guards usable/new.",
|
||||
entry->nickname, buf,
|
||||
num_live_entry_guards()-1, smartlist_len(entry_guards)-1);
|
||||
control_event_guard(entry->nickname, entry->identity, "DROPPED");
|
||||
entry_guard_free(entry);
|
||||
smartlist_del_keeporder(entry_guards, idx);
|
||||
log_entry_guards(LOG_INFO);
|
||||
|
153
src/or/control.c
153
src/or/control.c
@ -43,7 +43,8 @@
|
||||
#define EVENT_STREAM_BANDWIDTH_USED 0x0014
|
||||
#define EVENT_CLIENTS_SEEN 0x0015
|
||||
#define EVENT_NEWCONSENSUS 0x0016
|
||||
#define _EVENT_MAX 0x0016
|
||||
#define EVENT_BUILDTIMEOUT_SET 0x0017
|
||||
#define _EVENT_MAX 0x0017
|
||||
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
|
||||
|
||||
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
|
||||
@ -922,6 +923,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
|
||||
event_code = EVENT_CLIENTS_SEEN;
|
||||
else if (!strcasecmp(ev, "NEWCONSENSUS"))
|
||||
event_code = EVENT_NEWCONSENSUS;
|
||||
else if (!strcasecmp(ev, "BUILDTIMEOUT_SET"))
|
||||
event_code = EVENT_BUILDTIMEOUT_SET;
|
||||
else {
|
||||
connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n",
|
||||
ev);
|
||||
@ -2000,12 +2003,12 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len,
|
||||
static uint8_t
|
||||
circuit_purpose_from_string(const char *string)
|
||||
{
|
||||
if (!strcmpstart(string, "purpose="))
|
||||
if (!strcasecmpstart(string, "purpose="))
|
||||
string += strlen("purpose=");
|
||||
|
||||
if (!strcmp(string, "general"))
|
||||
if (!strcasecmp(string, "general"))
|
||||
return CIRCUIT_PURPOSE_C_GENERAL;
|
||||
else if (!strcmp(string, "controller"))
|
||||
else if (!strcasecmp(string, "controller"))
|
||||
return CIRCUIT_PURPOSE_CONTROLLER;
|
||||
else
|
||||
return CIRCUIT_PURPOSE_UNKNOWN;
|
||||
@ -2037,6 +2040,31 @@ getargs_helper(const char *command, control_connection_t *conn,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Helper. Return the first element of <b>sl</b> at index <b>start_at</b> or
|
||||
* higher that starts with <b>prefix</b>, case-insensitive. Return NULL if no
|
||||
* such element exists. */
|
||||
static const char *
|
||||
find_element_starting_with(smartlist_t *sl, int start_at, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
for (i = start_at; i < smartlist_len(sl); ++i) {
|
||||
const char *elt = smartlist_get(sl, i);
|
||||
if (!strcasecmpstart(elt, prefix))
|
||||
return elt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Helper. Return true iff s is an argument that we should treat as a
|
||||
* key-value pair. */
|
||||
static int
|
||||
is_keyval_pair(const char *s)
|
||||
{
|
||||
/* An argument is a key-value pair if it has an =, and it isn't of the form
|
||||
* $fingeprint=name */
|
||||
return strchr(s, '=') && s[0] != '$';
|
||||
}
|
||||
|
||||
/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed
|
||||
* circuit, and report success or failure. */
|
||||
static int
|
||||
@ -2052,27 +2080,49 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
|
||||
|
||||
router_nicknames = smartlist_create();
|
||||
|
||||
args = getargs_helper("EXTENDCIRCUIT", conn, body, 2, -1);
|
||||
args = getargs_helper("EXTENDCIRCUIT", conn, body, 1, -1);
|
||||
if (!args)
|
||||
goto done;
|
||||
|
||||
zero_circ = !strcmp("0", (char*)smartlist_get(args,0));
|
||||
|
||||
if (zero_circ) {
|
||||
const char *purp = find_element_starting_with(args, 1, "PURPOSE=");
|
||||
|
||||
if (purp) {
|
||||
intended_purpose = circuit_purpose_from_string(purp);
|
||||
if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) {
|
||||
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp);
|
||||
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
||||
smartlist_free(args);
|
||||
}
|
||||
}
|
||||
|
||||
if ((smartlist_len(args) == 1) ||
|
||||
(smartlist_len(args) >= 2 && is_keyval_pair(smartlist_get(args, 1)))) {
|
||||
// "EXTENDCIRCUIT 0" || EXTENDCIRCUIT 0 foo=bar"
|
||||
circ = circuit_launch_by_router(intended_purpose, NULL,
|
||||
CIRCLAUNCH_NEED_CAPACITY);
|
||||
if (!circ) {
|
||||
connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn);
|
||||
} else {
|
||||
connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n",
|
||||
(unsigned long)circ->global_identifier);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
// "EXTENDCIRCUIT 0 router1,router2" ||
|
||||
// "EXTENDCIRCUIT 0 router1,router2 PURPOSE=foo"
|
||||
}
|
||||
|
||||
if (!zero_circ && !(circ = get_circ(smartlist_get(args,0)))) {
|
||||
connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
|
||||
(char*)smartlist_get(args, 0));
|
||||
goto done;
|
||||
}
|
||||
|
||||
smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0);
|
||||
|
||||
if (zero_circ && smartlist_len(args)>2) {
|
||||
char *purp = smartlist_get(args,2);
|
||||
intended_purpose = circuit_purpose_from_string(purp);
|
||||
if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) {
|
||||
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp);
|
||||
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
||||
smartlist_free(args);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
||||
smartlist_free(args);
|
||||
if (!zero_circ && !circ) {
|
||||
@ -2162,7 +2212,7 @@ handle_control_setcircuitpurpose(control_connection_t *conn,
|
||||
}
|
||||
|
||||
{
|
||||
char *purp = smartlist_get(args,1);
|
||||
const char *purp = find_element_starting_with(args,1,"PURPOSE=");
|
||||
new_purpose = circuit_purpose_from_string(purp);
|
||||
if (new_purpose == CIRCUIT_PURPOSE_UNKNOWN) {
|
||||
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp);
|
||||
@ -2207,9 +2257,9 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
|
||||
} else if (!zero_circ && !(circ = get_circ(smartlist_get(args, 1)))) {
|
||||
connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
|
||||
(char*)smartlist_get(args, 1));
|
||||
} else if (circ && smartlist_len(args) > 2) {
|
||||
char *hopstring = smartlist_get(args, 2);
|
||||
if (!strcasecmpstart(hopstring, "HOP=")) {
|
||||
} else if (circ) {
|
||||
const char *hopstring = find_element_starting_with(args,2,"HOP=");
|
||||
if (hopstring) {
|
||||
hopstring += strlen("HOP=");
|
||||
hop = (int) tor_parse_ulong(hopstring, 10, 0, INT_MAX,
|
||||
&hop_line_ok, NULL);
|
||||
@ -2317,9 +2367,9 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len,
|
||||
}
|
||||
} else if (!strcasecmpstart(option, "cache=")) {
|
||||
option += strlen("cache=");
|
||||
if (!strcmp(option, "no"))
|
||||
if (!strcasecmp(option, "no"))
|
||||
cache = 0;
|
||||
else if (!strcmp(option, "yes"))
|
||||
else if (!strcasecmp(option, "yes"))
|
||||
cache = 1;
|
||||
else {
|
||||
connection_printf_to_buf(conn, "552 Unknown cache request \"%s\"\r\n",
|
||||
@ -2501,17 +2551,17 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
|
||||
args = smartlist_create();
|
||||
smartlist_split_string(args, body, " ",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
if (smartlist_len(args) &&
|
||||
!strcasecmp(smartlist_get(args, 0), "mode=reverse")) {
|
||||
char *cp = smartlist_get(args, 0);
|
||||
smartlist_del_keeporder(args, 0);
|
||||
tor_free(cp);
|
||||
is_reverse = 1;
|
||||
{
|
||||
const char *modearg = find_element_starting_with(args, 0, "mode=");
|
||||
if (modearg && !strcasecmp(modearg, "mode=reverse"))
|
||||
is_reverse = 1;
|
||||
}
|
||||
failed = smartlist_create();
|
||||
SMARTLIST_FOREACH(args, const char *, arg, {
|
||||
if (dnsserv_launch_request(arg, is_reverse)<0)
|
||||
smartlist_add(failed, (char*)arg);
|
||||
if (!is_keyval_pair(arg)) {
|
||||
if (dnsserv_launch_request(arg, is_reverse)<0)
|
||||
smartlist_add(failed, (char*)arg);
|
||||
}
|
||||
});
|
||||
|
||||
send_control_done(conn);
|
||||
@ -3440,6 +3490,51 @@ control_event_newconsensus(const networkstatus_t *consensus)
|
||||
consensus->routerstatus_list, EVENT_NEWCONSENSUS, "NEWCONSENSUS");
|
||||
}
|
||||
|
||||
/** Called when we compute a new circuitbuildtimeout */
|
||||
int
|
||||
control_event_buildtimeout_set(const circuit_build_times_t *cbt,
|
||||
buildtimeout_set_event_t type)
|
||||
{
|
||||
const char *type_string = NULL;
|
||||
double qnt = circuit_build_times_quantile_cutoff();
|
||||
|
||||
if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET))
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case BUILDTIMEOUT_SET_EVENT_COMPUTED:
|
||||
type_string = "COMPUTED";
|
||||
break;
|
||||
case BUILDTIMEOUT_SET_EVENT_RESET:
|
||||
type_string = "RESET";
|
||||
qnt = 1.0;
|
||||
break;
|
||||
case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
|
||||
type_string = "SUSPENDED";
|
||||
qnt = 1.0;
|
||||
break;
|
||||
case BUILDTIMEOUT_SET_EVENT_DISCARD:
|
||||
type_string = "DISCARD";
|
||||
qnt = 1.0;
|
||||
break;
|
||||
case BUILDTIMEOUT_SET_EVENT_RESUME:
|
||||
type_string = "RESUME";
|
||||
break;
|
||||
default:
|
||||
type_string = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
send_control_event(EVENT_BUILDTIMEOUT_SET, ALL_FORMATS,
|
||||
"650 BUILDTIMEOUT_SET %s TOTAL_TIMES=%lu "
|
||||
"TIMEOUT_MS=%lu XM=%lu ALPHA=%lf CUTOFF_QUANTILE=%lf\r\n",
|
||||
type_string, (unsigned long)cbt->total_build_times,
|
||||
(unsigned long)cbt->timeout_ms,
|
||||
(unsigned long)cbt->Xm, cbt->alpha, qnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Called when a single local_routerstatus_t has changed: Sends an NS event
|
||||
* to any controller that cares. */
|
||||
int
|
||||
|
@ -1680,6 +1680,7 @@ networkstatus_set_current_consensus(const char *consensus,
|
||||
dirvote_recalculate_timing(get_options(), now);
|
||||
routerstatus_list_update_named_server_map();
|
||||
cell_ewma_set_scale_factor(get_options(), current_consensus);
|
||||
circuit_build_times_new_consensus_params(&circ_times, current_consensus);
|
||||
}
|
||||
|
||||
if (!from_cache) {
|
||||
|
97
src/or/or.h
97
src/or/or.h
@ -3002,49 +3002,27 @@ void entry_guards_free_all(void);
|
||||
|
||||
/* Circuit Build Timeout "public" functions and structures. */
|
||||
|
||||
/** Total size of the circuit timeout history to accumulate.
|
||||
* 1000 is approx 2.5 days worth of continual-use circuits. */
|
||||
#define CBT_NCIRCUITS_TO_OBSERVE 1000
|
||||
|
||||
/** Maximum quantile to use to generate synthetic timeouts.
|
||||
* We want to stay a bit short of 1.0, because longtail is
|
||||
* loooooooooooooooooooooooooooooooooooooooooooooooooooong. */
|
||||
#define MAX_SYNTHETIC_QUANTILE 0.985
|
||||
|
||||
/** Minimum circuits before estimating a timeout */
|
||||
#define MIN_CIRCUITS_TO_OBSERVE 500
|
||||
|
||||
/** Total size of the circuit timeout history to accumulate.
|
||||
* 5000 is approx 1.5 weeks worth of continual-use circuits. */
|
||||
#define NCIRCUITS_TO_OBSERVE 5000
|
||||
#define CBT_MAX_SYNTHETIC_QUANTILE 0.985
|
||||
|
||||
/** Width of the histogram bins in milliseconds */
|
||||
#define BUILDTIME_BIN_WIDTH ((build_time_t)50)
|
||||
|
||||
/** Cutoff point on the CDF for our timeout estimation.
|
||||
* TODO: This should be moved to the consensus */
|
||||
#define BUILDTIMEOUT_QUANTILE_CUTOFF 0.8
|
||||
#define CBT_BIN_WIDTH ((build_time_t)50)
|
||||
|
||||
/** A build_time_t is milliseconds */
|
||||
typedef uint32_t build_time_t;
|
||||
#define BUILD_TIME_MAX ((build_time_t)(INT32_MAX))
|
||||
|
||||
/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
|
||||
#define BUILD_TIMEOUT_MIN_VALUE (3*1000)
|
||||
|
||||
/** Initial circuit build timeout in milliseconds */
|
||||
#define BUILD_TIMEOUT_INITIAL_VALUE (60*1000)
|
||||
|
||||
/** How often in seconds should we build a test circuit */
|
||||
#define BUILD_TIMES_TEST_FREQUENCY 60
|
||||
#define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX))
|
||||
|
||||
/** Save state every 10 circuits */
|
||||
#define BUILD_TIMES_SAVE_STATE_EVERY 10
|
||||
#define CBT_SAVE_STATE_EVERY 10
|
||||
|
||||
/* Circuit Build Timeout network liveness constants */
|
||||
|
||||
/**
|
||||
* How many circuits count as recent when considering if the
|
||||
* connection has gone gimpy or changed.
|
||||
*/
|
||||
#define RECENT_CIRCUITS 20
|
||||
|
||||
/**
|
||||
* Have we received a cell in the last N circ attempts?
|
||||
*
|
||||
@ -3053,7 +3031,7 @@ typedef uint32_t build_time_t;
|
||||
* at which point we switch back to computing the timeout from
|
||||
* our saved history.
|
||||
*/
|
||||
#define NETWORK_NONLIVE_TIMEOUT_COUNT (RECENT_CIRCUITS*3/20)
|
||||
#define CBT_NETWORK_NONLIVE_TIMEOUT_COUNT (3)
|
||||
|
||||
/**
|
||||
* This tells us when to toss out the last streak of N timeouts.
|
||||
@ -3061,7 +3039,15 @@ typedef uint32_t build_time_t;
|
||||
* If instead we start getting cells, we switch back to computing the timeout
|
||||
* from our saved history.
|
||||
*/
|
||||
#define NETWORK_NONLIVE_DISCARD_COUNT (NETWORK_NONLIVE_TIMEOUT_COUNT*2)
|
||||
#define CBT_NETWORK_NONLIVE_DISCARD_COUNT (CBT_NETWORK_NONLIVE_TIMEOUT_COUNT*2)
|
||||
|
||||
/* Circuit build times consensus parameters */
|
||||
|
||||
/**
|
||||
* How many circuits count as recent when considering if the
|
||||
* connection has gone gimpy or changed.
|
||||
*/
|
||||
#define CBT_DEFAULT_RECENT_CIRCUITS 20
|
||||
|
||||
/**
|
||||
* Maximum count of timeouts that finish the first hop in the past
|
||||
@ -3070,10 +3056,28 @@ typedef uint32_t build_time_t;
|
||||
* This tells us to abandon timeout history and set
|
||||
* the timeout back to BUILD_TIMEOUT_INITIAL_VALUE.
|
||||
*/
|
||||
#define MAX_RECENT_TIMEOUT_COUNT (RECENT_CIRCUITS*4/5)
|
||||
#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10)
|
||||
|
||||
#if MAX_RECENT_TIMEOUT_COUNT < 1 || NETWORK_NONLIVE_DISCARD_COUNT < 1 || \
|
||||
NETWORK_NONLIVE_TIMEOUT_COUNT < 1
|
||||
/** Minimum circuits before estimating a timeout */
|
||||
#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100
|
||||
|
||||
/** Cutoff percentile on the CDF for our timeout estimation. */
|
||||
#define CBT_DEFAULT_QUANTILE_CUTOFF 80
|
||||
double circuit_build_times_quantile_cutoff(void);
|
||||
|
||||
/** How often in seconds should we build a test circuit */
|
||||
#define CBT_DEFAULT_TEST_FREQUENCY 60
|
||||
|
||||
/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
|
||||
#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (2*1000)
|
||||
|
||||
/** Initial circuit build timeout in milliseconds */
|
||||
#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000)
|
||||
int32_t circuit_build_times_initial_timeout(void);
|
||||
|
||||
#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < 1 || \
|
||||
CBT_NETWORK_NONLIVE_DISCARD_COUNT < 1 || \
|
||||
CBT_NETWORK_NONLIVE_TIMEOUT_COUNT < 1
|
||||
#error "RECENT_CIRCUITS is set too low."
|
||||
#endif
|
||||
|
||||
@ -3087,18 +3091,22 @@ typedef struct {
|
||||
int nonlive_discarded;
|
||||
/** Circular array of circuits that have made it to the first hop. Slot is
|
||||
* 1 if circuit timed out, 0 if circuit succeeded */
|
||||
int8_t timeouts_after_firsthop[RECENT_CIRCUITS];
|
||||
int8_t *timeouts_after_firsthop;
|
||||
/** Number of elements allocated for the above array */
|
||||
int num_recent_circs;
|
||||
/** Index into circular array. */
|
||||
int after_firsthop_idx;
|
||||
/** The network is not live. Timeout gathering is suspended */
|
||||
int net_suspended;
|
||||
} network_liveness_t;
|
||||
|
||||
/** Structure for circuit build times history */
|
||||
typedef struct {
|
||||
/** The circular array of recorded build times in milliseconds */
|
||||
build_time_t circuit_build_times[NCIRCUITS_TO_OBSERVE];
|
||||
build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
|
||||
/** Current index in the circuit_build_times circular array */
|
||||
int build_times_idx;
|
||||
/** Total number of build times accumulated. Maxes at NCIRCUITS_TO_OBSERVE */
|
||||
/** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
|
||||
int total_build_times;
|
||||
/** Information about the state of our local network connection */
|
||||
network_liveness_t liveness;
|
||||
@ -3130,6 +3138,8 @@ int circuit_build_times_add_time(circuit_build_times_t *cbt,
|
||||
int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
|
||||
int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
|
||||
void circuit_build_times_init(circuit_build_times_t *cbt);
|
||||
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
|
||||
networkstatus_t *ns);
|
||||
|
||||
#ifdef CIRCUIT_PRIVATE
|
||||
double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
|
||||
@ -3583,6 +3593,15 @@ typedef enum or_conn_status_event_t {
|
||||
OR_CONN_EVENT_NEW = 4,
|
||||
} or_conn_status_event_t;
|
||||
|
||||
/** Used to indicate the type of a buildtime event */
|
||||
typedef enum buildtimeout_set_event_t {
|
||||
BUILDTIMEOUT_SET_EVENT_COMPUTED = 0,
|
||||
BUILDTIMEOUT_SET_EVENT_RESET = 1,
|
||||
BUILDTIMEOUT_SET_EVENT_SUSPENDED = 2,
|
||||
BUILDTIMEOUT_SET_EVENT_DISCARD = 3,
|
||||
BUILDTIMEOUT_SET_EVENT_RESUME = 4
|
||||
} buildtimeout_set_event_t;
|
||||
|
||||
void control_update_global_event_mask(void);
|
||||
void control_adjust_event_log_severity(void);
|
||||
|
||||
@ -3648,6 +3667,8 @@ int control_event_server_status(int severity, const char *format, ...)
|
||||
CHECK_PRINTF(2,3);
|
||||
int control_event_guard(const char *nickname, const char *digest,
|
||||
const char *status);
|
||||
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
|
||||
buildtimeout_set_event_t type);
|
||||
|
||||
int init_cookie_authentication(int enabled);
|
||||
smartlist_t *decode_hashed_passwords(config_line_t *passwords);
|
||||
|
@ -479,11 +479,12 @@ test_circuit_timeout(void)
|
||||
circuitbuild_running_unit_tests();
|
||||
#define timeout0 (build_time_t)(30*1000.0)
|
||||
initial.Xm = 750;
|
||||
circuit_build_times_initial_alpha(&initial, BUILDTIMEOUT_QUANTILE_CUTOFF,
|
||||
circuit_build_times_initial_alpha(&initial,
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF/100.0,
|
||||
timeout0);
|
||||
do {
|
||||
int n = 0;
|
||||
for (i=0; i < MIN_CIRCUITS_TO_OBSERVE; i++) {
|
||||
for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) {
|
||||
if (circuit_build_times_add_time(&estimate,
|
||||
circuit_build_times_generate_sample(&initial, 0, 1)) == 0) {
|
||||
n++;
|
||||
@ -491,23 +492,23 @@ test_circuit_timeout(void)
|
||||
}
|
||||
circuit_build_times_update_alpha(&estimate);
|
||||
timeout1 = circuit_build_times_calculate_timeout(&estimate,
|
||||
BUILDTIMEOUT_QUANTILE_CUTOFF);
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF/100.0);
|
||||
circuit_build_times_set_timeout(&estimate);
|
||||
log_warn(LD_CIRC, "Timeout is %lf, Xm is %d", timeout1, estimate.Xm);
|
||||
/* XXX: 5% distribution error may not be the right metric */
|
||||
} while (fabs(circuit_build_times_cdf(&initial, timeout0) -
|
||||
circuit_build_times_cdf(&initial, timeout1)) > 0.05
|
||||
/* 5% error */
|
||||
&& estimate.total_build_times < NCIRCUITS_TO_OBSERVE);
|
||||
&& estimate.total_build_times < CBT_NCIRCUITS_TO_OBSERVE);
|
||||
|
||||
test_assert(estimate.total_build_times < NCIRCUITS_TO_OBSERVE);
|
||||
test_assert(estimate.total_build_times < CBT_NCIRCUITS_TO_OBSERVE);
|
||||
|
||||
circuit_build_times_update_state(&estimate, &state);
|
||||
test_assert(circuit_build_times_parse_state(&final, &state, &msg) == 0);
|
||||
|
||||
circuit_build_times_update_alpha(&final);
|
||||
timeout2 = circuit_build_times_calculate_timeout(&final,
|
||||
BUILDTIMEOUT_QUANTILE_CUTOFF);
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF/100.0);
|
||||
|
||||
circuit_build_times_set_timeout(&final);
|
||||
log_warn(LD_CIRC, "Timeout is %lf, Xm is %d", timeout2, final.Xm);
|
||||
@ -519,19 +520,19 @@ test_circuit_timeout(void)
|
||||
int build_times_idx = 0;
|
||||
int total_build_times = 0;
|
||||
|
||||
final.timeout_ms = BUILD_TIMEOUT_INITIAL_VALUE;
|
||||
estimate.timeout_ms = BUILD_TIMEOUT_INITIAL_VALUE;
|
||||
final.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE;
|
||||
estimate.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE;
|
||||
|
||||
for (i = 0; i < RECENT_CIRCUITS*2; i++) {
|
||||
for (i = 0; i < CBT_DEFAULT_RECENT_CIRCUITS*2; i++) {
|
||||
circuit_build_times_network_circ_success(&estimate);
|
||||
circuit_build_times_add_time(&estimate,
|
||||
circuit_build_times_generate_sample(&estimate, 0,
|
||||
BUILDTIMEOUT_QUANTILE_CUTOFF));
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF/100.0));
|
||||
estimate.have_computed_timeout = 1;
|
||||
circuit_build_times_network_circ_success(&estimate);
|
||||
circuit_build_times_add_time(&final,
|
||||
circuit_build_times_generate_sample(&final, 0,
|
||||
BUILDTIMEOUT_QUANTILE_CUTOFF));
|
||||
CBT_DEFAULT_QUANTILE_CUTOFF/100.0));
|
||||
final.have_computed_timeout = 1;
|
||||
}
|
||||
|
||||
@ -544,7 +545,7 @@ test_circuit_timeout(void)
|
||||
|
||||
build_times_idx = estimate.build_times_idx;
|
||||
total_build_times = estimate.total_build_times;
|
||||
for (i = 0; i < NETWORK_NONLIVE_TIMEOUT_COUNT; i++) {
|
||||
for (i = 0; i < CBT_NETWORK_NONLIVE_TIMEOUT_COUNT; i++) {
|
||||
test_assert(circuit_build_times_network_check_live(&estimate));
|
||||
test_assert(circuit_build_times_network_check_live(&final));
|
||||
|
||||
@ -559,12 +560,12 @@ test_circuit_timeout(void)
|
||||
test_assert(!circuit_build_times_network_check_live(&estimate));
|
||||
test_assert(!circuit_build_times_network_check_live(&final));
|
||||
|
||||
for ( ; i < NETWORK_NONLIVE_DISCARD_COUNT; i++) {
|
||||
for ( ; i < CBT_NETWORK_NONLIVE_DISCARD_COUNT; i++) {
|
||||
if (circuit_build_times_add_timeout(&estimate, 0,
|
||||
(time_t)(approx_time()-estimate.timeout_ms/1000.0-1)))
|
||||
estimate.have_computed_timeout = 1;
|
||||
|
||||
if (i < NETWORK_NONLIVE_DISCARD_COUNT-1) {
|
||||
if (i < CBT_NETWORK_NONLIVE_DISCARD_COUNT-1) {
|
||||
if (circuit_build_times_add_timeout(&final, 0,
|
||||
(time_t)(approx_time()-final.timeout_ms/1000.0-1)))
|
||||
final.have_computed_timeout = 1;
|
||||
@ -587,11 +588,11 @@ test_circuit_timeout(void)
|
||||
circuit_build_times_network_is_live(&estimate);
|
||||
circuit_build_times_network_is_live(&final);
|
||||
|
||||
for (i = 0; i < MAX_RECENT_TIMEOUT_COUNT; i++) {
|
||||
for (i = 0; i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT; i++) {
|
||||
if (circuit_build_times_add_timeout(&estimate, 1, approx_time()-1))
|
||||
estimate.have_computed_timeout = 1;
|
||||
|
||||
if (i < MAX_RECENT_TIMEOUT_COUNT-1) {
|
||||
if (i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1) {
|
||||
if (circuit_build_times_add_timeout(&final, 1, approx_time()-1))
|
||||
final.have_computed_timeout = 1;
|
||||
}
|
||||
@ -599,7 +600,7 @@ test_circuit_timeout(void)
|
||||
|
||||
test_assert(estimate.liveness.after_firsthop_idx == 0);
|
||||
test_assert(final.liveness.after_firsthop_idx ==
|
||||
MAX_RECENT_TIMEOUT_COUNT-1);
|
||||
CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1);
|
||||
|
||||
test_assert(circuit_build_times_network_check_live(&estimate));
|
||||
test_assert(circuit_build_times_network_check_live(&final));
|
||||
|
Loading…
Reference in New Issue
Block a user