2005-04-01 22:15:56 +02:00
|
|
|
/* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
|
2004-03-20 02:48:05 +01:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
2005-12-14 21:40:40 +01:00
|
|
|
const char rephist_c_id[] =
|
|
|
|
"$Id$";
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/**
|
|
|
|
* \file rephist.c
|
2005-06-11 20:52:12 +02:00
|
|
|
* \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.
|
2004-05-10 06:34:48 +02:00
|
|
|
**/
|
2004-05-05 23:32:43 +02:00
|
|
|
|
2004-03-20 02:48:05 +01:00
|
|
|
#include "or.h"
|
|
|
|
|
2004-07-20 22:57:46 +02:00
|
|
|
static void bw_arrays_init(void);
|
2004-12-05 08:10:08 +01:00
|
|
|
static void predicted_ports_init(void);
|
2004-07-20 22:57:46 +02:00
|
|
|
|
2005-07-18 08:09:04 +02:00
|
|
|
uint64_t rephist_total_alloc=0;
|
|
|
|
uint32_t rephist_total_num=0;
|
2005-06-06 19:03:21 +02:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** History of an OR-\>OR link. */
|
2004-03-20 02:48:05 +01:00
|
|
|
typedef struct link_history_t {
|
2004-05-10 06:34:48 +02:00
|
|
|
/** When did we start tracking this list? */
|
2004-03-20 02:48:05 +01:00
|
|
|
time_t since;
|
2004-11-21 06:14:46 +01:00
|
|
|
/** When did we most recently note a change to this link */
|
|
|
|
time_t changed;
|
2004-12-01 04:48:14 +01:00
|
|
|
/** How many times did extending from OR1 to OR2 succeed? */
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long n_extend_ok;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** How many times did extending from OR1 to OR2 fail? */
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long n_extend_fail;
|
|
|
|
} link_history_t;
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** History of an OR. */
|
2004-03-20 02:48:05 +01:00
|
|
|
typedef struct or_history_t {
|
2004-05-10 06:34:48 +02:00
|
|
|
/** When did we start tracking this OR? */
|
2004-03-20 02:48:05 +01:00
|
|
|
time_t since;
|
2004-11-21 06:14:46 +01:00
|
|
|
/** When did we most recently note a change to this OR? */
|
|
|
|
time_t changed;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** How many times did we successfully connect? */
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long n_conn_ok;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** How many times did we try to connect and fail?*/
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long n_conn_fail;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** How many seconds have we been connected to this OR before
|
2004-05-05 23:32:43 +02:00
|
|
|
* 'up_since'? */
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long uptime;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** How many seconds have we been unable to connect to this OR before
|
2004-05-05 23:32:43 +02:00
|
|
|
* 'down_since'? */
|
2004-03-20 02:48:05 +01:00
|
|
|
unsigned long downtime;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** If nonzero, we have been connected since this time. */
|
2004-03-20 02:48:05 +01:00
|
|
|
time_t up_since;
|
2004-05-10 06:34:48 +02:00
|
|
|
/** If nonzero, we have been unable to connect since this time. */
|
2004-03-20 02:48:05 +01:00
|
|
|
time_t down_since;
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Map from hex OR2 identity digest to a link_history_t for the link
|
2004-05-05 23:32:43 +02:00
|
|
|
* from this OR to OR2. */
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_t *link_history_map;
|
2004-03-20 02:48:05 +01:00
|
|
|
} or_history_t;
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Map from hex OR identity digest to or_history_t. */
|
2005-10-18 22:12:22 +02:00
|
|
|
static digestmap_t *history_map = NULL;
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return the or_history_t for the named OR, creating it if necessary.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static or_history_t *
|
|
|
|
get_or_history(const char* id)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
or_history_t *hist;
|
2004-07-13 20:23:40 +02:00
|
|
|
|
2005-10-18 22:12:22 +02:00
|
|
|
if (!memcmp(id, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DIGEST_LEN))
|
2004-08-17 09:12:05 +02:00
|
|
|
return NULL;
|
|
|
|
|
2005-10-18 22:12:22 +02:00
|
|
|
hist = digestmap_get(history_map, id);
|
2004-03-20 02:48:05 +01:00
|
|
|
if (!hist) {
|
|
|
|
hist = tor_malloc_zero(sizeof(or_history_t));
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc += sizeof(or_history_t);
|
2005-07-18 08:09:04 +02:00
|
|
|
rephist_total_num++;
|
2005-10-18 22:12:22 +02:00
|
|
|
hist->link_history_map = digestmap_new();
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->since = hist->changed = time(NULL);
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_set(history_map, id, hist);
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
return hist;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return the link_history_t for the link from the first named OR to
|
2004-07-17 00:23:18 +02:00
|
|
|
* the second, creating it if necessary. (ORs are identified by
|
|
|
|
* identity digest)
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static link_history_t *
|
|
|
|
get_link_history(const char *from_id, const char *to_id)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
or_history_t *orhist;
|
|
|
|
link_history_t *lhist;
|
2004-07-13 20:23:40 +02:00
|
|
|
orhist = get_or_history(from_id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!orhist)
|
|
|
|
return NULL;
|
2005-10-18 22:12:22 +02:00
|
|
|
if (!memcmp(to_id, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DIGEST_LEN))
|
2004-08-17 09:12:05 +02:00
|
|
|
return NULL;
|
2005-10-18 22:12:22 +02:00
|
|
|
lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id);
|
2004-03-20 02:48:05 +01:00
|
|
|
if (!lhist) {
|
|
|
|
lhist = tor_malloc_zero(sizeof(link_history_t));
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc += sizeof(link_history_t);
|
2004-11-21 06:14:46 +01:00
|
|
|
lhist->since = lhist->changed = time(NULL);
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_set(orhist->link_history_map, to_id, lhist);
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
return lhist;
|
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** Helper: free storage held by a single link history entry */
|
2004-11-21 06:14:46 +01:00
|
|
|
static void
|
|
|
|
_free_link_history(void *val)
|
|
|
|
{
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= sizeof(link_history_t);
|
2004-11-21 06:14:46 +01:00
|
|
|
tor_free(val);
|
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** Helper: free storage held by a single OR history entry */
|
2004-11-21 06:14:46 +01:00
|
|
|
static void
|
2005-02-11 02:26:47 +01:00
|
|
|
free_or_history(void *_hist)
|
2004-11-21 06:14:46 +01:00
|
|
|
{
|
2005-02-11 02:26:47 +01:00
|
|
|
or_history_t *hist = _hist;
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_free(hist->link_history_map, _free_link_history);
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= sizeof(or_history_t);
|
2005-07-18 08:09:04 +02:00
|
|
|
rephist_total_num--;
|
2004-11-21 06:14:46 +01:00
|
|
|
tor_free(hist);
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Update an or_history_t object <b>hist</b> so that its uptime/downtime
|
|
|
|
* count is up-to-date as of <b>when</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static void
|
|
|
|
update_or_history(or_history_t *hist, time_t when)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(hist);
|
2004-03-20 02:48:05 +01:00
|
|
|
if (hist->up_since) {
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(!hist->down_since);
|
2004-03-20 02:48:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Initialize the static data structures for tracking history.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_init(void)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
2005-10-18 22:12:22 +02:00
|
|
|
history_map = digestmap_new();
|
2004-07-20 22:57:46 +02:00
|
|
|
bw_arrays_init();
|
2004-12-05 08:10:08 +01:00
|
|
|
predicted_ports_init();
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Remember that an attempt to connect to the OR with identity digest
|
|
|
|
* <b>id</b> failed at <b>when</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_connect_failed(const char* id, time_t when)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
or_history_t *hist;
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_or_history(id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 02:48:05 +01:00
|
|
|
++hist->n_conn_fail;
|
|
|
|
if (hist->up_since) {
|
|
|
|
hist->uptime += (when - hist->up_since);
|
|
|
|
hist->up_since = 0;
|
|
|
|
}
|
|
|
|
if (!hist->down_since)
|
|
|
|
hist->down_since = when;
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = when;
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Remember that an attempt to connect to the OR with identity digest
|
|
|
|
* <b>id</b> succeeded at <b>when</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_connect_succeeded(const char* id, time_t when)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
or_history_t *hist;
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_or_history(id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 02:48:05 +01:00
|
|
|
++hist->n_conn_ok;
|
|
|
|
if (hist->down_since) {
|
|
|
|
hist->downtime += (when - hist->down_since);
|
|
|
|
hist->down_since = 0;
|
|
|
|
}
|
|
|
|
if (!hist->up_since)
|
|
|
|
hist->up_since = when;
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = when;
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
2004-03-20 05:59:29 +01:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Remember that we intentionally closed our connection to the OR
|
2004-07-17 00:23:18 +02:00
|
|
|
* with identity digest <b>id</b> at <b>when</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_disconnect(const char* id, time_t when)
|
2004-03-20 05:59:29 +01:00
|
|
|
{
|
|
|
|
or_history_t *hist;
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_or_history(id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 05:59:29 +01:00
|
|
|
++hist->n_conn_ok;
|
|
|
|
if (hist->up_since) {
|
|
|
|
hist->uptime += (when - hist->up_since);
|
|
|
|
hist->up_since = 0;
|
|
|
|
}
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = when;
|
2004-03-20 05:59:29 +01:00
|
|
|
}
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Remember that our connection to the OR with identity digest
|
|
|
|
* <b>id</b> had an error and stopped working at <b>when</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_connection_died(const char* id, time_t when)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
or_history_t *hist;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!id) {
|
2004-11-12 17:39:03 +01:00
|
|
|
/* XXXX009 Well, everybody has an ID now. Hm. */
|
2004-05-18 17:35:21 +02:00
|
|
|
/* If conn has no nickname, it's either an OP, or it is an OR
|
2004-03-20 21:37:49 +01:00
|
|
|
* which didn't complete its handshake (or did and was unapproved).
|
2004-05-18 17:35:21 +02:00
|
|
|
* Ignore it.
|
2004-03-20 21:37:49 +01:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_or_history(id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 02:48:05 +01:00
|
|
|
if (hist->up_since) {
|
|
|
|
hist->uptime += (when - hist->up_since);
|
|
|
|
hist->up_since = 0;
|
|
|
|
}
|
|
|
|
if (!hist->down_since)
|
|
|
|
hist->down_since = when;
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = when;
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Remember that we successfully extended from the OR with identity
|
|
|
|
* digest <b>from_id</b> to the OR with identity digest
|
|
|
|
* <b>to_name</b>.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_extend_succeeded(const char *from_id, const char *to_id)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
link_history_t *hist;
|
2004-03-20 05:59:29 +01:00
|
|
|
/* log_fn(LOG_WARN, "EXTEND SUCCEEDED: %s->%s",from_name,to_name); */
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_link_history(from_id, to_id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 02:48:05 +01:00
|
|
|
++hist->n_extend_ok;
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = time(NULL);
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
2004-03-20 05:59:29 +01:00
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Remember that we tried to extend from the OR with identity digest
|
|
|
|
* <b>from_id</b> to the OR with identity digest <b>to_name</b>, but
|
|
|
|
* failed.
|
2004-03-20 05:59:29 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_extend_failed(const char *from_id, const char *to_id)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
|
|
|
link_history_t *hist;
|
2004-03-20 05:59:29 +01:00
|
|
|
/* log_fn(LOG_WARN, "EXTEND FAILED: %s->%s",from_name,to_name); */
|
2004-07-13 20:23:40 +02:00
|
|
|
hist = get_link_history(from_id, to_id);
|
2004-08-17 09:12:05 +02:00
|
|
|
if (!hist)
|
|
|
|
return;
|
2004-03-20 02:48:05 +01:00
|
|
|
++hist->n_extend_fail;
|
2004-11-21 06:14:46 +01:00
|
|
|
hist->changed = time(NULL);
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
|
2004-12-01 03:54:13 +01:00
|
|
|
/** Log all the reliability data we have remembered, with the chosen
|
2004-03-20 05:59:29 +01:00
|
|
|
* severity.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_dump_stats(time_t now, int severity)
|
2004-03-20 02:48:05 +01:00
|
|
|
{
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_iter_t *lhist_it;
|
|
|
|
digestmap_iter_t *orhist_it;
|
|
|
|
const char *name1, *name2, *digest1, *digest2;
|
|
|
|
char hexdigest1[HEX_DIGEST_LEN+1];
|
2004-03-20 02:48:05 +01:00
|
|
|
or_history_t *or_history;
|
|
|
|
link_history_t *link_history;
|
2004-03-29 08:18:04 +02:00
|
|
|
void *or_history_p, *link_history_p;
|
2004-03-20 02:48:05 +01:00
|
|
|
double uptime;
|
|
|
|
char buffer[2048];
|
2004-10-14 04:47:09 +02:00
|
|
|
size_t len;
|
2004-10-27 23:54:44 +02:00
|
|
|
int ret;
|
2004-03-20 05:59:29 +01:00
|
|
|
unsigned long upt, downt;
|
2004-07-13 20:23:40 +02:00
|
|
|
routerinfo_t *r;
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2005-07-25 12:29:21 +02:00
|
|
|
rep_history_clean(now - get_options()->RephistTrackTime);
|
2004-11-21 06:14:46 +01:00
|
|
|
|
2005-10-19 00:56:40 +02:00
|
|
|
log(severity, LD_GENERAL, "--------------- Dumping history information:");
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2005-12-14 21:40:40 +01:00
|
|
|
for (orhist_it = digestmap_iter_init(history_map);
|
|
|
|
!digestmap_iter_done(orhist_it);
|
2005-10-18 22:12:22 +02:00
|
|
|
orhist_it = digestmap_iter_next(history_map,orhist_it)) {
|
|
|
|
digestmap_iter_get(orhist_it, &digest1, &or_history_p);
|
2004-03-29 08:18:04 +02:00
|
|
|
or_history = (or_history_t*) or_history_p;
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2005-10-18 22:12:22 +02:00
|
|
|
if ((r = router_get_by_digest(digest1)))
|
2004-07-13 20:23:40 +02:00
|
|
|
name1 = r->nickname;
|
|
|
|
else
|
|
|
|
name1 = "(unknown)";
|
2005-10-18 22:12:22 +02:00
|
|
|
base16_encode(hexdigest1, sizeof(hexdigest1), digest1, DIGEST_LEN);
|
2004-03-20 02:48:05 +01:00
|
|
|
update_or_history(or_history, now);
|
2004-03-20 05:59:29 +01:00
|
|
|
upt = or_history->uptime;
|
|
|
|
downt = or_history->downtime;
|
|
|
|
if (upt+downt) {
|
|
|
|
uptime = ((double)upt) / (upt+downt);
|
|
|
|
} else {
|
|
|
|
uptime=1.0;
|
|
|
|
}
|
2005-10-19 00:56:40 +02:00
|
|
|
log(severity, LD_GENERAL,
|
2004-07-13 20:23:40 +02:00
|
|
|
"OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%)",
|
|
|
|
name1, hexdigest1,
|
2004-04-03 04:14:20 +02:00
|
|
|
or_history->n_conn_ok, or_history->n_conn_fail+or_history->n_conn_ok,
|
2004-03-20 05:59:29 +01:00
|
|
|
upt, upt+downt, uptime*100.0);
|
2004-03-20 02:48:05 +01:00
|
|
|
|
2005-10-18 22:12:22 +02:00
|
|
|
if (!digestmap_isempty(or_history->link_history_map)) {
|
2004-12-04 09:56:59 +01:00
|
|
|
strlcpy(buffer, " Extend attempts: ", sizeof(buffer));
|
2004-08-18 11:57:50 +02:00
|
|
|
len = strlen(buffer);
|
2005-10-18 22:12:22 +02:00
|
|
|
for (lhist_it = digestmap_iter_init(or_history->link_history_map);
|
|
|
|
!digestmap_iter_done(lhist_it);
|
2005-12-14 21:40:40 +01:00
|
|
|
lhist_it = digestmap_iter_next(or_history->link_history_map,
|
|
|
|
lhist_it)) {
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_iter_get(lhist_it, &digest2, &link_history_p);
|
|
|
|
if ((r = router_get_by_digest(digest2)))
|
2004-08-18 11:57:50 +02:00
|
|
|
name2 = r->nickname;
|
|
|
|
else
|
|
|
|
name2 = "(unknown)";
|
2004-07-13 20:23:40 +02:00
|
|
|
|
2004-08-18 11:57:50 +02:00
|
|
|
link_history = (link_history_t*) link_history_p;
|
2004-11-09 21:04:00 +01:00
|
|
|
|
2004-10-27 23:54:44 +02:00
|
|
|
ret = tor_snprintf(buffer+len, 2048-len, "%s(%ld/%ld); ", name2,
|
2004-08-18 11:57:50 +02:00
|
|
|
link_history->n_extend_ok,
|
|
|
|
link_history->n_extend_ok+link_history->n_extend_fail);
|
2004-10-27 23:54:44 +02:00
|
|
|
if (ret<0)
|
2004-08-18 11:57:50 +02:00
|
|
|
break;
|
2004-10-27 23:30:47 +02:00
|
|
|
else
|
2004-10-27 23:54:44 +02:00
|
|
|
len += ret;
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
2005-10-19 00:56:40 +02:00
|
|
|
log(severity, LD_GENERAL, "%s", buffer);
|
2004-03-20 02:48:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-21 06:14:46 +01:00
|
|
|
/** Remove history info for routers/links that haven't changed since
|
|
|
|
* <b>before</b> */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_history_clean(time_t before)
|
2004-11-21 06:14:46 +01:00
|
|
|
{
|
|
|
|
or_history_t *or_history;
|
|
|
|
link_history_t *link_history;
|
|
|
|
void *or_history_p, *link_history_p;
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_iter_t *orhist_it, *lhist_it;
|
|
|
|
const char *d1, *d2;
|
2004-11-21 06:14:46 +01:00
|
|
|
|
2005-10-18 22:12:22 +02:00
|
|
|
orhist_it = digestmap_iter_init(history_map);
|
|
|
|
while (!digestmap_iter_done(orhist_it)) {
|
|
|
|
digestmap_iter_get(orhist_it, &d1, &or_history_p);
|
2004-11-21 06:14:46 +01:00
|
|
|
or_history = or_history_p;
|
|
|
|
if (or_history->changed < before) {
|
2005-10-18 22:12:22 +02:00
|
|
|
orhist_it = digestmap_iter_next_rmv(history_map, orhist_it);
|
2005-11-23 05:18:45 +01:00
|
|
|
free_or_history(or_history);
|
2004-11-21 06:14:46 +01:00
|
|
|
continue;
|
|
|
|
}
|
2005-10-18 22:12:22 +02:00
|
|
|
for (lhist_it = digestmap_iter_init(or_history->link_history_map);
|
|
|
|
!digestmap_iter_done(lhist_it); ) {
|
|
|
|
digestmap_iter_get(lhist_it, &d2, &link_history_p);
|
2004-11-21 06:14:46 +01:00
|
|
|
link_history = link_history_p;
|
|
|
|
if (link_history->changed < before) {
|
2005-12-14 21:40:40 +01:00
|
|
|
lhist_it = digestmap_iter_next_rmv(or_history->link_history_map,
|
|
|
|
lhist_it);
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= sizeof(link_history_t);
|
2004-11-21 06:14:46 +01:00
|
|
|
tor_free(link_history);
|
|
|
|
continue;
|
|
|
|
}
|
2005-10-18 22:12:22 +02:00
|
|
|
lhist_it = digestmap_iter_next(or_history->link_history_map,lhist_it);
|
2004-11-21 06:14:46 +01:00
|
|
|
}
|
2005-10-18 22:12:22 +02:00
|
|
|
orhist_it = digestmap_iter_next(history_map, orhist_it);
|
2004-11-21 06:14:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-13 09:42:20 +02:00
|
|
|
#define NUM_SECS_ROLLING_MEASURE 10
|
2004-08-06 22:46:50 +02:00
|
|
|
#define NUM_SECS_BW_SUM_IS_VALID (24*60*60) /* one day */
|
2004-07-20 22:57:46 +02:00
|
|
|
#define NUM_SECS_BW_SUM_INTERVAL (15*60)
|
|
|
|
#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
|
|
|
|
|
|
|
|
/**
|
2004-07-21 01:31:00 +02:00
|
|
|
* Structure to track bandwidth use, and remember the maxima for a given
|
2004-07-20 22:57:46 +02:00
|
|
|
* time period.
|
|
|
|
*/
|
|
|
|
typedef struct bw_array_t {
|
|
|
|
/** Observation array: Total number of bytes transferred in each of the last
|
|
|
|
* NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
|
|
|
|
int obs[NUM_SECS_ROLLING_MEASURE];
|
|
|
|
int cur_obs_idx; /**< Current position in obs. */
|
|
|
|
time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
|
|
|
|
int total_obs; /**< Total for all members of obs except obs[cur_obs_idx] */
|
|
|
|
int max_total; /**< Largest value that total_obs has taken on in the current
|
|
|
|
* period. */
|
2005-12-14 21:40:40 +01:00
|
|
|
uint64_t total_in_period; /**< Total bytes transferred in the current
|
|
|
|
* period. */
|
2004-07-20 22:57:46 +02:00
|
|
|
|
|
|
|
/** When does the next period begin? */
|
|
|
|
time_t next_period;
|
|
|
|
/** Where in 'maxima' should the maximum bandwidth usage for the current
|
|
|
|
* period be stored? */
|
|
|
|
int next_max_idx;
|
2004-08-07 04:46:16 +02:00
|
|
|
/** How many values in maxima/totals have been set ever? */
|
|
|
|
int num_maxes_set;
|
|
|
|
/** Circular array of the maximum
|
|
|
|
* bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
|
|
|
|
* NUM_TOTALS periods */
|
2004-07-20 22:57:46 +02:00
|
|
|
int maxima[NUM_TOTALS];
|
2004-08-07 04:46:16 +02:00
|
|
|
/** Circular array of the total bandwidth usage for the last NUM_TOTALS
|
|
|
|
* periods */
|
2005-09-23 10:29:58 +02:00
|
|
|
uint64_t totals[NUM_TOTALS];
|
2004-07-20 22:57:46 +02:00
|
|
|
} bw_array_t;
|
|
|
|
|
2004-07-21 01:31:00 +02:00
|
|
|
/** Shift the current period of b forward by one.
|
2004-07-20 22:57:46 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static void
|
|
|
|
commit_max(bw_array_t *b)
|
|
|
|
{
|
2004-08-07 04:46:16 +02:00
|
|
|
/* Store total from current period. */
|
|
|
|
b->totals[b->next_max_idx] = b->total_in_period;
|
2004-07-20 22:57:46 +02:00
|
|
|
/* Store maximum from current period. */
|
|
|
|
b->maxima[b->next_max_idx++] = b->max_total;
|
|
|
|
/* Advance next_period and next_max_idx */
|
|
|
|
b->next_period += NUM_SECS_BW_SUM_INTERVAL;
|
|
|
|
if (b->next_max_idx == NUM_TOTALS)
|
|
|
|
b->next_max_idx = 0;
|
2004-08-07 04:46:16 +02:00
|
|
|
if (b->num_maxes_set < NUM_TOTALS)
|
|
|
|
++b->num_maxes_set;
|
2004-07-20 22:57:46 +02:00
|
|
|
/* Reset max_total. */
|
|
|
|
b->max_total = 0;
|
2004-08-07 07:13:55 +02:00
|
|
|
/* Reset total_in_period. */
|
|
|
|
b->total_in_period = 0;
|
2004-07-20 22:57:46 +02:00
|
|
|
}
|
|
|
|
|
2004-07-21 01:31:00 +02:00
|
|
|
/** Shift the current observation time of 'b' forward by one second.
|
2004-07-20 22:57:46 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE void
|
|
|
|
advance_obs(bw_array_t *b)
|
|
|
|
{
|
2004-07-20 22:57:46 +02:00
|
|
|
int nextidx;
|
|
|
|
int total;
|
|
|
|
|
|
|
|
/* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
|
|
|
|
* seconds; adjust max_total as needed.*/
|
|
|
|
total = b->total_obs + b->obs[b->cur_obs_idx];
|
|
|
|
if (total > b->max_total)
|
|
|
|
b->max_total = total;
|
|
|
|
|
|
|
|
nextidx = b->cur_obs_idx+1;
|
|
|
|
if (nextidx == NUM_SECS_ROLLING_MEASURE)
|
|
|
|
nextidx = 0;
|
|
|
|
|
|
|
|
b->total_obs = total - b->obs[nextidx];
|
|
|
|
b->obs[nextidx]=0;
|
|
|
|
b->cur_obs_idx = nextidx;
|
|
|
|
|
|
|
|
if (++b->cur_obs_time >= b->next_period)
|
|
|
|
commit_max(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add 'n' bytes to the number of bytes in b for second 'when'.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE void
|
|
|
|
add_obs(bw_array_t *b, time_t when, int n)
|
|
|
|
{
|
2004-07-21 01:25:00 +02:00
|
|
|
/* Don't record data in the past. */
|
|
|
|
if (when<b->cur_obs_time)
|
|
|
|
return;
|
|
|
|
/* If we're currently adding observations for an earlier second than
|
|
|
|
* 'when', advance b->cur_obs_time and b->cur_obs_idx by an
|
|
|
|
* appropriate number of seconds, and do all the other housekeeping */
|
|
|
|
while (when>b->cur_obs_time)
|
2004-07-20 22:57:46 +02:00
|
|
|
advance_obs(b);
|
2004-07-21 01:25:00 +02:00
|
|
|
|
2004-07-20 22:57:46 +02:00
|
|
|
b->obs[b->cur_obs_idx] += n;
|
2004-08-07 04:46:16 +02:00
|
|
|
b->total_in_period += n;
|
2004-07-20 22:57:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Allocate, initialize, and return a new bw_array.
|
|
|
|
*/
|
2005-09-30 03:39:24 +02:00
|
|
|
static bw_array_t *
|
|
|
|
bw_array_new(void)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-07-20 22:57:46 +02:00
|
|
|
bw_array_t *b;
|
|
|
|
time_t start;
|
|
|
|
b = tor_malloc_zero(sizeof(bw_array_t));
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc += sizeof(bw_array_t);
|
2004-07-20 22:57:46 +02:00
|
|
|
start = time(NULL);
|
|
|
|
b->cur_obs_time = start;
|
|
|
|
b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bw_array_t *read_array = NULL;
|
|
|
|
static bw_array_t *write_array = NULL;
|
|
|
|
|
|
|
|
/** Set up read_array and write_array
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static void
|
|
|
|
bw_arrays_init(void)
|
2004-07-20 22:57:46 +02:00
|
|
|
{
|
|
|
|
read_array = bw_array_new();
|
|
|
|
write_array = bw_array_new();
|
|
|
|
}
|
2004-07-13 09:42:20 +02:00
|
|
|
|
|
|
|
/** We read <b>num_bytes</b> more bytes in second <b>when</b>.
|
|
|
|
*
|
|
|
|
* Add num_bytes to the current running total for <b>when</b>.
|
|
|
|
*
|
|
|
|
* <b>when</b> can go back to time, but it's safe to ignore calls
|
2004-07-13 18:58:01 +02:00
|
|
|
* earlier than the latest <b>when</b> you've heard of.
|
2004-07-13 09:42:20 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_bytes_written(int num_bytes, time_t when)
|
|
|
|
{
|
2004-07-13 09:42:20 +02:00
|
|
|
/* Maybe a circular array for recent seconds, and step to a new point
|
|
|
|
* every time a new second shows up. Or simpler is to just to have
|
|
|
|
* a normal array and push down each item every second; it's short.
|
|
|
|
*/
|
|
|
|
/* When a new second has rolled over, compute the sum of the bytes we've
|
|
|
|
* seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
|
|
|
|
* somewhere. See rep_hist_bandwidth_assess() below.
|
|
|
|
*/
|
2004-07-20 22:57:46 +02:00
|
|
|
add_obs(write_array, when, num_bytes);
|
2004-07-13 09:42:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** We wrote <b>num_bytes</b> more bytes in second <b>when</b>.
|
|
|
|
* (like rep_hist_note_bytes_written() above)
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_bytes_read(int num_bytes, time_t when)
|
|
|
|
{
|
2004-07-13 09:42:20 +02:00
|
|
|
/* if we're smart, we can make this func and the one above share code */
|
2004-07-20 22:57:46 +02:00
|
|
|
add_obs(read_array, when, num_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper: Return the largest value in b->maxima. (This is equal to the
|
|
|
|
* most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
|
|
|
|
* NUM_SECS_BW_SUM_IS_VALID seconds.)
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
static int
|
|
|
|
find_largest_max(bw_array_t *b)
|
2004-07-20 22:57:46 +02:00
|
|
|
{
|
|
|
|
int i,max;
|
|
|
|
max=0;
|
|
|
|
for (i=0; i<NUM_TOTALS; ++i) {
|
|
|
|
if (b->maxima[i]>max)
|
|
|
|
max = b->maxima[i];
|
|
|
|
}
|
|
|
|
return max;
|
2004-07-13 09:42:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
|
|
|
|
* seconds. Find one sum for reading and one for writing. They don't have
|
|
|
|
* to be at the same time).
|
|
|
|
*
|
|
|
|
* Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
rep_hist_bandwidth_assess(void)
|
|
|
|
{
|
2004-07-20 22:57:46 +02:00
|
|
|
int w,r;
|
|
|
|
r = find_largest_max(read_array);
|
|
|
|
w = find_largest_max(write_array);
|
|
|
|
if (r>w)
|
2004-08-04 01:57:05 +02:00
|
|
|
return (int)(w/(double)NUM_SECS_ROLLING_MEASURE);
|
2004-07-20 22:57:46 +02:00
|
|
|
else
|
2004-08-04 01:57:05 +02:00
|
|
|
return (int)(r/(double)NUM_SECS_ROLLING_MEASURE);
|
2004-07-13 09:42:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-07 04:46:16 +02:00
|
|
|
/**
|
2004-11-09 19:22:17 +01:00
|
|
|
* Allocate and return lines for representing this server's bandwidth
|
|
|
|
* history in its descriptor.
|
2004-08-07 04:46:16 +02:00
|
|
|
*/
|
2004-11-09 19:22:17 +01:00
|
|
|
char *
|
|
|
|
rep_hist_get_bandwidth_lines(void)
|
2004-08-07 04:46:16 +02:00
|
|
|
{
|
|
|
|
char *buf, *cp;
|
|
|
|
char t[ISO_TIME_LEN+1];
|
|
|
|
int r, i, n;
|
|
|
|
bw_array_t *b;
|
|
|
|
size_t len;
|
|
|
|
|
2004-11-09 19:22:17 +01:00
|
|
|
/* opt (read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n,n,n... */
|
2005-09-23 10:29:58 +02:00
|
|
|
len = (60+20*NUM_TOTALS)*2;
|
2004-08-07 04:46:16 +02:00
|
|
|
buf = tor_malloc_zero(len);
|
|
|
|
cp = buf;
|
|
|
|
for (r=0;r<2;++r) {
|
|
|
|
b = r?read_array:write_array;
|
2004-11-23 10:01:37 +01:00
|
|
|
tor_assert(b);
|
2004-08-07 04:46:16 +02:00
|
|
|
format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
|
2005-09-23 10:29:58 +02:00
|
|
|
tor_snprintf(cp, len-(cp-buf), "opt %s %s (%d s) ",
|
2005-09-23 19:02:50 +02:00
|
|
|
r ? "read-history" : "write-history", t,
|
2005-09-23 10:29:58 +02:00
|
|
|
NUM_SECS_BW_SUM_INTERVAL);
|
2004-08-07 04:46:16 +02:00
|
|
|
cp += strlen(cp);
|
2004-08-07 07:13:55 +02:00
|
|
|
|
2004-08-08 21:14:44 +02:00
|
|
|
if (b->num_maxes_set <= b->next_max_idx)
|
|
|
|
/* We haven't been through the circular array yet; time starts at i=0.*/
|
2004-08-07 07:13:55 +02:00
|
|
|
i = 0;
|
|
|
|
else
|
2004-12-01 04:48:14 +01:00
|
|
|
/* We've been around the array at least once. The next i to be
|
2004-08-08 21:14:44 +02:00
|
|
|
overwritten is the oldest. */
|
2004-08-07 07:13:55 +02:00
|
|
|
i = b->next_max_idx;
|
|
|
|
|
|
|
|
for (n=0; n<b->num_maxes_set; ++n,++i) {
|
|
|
|
while (i >= NUM_TOTALS) i -= NUM_TOTALS;
|
2004-08-07 04:46:16 +02:00
|
|
|
if (n==(b->num_maxes_set-1))
|
2005-09-23 10:29:58 +02:00
|
|
|
tor_snprintf(cp, len-(cp-buf), U64_FORMAT,
|
|
|
|
U64_PRINTF_ARG(b->totals[i]));
|
2004-08-07 04:46:16 +02:00
|
|
|
else
|
2005-09-23 10:29:58 +02:00
|
|
|
tor_snprintf(cp, len-(cp-buf), U64_FORMAT",",
|
|
|
|
U64_PRINTF_ARG(b->totals[i]));
|
2004-08-07 04:46:16 +02:00
|
|
|
cp += strlen(cp);
|
|
|
|
}
|
2004-10-27 08:25:29 +02:00
|
|
|
strlcat(cp, "\n", len-(cp-buf));
|
2004-08-07 04:46:16 +02:00
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2004-12-05 08:10:08 +01:00
|
|
|
/** A list of port numbers that have been used recently. */
|
|
|
|
static smartlist_t *predicted_ports_list=NULL;
|
|
|
|
/** The corresponding most recently used time for each port. */
|
|
|
|
static smartlist_t *predicted_ports_times=NULL;
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** DOCDOC */
|
|
|
|
static void
|
|
|
|
add_predicted_port(uint16_t port, time_t now)
|
|
|
|
{
|
2005-06-06 19:03:21 +02:00
|
|
|
/* XXXX we could just use uintptr_t here, I think. */
|
2004-12-05 08:10:08 +01:00
|
|
|
uint16_t *tmp_port = tor_malloc(sizeof(uint16_t));
|
|
|
|
time_t *tmp_time = tor_malloc(sizeof(time_t));
|
|
|
|
*tmp_port = port;
|
|
|
|
*tmp_time = now;
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc += sizeof(uint16_t) + sizeof(time_t);
|
2004-12-05 08:10:08 +01:00
|
|
|
smartlist_add(predicted_ports_list, tmp_port);
|
|
|
|
smartlist_add(predicted_ports_times, tmp_time);
|
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** DOCDOC */
|
|
|
|
static void
|
|
|
|
predicted_ports_init(void)
|
|
|
|
{
|
2004-12-05 08:10:08 +01:00
|
|
|
predicted_ports_list = smartlist_create();
|
|
|
|
predicted_ports_times = smartlist_create();
|
|
|
|
add_predicted_port(80, time(NULL)); /* add one to kickstart us */
|
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** DOCDOC */
|
|
|
|
static void
|
|
|
|
predicted_ports_free(void)
|
|
|
|
{
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= smartlist_len(predicted_ports_list)*sizeof(uint16_t);
|
2005-02-28 02:59:18 +01:00
|
|
|
SMARTLIST_FOREACH(predicted_ports_list, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(predicted_ports_list);
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= smartlist_len(predicted_ports_times)*sizeof(time_t);
|
2005-02-28 02:59:18 +01:00
|
|
|
SMARTLIST_FOREACH(predicted_ports_times, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(predicted_ports_times);
|
|
|
|
}
|
|
|
|
|
2004-12-05 08:10:08 +01:00
|
|
|
/** Remember that <b>port</b> has been asked for as of time <b>now</b>.
|
|
|
|
* This is used for predicting what sorts of streams we'll make in the
|
2005-11-25 09:08:56 +01:00
|
|
|
* future and making exit circuits to anticipate that.
|
2004-12-05 08:10:08 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
rep_hist_note_used_port(uint16_t port, time_t now)
|
|
|
|
{
|
2004-12-05 08:10:08 +01:00
|
|
|
int i;
|
|
|
|
uint16_t *tmp_port;
|
|
|
|
time_t *tmp_time;
|
|
|
|
|
|
|
|
tor_assert(predicted_ports_list);
|
|
|
|
tor_assert(predicted_ports_times);
|
|
|
|
|
2004-12-07 06:33:55 +01:00
|
|
|
if (!port) /* record nothing */
|
2004-12-05 08:10:08 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
|
|
|
|
tmp_port = smartlist_get(predicted_ports_list, i);
|
|
|
|
tmp_time = smartlist_get(predicted_ports_times, i);
|
|
|
|
if (*tmp_port == port) {
|
|
|
|
*tmp_time = now;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* it's not there yet; we need to add it */
|
|
|
|
add_predicted_port(port, now);
|
|
|
|
}
|
|
|
|
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
#define PREDICTED_CIRCS_RELEVANCE_TIME (3600) /* 1 hour */
|
2004-12-05 08:10:08 +01:00
|
|
|
|
2004-12-07 16:29:54 +01:00
|
|
|
/** Return a pointer to the list of port numbers that
|
2004-12-05 08:10:08 +01:00
|
|
|
* are likely to be asked for in the near future.
|
2004-12-07 16:29:54 +01:00
|
|
|
*
|
|
|
|
* The caller promises not to mess with it.
|
2004-12-05 08:10:08 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
smartlist_t *
|
|
|
|
rep_hist_get_predicted_ports(time_t now)
|
|
|
|
{
|
2004-12-05 08:10:08 +01:00
|
|
|
int i;
|
|
|
|
uint16_t *tmp_port;
|
|
|
|
time_t *tmp_time;
|
|
|
|
|
|
|
|
tor_assert(predicted_ports_list);
|
|
|
|
tor_assert(predicted_ports_times);
|
|
|
|
|
|
|
|
/* clean out obsolete entries */
|
|
|
|
for (i = 0; i < smartlist_len(predicted_ports_list); ++i) {
|
|
|
|
tmp_time = smartlist_get(predicted_ports_times, i);
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
if (*tmp_time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
|
2004-12-05 08:10:08 +01:00
|
|
|
tmp_port = smartlist_get(predicted_ports_list, i);
|
2005-10-19 00:56:40 +02:00
|
|
|
debug(LD_CIRC, "Expiring predicted port %d", *tmp_port);
|
2004-12-05 08:10:08 +01:00
|
|
|
smartlist_del(predicted_ports_list, i);
|
|
|
|
smartlist_del(predicted_ports_times, i);
|
2005-06-06 19:03:21 +02:00
|
|
|
rephist_total_alloc -= sizeof(uint16_t)+sizeof(time_t);
|
2004-12-05 08:10:08 +01:00
|
|
|
tor_free(tmp_port);
|
|
|
|
tor_free(tmp_time);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
2004-12-07 16:29:54 +01:00
|
|
|
return predicted_ports_list;
|
2004-12-05 08:10:08 +01:00
|
|
|
}
|
|
|
|
|
2005-11-25 09:08:56 +01:00
|
|
|
/** The user asked us to do a resolve. Rather than keeping track of
|
|
|
|
* timings and such of resolves, we fake it for now by making treating
|
|
|
|
* it the same way as a connection to port 80. This way we will continue
|
|
|
|
* to have circuits lying around if the user only uses Tor for resolves.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
rep_hist_note_used_resolve(time_t now)
|
|
|
|
{
|
|
|
|
rep_hist_note_used_port(80, now);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
int
|
|
|
|
rep_hist_get_predicted_resolve(time_t now)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
/** The last time at which we needed an internal circ. */
|
2005-11-25 09:08:56 +01:00
|
|
|
static time_t predicted_internal_time = 0;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
/** The last time we needed an internal circ with good uptime. */
|
2005-11-25 09:08:56 +01:00
|
|
|
static time_t predicted_internal_uptime_time = 0;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
/** The last time we needed an internal circ with good capacity. */
|
2005-11-25 09:08:56 +01:00
|
|
|
static time_t predicted_internal_capacity_time = 0;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
|
|
|
|
/** Remember that we used an internal circ at time <b>now</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2005-11-25 09:08:56 +01:00
|
|
|
rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2005-11-25 09:08:56 +01:00
|
|
|
predicted_internal_time = now;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
if (need_uptime)
|
2005-11-25 09:08:56 +01:00
|
|
|
predicted_internal_uptime_time = now;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
if (need_capacity)
|
2005-11-25 09:08:56 +01:00
|
|
|
predicted_internal_capacity_time = now;
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return 1 if we've used an internal circ recently; else return 0. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2005-12-14 21:40:40 +01:00
|
|
|
rep_hist_get_predicted_internal(time_t now, int *need_uptime,
|
|
|
|
int *need_capacity)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2005-11-25 09:08:56 +01:00
|
|
|
if (!predicted_internal_time) { /* initialize it */
|
|
|
|
predicted_internal_time = now;
|
|
|
|
predicted_internal_uptime_time = now;
|
|
|
|
predicted_internal_capacity_time = now;
|
2005-08-13 02:22:07 +02:00
|
|
|
}
|
2005-11-25 09:08:56 +01:00
|
|
|
if (predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
return 0; /* too long ago */
|
2005-11-25 09:08:56 +01:00
|
|
|
if (predicted_internal_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
*need_uptime = 1;
|
2005-11-25 09:08:56 +01:00
|
|
|
if (predicted_internal_capacity_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
*need_capacity = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** Free all storage held by the OR/link history caches, by the
|
|
|
|
* bandwidth history arrays, or by the port history. */
|
|
|
|
void
|
|
|
|
rep_hist_free_all(void)
|
2005-02-11 00:18:39 +01:00
|
|
|
{
|
2005-10-18 22:12:22 +02:00
|
|
|
digestmap_free(history_map, free_or_history);
|
2005-02-11 00:18:39 +01:00
|
|
|
tor_free(read_array);
|
|
|
|
tor_free(write_array);
|
2005-02-28 02:59:18 +01:00
|
|
|
predicted_ports_free();
|
2005-02-11 00:18:39 +01:00
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|