Back to index

tor  0.2.3.18-rc
Classes | Defines | Typedefs | Functions | Variables
rephist.c File Reference

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; further, exit port statistics, cell statistics, and connection statistics. More...

#include "or.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "ht.h"

Go to the source code of this file.

Classes

struct  or_history_t
 History of an OR. More...
struct  bw_array_t
 Structure to track bandwidth use, and remember the maxima for a given time period. More...
struct  predicted_port_t
 A single predicted port: used to remember which ports we've made connections to, so that we can try to keep making circuits that can handle those ports. More...
struct  circ_buffer_stats_t
 Statistics from a single circuit. More...
struct  bidi_map_entry_t
 Entry in a map from connection ID to the number of read and written bytes on this connection in a BIDI_INTERVAL second interval. More...

Defines

#define STABILITY_EPSILON   0.0001
 If the total weighted run count of all runs for a router ever falls below this amount, the router can be treated as having 0 MTBF.
#define STABILITY_ALPHA   0.95
 Value by which to discount all old intervals for MTBF purposes.
#define STABILITY_INTERVAL   (12*60*60)
 Interval at which to discount all old intervals for MTBF purposes.
#define SUBTRACT_CLAMPED(var, penalty)   do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0)
#define PUT(s)   STMT_BEGIN if (fputs((s),f)<0) goto err; STMT_END
#define PRINTF(args)   STMT_BEGIN if (fprintf args <0) goto err; STMT_END
#define MAX_STABILITY_DOC_BUILD_RATE   (3*60)
 Shortest allowable time between building two stability documents.
#define NUM_SECS_ROLLING_MEASURE   10
 For how many seconds do we keep track of individual per-second bandwidth totals?
#define NUM_SECS_BW_SUM_INTERVAL   (15*60)
 How large are the intervals for which we track and report bandwidth use?
#define NUM_SECS_BW_SUM_IS_VALID   (24*60*60)
 How far in the past do we remember and publish bandwidth use?
#define NUM_TOTALS   (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
 How many bandwidth usage intervals do we remember? (derived)
#define MAX_HIST_VALUE_LEN   21*NUM_TOTALS
#define UPDATE(arrname, st)
#define LOAD(arrname, st)
#define PREDICTED_CIRCS_RELEVANCE_TIME   (60*60)
 For this long after we've seen a request for a given port, assume that we'll want to make connections to the same port in the future.
#define EXIT_STATS_ROUND_UP_BYTES   1024
 To what multiple should byte numbers be rounded up?
#define EXIT_STATS_ROUND_UP_STREAMS   4
 To what multiple should stream counts be rounded up?
#define EXIT_STATS_NUM_PORTS   65536
 Number of TCP ports.
#define EXIT_STATS_TOP_N_PORTS   10
 Top n ports that will be included in exit stats.
#define SHARES   10
#define BIDI_THRESHOLD   20480
#define BIDI_FACTOR   10
#define BIDI_INTERVAL   10

Typedefs

typedef struct link_history_t link_history_t
 History of an OR->OR link.
typedef struct or_history_t or_history_t
 History of an OR.
typedef struct bw_array_t bw_array_t
 Structure to track bandwidth use, and remember the maxima for a given time period.
typedef struct predicted_port_t predicted_port_t
 A single predicted port: used to remember which ports we've made connections to, so that we can try to keep making circuits that can handle those ports.
typedef struct circ_buffer_stats_t circ_buffer_stats_t
 Statistics from a single circuit.
typedef struct bidi_map_entry_t bidi_map_entry_t
 Entry in a map from connection ID to the number of read and written bytes on this connection in a BIDI_INTERVAL second interval.

Functions

static void bw_arrays_init (void)
 Set up [dir-]read_array and [dir-]write_array, freeing them if they already exist.
static void predicted_ports_init (void)
 Initialize whatever memory and structs are needed for predicting which ports will be used.
static or_history_tget_or_history (const char *id)
 Return the or_history_t for the OR with identity digest id, creating it if necessary.
static link_history_tget_link_history (const char *from_id, const char *to_id)
 Return the link_history_t for the link from the first named OR to the second, creating it if necessary.
static void _free_link_history (void *val)
 Helper: free storage held by a single link history entry.
static void free_or_history (void *_hist)
 Helper: free storage held by a single OR history entry.
static void update_or_history (or_history_t *hist, time_t when)
 Update an or_history_t object hist so that its uptime/downtime count is up-to-date as of when.
void rep_hist_init (void)
 Initialize the static data structures for tracking history.
static void mark_or_down (or_history_t *hist, time_t when, int failed)
 Helper: note that we are no longer connected to the router with history hist.
static void mark_or_up (or_history_t *hist, time_t when)
 Helper: note that we are connected to the router with history hist.
void rep_hist_note_connect_failed (const char *id, time_t when)
 Remember that an attempt to connect to the OR with identity digest id failed at when.
void rep_hist_note_connect_succeeded (const char *id, time_t when)
 Remember that an attempt to connect to the OR with identity digest id succeeded at when.
void rep_hist_note_disconnect (const char *id, time_t when)
 Remember that we intentionally closed our connection to the OR with identity digest id at when.
void rep_hist_note_connection_died (const char *id, time_t when)
 Remember that our connection to the OR with identity digest id had an error and stopped working at when.
void rep_hist_note_router_reachable (const char *id, const tor_addr_t *at_addr, const uint16_t at_port, time_t when)
 We have just decided that this router with identity digest id is reachable, meaning we will give it a "Running" flag for the next while.
void rep_hist_note_router_unreachable (const char *id, time_t when)
 We have just decided that this router is unreachable, meaning we are taking away its "Running" flag.
time_t rep_hist_downrate_old_runs (time_t now)
 Helper: Discount all old MTBF data, if it is time to do so.
static double get_stability (or_history_t *hist, time_t when)
 Helper: Return the weighted MTBF of the router with history hist.
static long get_total_weighted_time (or_history_t *hist, time_t when)
 Return the total amount of time we've been observing, with each run of time downrated by the appropriate factor.
static double get_weighted_fractional_uptime (or_history_t *hist, time_t when)
 Helper: Return the weighted percent-of-time-online of the router with history hist.
long rep_hist_get_uptime (const char *id, time_t when)
 Return how long the router whose identity digest is id has been reachable.
double rep_hist_get_stability (const char *id, time_t when)
 Return an estimated MTBF for the router whose identity digest is id.
double rep_hist_get_weighted_fractional_uptime (const char *id, time_t when)
 Return an estimated percent-of-time-online for the router whose identity digest is id.
long rep_hist_get_weighted_time_known (const char *id, time_t when)
 Return a number representing how long we've known about the router whose digest is id.
int rep_hist_have_measured_enough_stability (void)
 Return true if we've been measuring MTBFs for long enough to pronounce on Stability.
void rep_hist_note_extend_succeeded (const char *from_id, const char *to_id)
 Remember that we successfully extended from the OR with identity digest from_id to the OR with identity digest to_name.
void rep_hist_note_extend_failed (const char *from_id, const char *to_id)
 Remember that we tried to extend from the OR with identity digest from_id to the OR with identity digest to_name, but failed.
void rep_hist_dump_stats (time_t now, int severity)
 Log all the reliability data we have remembered, with the chosen severity.
void rep_history_clean (time_t before)
 Remove history info for routers/links that haven't changed since before.
int rep_hist_record_mtbf_data (time_t now, int missing_means_down)
 Write MTBF data to disk.
static char * rep_hist_format_router_status (or_history_t *hist, time_t now)
 Format the current tracked status of the router in hist at time now for analysis; return it in a newly allocated string.
const char * rep_hist_get_router_stability_doc (time_t now)
 Return a pointer to a NUL-terminated document describing our view of the stability of the routers we've been tracking.
static int find_next_with (smartlist_t *sl, int i, const char *prefix)
 Helper: return the first j >= i such that !strcmpstart(sl[j], prefix) and such that no line sl[k] with i <= k < j starts with "R ".
static int parse_possibly_bad_iso_time (const char *s, time_t *time_out)
 Parse the ISO-formatted time in s into *time_out, but round any pre-1970 date to Jan 1, 1970.
static INLINE time_t correct_time (time_t t, time_t now, time_t stored_at, time_t started_measuring)
 We've read a time t from a file stored at stored_at, which says we started measuring at started_measuring.
int rep_hist_load_mtbf_data (time_t now)
 Load MTBF data from disk.
static void commit_max (bw_array_t *b)
 Shift the current period of b forward by one.
static INLINE void advance_obs (bw_array_t *b)
 Shift the current observation time of b forward by one second.
static INLINE void add_obs (bw_array_t *b, time_t when, uint64_t n)
 Add n bytes to the number of bytes in b for second when.
static bw_array_tbw_array_new (void)
 Allocate, initialize, and return a new bw_array.
void rep_hist_note_bytes_written (size_t num_bytes, time_t when)
 Remember that we read num_bytes bytes in second when.
void rep_hist_note_bytes_read (size_t num_bytes, time_t when)
 Remember that we wrote num_bytes bytes in second when.
void rep_hist_note_dir_bytes_written (size_t num_bytes, time_t when)
 Remember that we wrote num_bytes directory bytes in second when.
void rep_hist_note_dir_bytes_read (size_t num_bytes, time_t when)
 Remember that we read num_bytes directory bytes in second when.
static uint64_t find_largest_max (bw_array_t *b)
 Helper: Return the largest value in b->maxima.
int rep_hist_bandwidth_assess (void)
 Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly) seconds.
static size_t rep_hist_fill_bandwidth_history (char *buf, size_t len, const bw_array_t *b)
 Print the bandwidth history of b (either [dir-]read_array or [dir-]write_array) into the buffer pointed to by buf.
char * rep_hist_get_bandwidth_lines (void)
 Allocate and return lines for representing this server's bandwidth history in its descriptor.
static void rep_hist_update_bwhist_state_section (or_state_t *state, const bw_array_t *b, smartlist_t **s_values, smartlist_t **s_maxima, time_t *s_begins, int *s_interval)
 Write a single bw_array_t into the Values, Ends, Interval, and Maximum entries of an or_state_t.
void rep_hist_update_state (or_state_t *state)
 Update state with the newest bandwidth history.
static int rep_hist_load_bwhist_state_section (bw_array_t *b, const smartlist_t *s_values, const smartlist_t *s_maxima, const time_t s_begins, const int s_interval)
 Load a single bw_array_t from its Values, Ends, Maxima, and Interval entries in an or_state_t.
int rep_hist_load_state (or_state_t *state, char **err)
 Set bandwidth history from the state file we just loaded.
static void add_predicted_port (time_t now, uint16_t port)
 We just got an application request for a connection with port port.
static void predicted_ports_free (void)
 Free whatever memory is needed for predicting which ports will be used.
void rep_hist_note_used_port (time_t now, uint16_t port)
 Remember that port has been asked for as of time now.
smartlist_trep_hist_get_predicted_ports (time_t now)
 Return a newly allocated pointer to a list of uint16_t * for ports that are likely to be asked for in the near future.
void rep_hist_remove_predicted_ports (const smartlist_t *rmv_ports)
 Take a list of uint16_t *, and remove every port in the list from the current list of predicted ports.
void rep_hist_note_used_resolve (time_t now)
 The user asked us to do a resolve.
void rep_hist_note_used_internal (time_t now, int need_uptime, int need_capacity)
 Remember that we used an internal circ at time now.
int rep_hist_get_predicted_internal (time_t now, int *need_uptime, int *need_capacity)
 Return 1 if we've used an internal circ recently; else return 0.
int any_predicted_circuits (time_t now)
 Any ports used lately? These are pre-seeded if we just started up or if we're running a hidden service.
int rep_hist_circbuilding_dormant (time_t now)
 Return 1 if we have no need for circuits currently, else return 0.
void note_crypto_pk_op (pk_op_t operation)
 Increment the count of the number of times we've done operation.
void dump_pk_ops (int severity)
 Log the number of times we've done each public/private-key operation.
void rep_hist_exit_stats_init (time_t now)
 Initialize exit port stats.
void rep_hist_reset_exit_stats (time_t now)
 Reset counters for exit port statistics.
void rep_hist_exit_stats_term (void)
 Stop collecting exit port stats in a way that we can re-start doing so in rep_hist_exit_stats_init().
static int _compare_int (const void *x, const void *y)
 Helper for qsort: compare two ints.
char * rep_hist_format_exit_stats (time_t now)
 Return a newly allocated string containing the exit port statistics until now, or NULL if we're not collecting exit stats.
time_t rep_hist_exit_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current exit port stats period, write exit stats to $DATADIR/stats/exit-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_note_exit_bytes (uint16_t port, size_t num_written, size_t num_read)
 Note that we wrote num_written bytes and read num_read bytes to/from an exit connection to port.
void rep_hist_note_exit_stream_opened (uint16_t port)
 Note that we opened an exit stream to port.
void rep_hist_buffer_stats_init (time_t now)
 Initialize buffer stats.
void rep_hist_add_buffer_stats (double mean_num_cells_in_queue, double mean_time_cells_in_queue, uint32_t processed_cells)
 Remember cell statistics mean_num_cells_in_queue, mean_time_cells_in_queue, and processed_cells of a circuit.
void rep_hist_buffer_stats_add_circ (circuit_t *circ, time_t end_of_interval)
 Remember cell statistics for circuit circ at time end_of_interval and reset cell counters in case the circuit remains open in the next measurement interval.
static int _buffer_stats_compare_entries (const void **_a, const void **_b)
 Sorting helper: return -1, 1, or 0 based on comparison of two circ_buffer_stats_t.
void rep_hist_buffer_stats_term (void)
 Stop collecting cell stats in a way that we can re-start doing so in rep_hist_buffer_stats_init().
void rep_hist_reset_buffer_stats (time_t now)
 Clear history of circuit statistics and set the measurement interval start to now.
char * rep_hist_format_buffer_stats (time_t now)
 Return a newly allocated string containing the buffer statistics until now, or NULL if we're not collecting buffer stats.
time_t rep_hist_buffer_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current buffer stats period, write buffer stats to $DATADIR/stats/buffer-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_desc_stats_init (time_t now)
 Initialize descriptor stats.
static void rep_hist_reset_desc_stats (time_t now)
 Reset served descs stats to empty, starting a new interval now.
void rep_hist_desc_stats_term (void)
 Stop collecting served descs stats, so that rep_hist_desc_stats_init() is safe to be called again.
static char * rep_hist_format_desc_stats (time_t now)
 Helper for rep_hist_desc_stats_write().
time_t rep_hist_desc_stats_write (time_t now)
 If WRITE_STATS_INTERVAL seconds have passed since the beginning of the current served desc stats interval, write the stats to $DATADIR/stats/served-desc-stats (possibly appending to an existing file) and reset the state for the next interval.
void rep_hist_note_desc_served (const char *desc)
void rep_hist_conn_stats_init (time_t now)
 Initialize connection stats.
static HT_HEAD (bidimap, bidi_map_entry_t)
 Map of OR connections together with the number of read and written bytes in the current BIDI_INTERVAL second interval.
static unsigned bidi_map_ent_hash (const bidi_map_entry_t *entry)
 HT_PROTOTYPE (bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, bidi_map_ent_eq)
 HT_GENERATE (bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, bidi_map_ent_eq, 0.6, malloc, realloc, free)
static void bidi_map_free (void)
void rep_hist_reset_conn_stats (time_t now)
 Reset counters for conn statistics.
void rep_hist_conn_stats_term (void)
 Stop collecting connection stats in a way that we can re-start doing so in rep_hist_conn_stats_init().
void rep_hist_note_or_conn_bytes (uint64_t conn_id, size_t num_read, size_t num_written, time_t when)
 We read num_read bytes and wrote num_written from/to OR connection conn_id in second when.
char * rep_hist_format_conn_stats (time_t now)
 Return a newly allocated string containing the connection statistics until now, or NULL if we're not collecting conn stats.
time_t rep_hist_conn_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current conn stats period, write conn stats to $DATADIR/stats/conn-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_free_all (void)
 Free all storage held by the OR/link history caches, by the bandwidth history arrays, by the port history, or by statistics .

Variables

uint64_t rephist_total_alloc = 0
 Total number of bytes currently allocated in fields used by rephist.c.
uint32_t rephist_total_num = 0
 Number of or_history_t objects currently allocated.
static time_t stability_last_downrated = 0
 When did we last multiply all routers' weighted_run_length and total_run_weights by STABILITY_ALPHA?
static time_t started_tracking_stability = 0
static digestmap_t * history_map = NULL
 Map from hex OR identity digest to or_history_t.
static char * last_stability_doc = NULL
 The last stability analysis document that we created, or NULL if we never have created one.
static time_t built_last_stability_doc_at = 0
 The last time we created a stability analysis document, or 0 if we never have created one.
static int n_bogus_times = 0
 How many bad times has parse_possibly_bad_iso_time() parsed?
static bw_array_tread_array = NULL
 Recent history of bandwidth observations for read operations.
static bw_array_twrite_array = NULL
 Recent history of bandwidth observations for write operations.
static bw_array_tdir_read_array = NULL
 Recent history of bandwidth observations for read operations for the directory protocol.
static bw_array_tdir_write_array = NULL
 Recent history of bandwidth observations for write operations for the directory protocol.
static smartlist_tpredicted_ports_list = NULL
 A list of port numbers that have been used recently.
static time_t predicted_internal_time = 0
 The last time at which we needed an internal circ.
static time_t predicted_internal_uptime_time = 0
 The last time we needed an internal circ with good uptime.
static time_t predicted_internal_capacity_time = 0
 The last time we needed an internal circ with good capacity.
struct {
unsigned long n_signed_dir_objs
 How many directory objects have we signed?
unsigned long n_signed_routerdescs
 How many routerdescs have we signed?
unsigned long n_verified_dir_objs
 How many directory objects have we verified?
unsigned long n_verified_routerdescs
 How many routerdescs have we verified.
unsigned long n_onionskins_encrypted
 How many onionskins have we encrypted to build circuits?
unsigned long n_onionskins_decrypted
 How many onionskins have we decrypted to do circuit build requests?
unsigned long n_tls_client_handshakes
 How many times have we done the TLS handshake as a client?
unsigned long n_tls_server_handshakes
 How many times have we done the TLS handshake as a server?
unsigned long n_rend_client_ops
 How many PK operations have we done as a hidden service client?
unsigned long n_rend_mid_ops
 How many PK operations have we done as a hidden service midpoint?
unsigned long n_rend_server_ops
 How many PK operations have we done as a hidden service provider?
pk_op_counts
 Structure to track how many times we've done each public key operation.
static uint64_t * exit_bytes_read = NULL
 Number of bytes read in current period by exit port.
static uint64_t * exit_bytes_written = NULL
 Number of bytes written in current period by exit port.
static uint32_t * exit_streams = NULL
 Number of streams opened in current period by exit port.
static time_t start_of_exit_stats_interval
 Start time of exit stats or 0 if we're not collecting exit stats.
static time_t start_of_buffer_stats_interval
 Start of the current buffer stats interval or 0 if we're not collecting buffer statistics.
static smartlist_tcircuits_for_buffer_stats = NULL
 List of circ_buffer_stats_t.
static digestmap_t * served_descs = NULL
 Digestmap to track which descriptors were downloaded this stats collection interval.
static unsigned long total_descriptor_downloads
 Number of how many descriptors were downloaded in total during this interval.
static time_t start_of_served_descs_stats_interval
 Start time of served descs stats or 0 if we're not collecting those.
static time_t start_of_conn_stats_interval
 Start of the current connection stats interval or 0 if we're not collecting connection statistics.
static time_t bidi_next_interval = 0
 Start of next BIDI_INTERVAL second interval.
static uint32_t below_threshold = 0
 Number of connections that we read and wrote less than BIDI_THRESHOLD bytes from/to in BIDI_INTERVAL seconds.
static uint32_t mostly_read = 0
 Number of connections that we read at least BIDI_FACTOR times more bytes from than we wrote to in BIDI_INTERVAL seconds.
static uint32_t mostly_written = 0
 Number of connections that we wrote at least BIDI_FACTOR times more bytes to than we read from in BIDI_INTERVAL seconds.
static uint32_t both_read_and_written = 0
 Number of connections that we read and wrote at least BIDI_THRESHOLD bytes from/to, but not BIDI_FACTOR times more in either direction in BIDI_INTERVAL seconds.

Detailed Description

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; further, exit port statistics, cell statistics, and connection statistics.

Definition in file rephist.c.


Class Documentation

struct link_history_t

History of an OR->OR link.

Definition at line 46 of file rephist.c.

Class Members
time_t changed When did we most recently note a change to this link.
unsigned long n_extend_fail How many times did extending from OR1 to OR2 fail?
unsigned long n_extend_ok How many times did extending from OR1 to OR2 succeed?
time_t since When did we start tracking this list?
struct or_history_t

History of an OR.

Definition at line 58 of file rephist.c.

Collaboration diagram for or_history_t:
Class Members
time_t changed When did we most recently note a change to this OR?
time_t down_since If nonzero, we have been unable to connect since this time.
unsigned long downtime How many seconds have we been unable to connect to this OR before 'down_since'?
tor_addr_t last_reached_addr The address at which we most recently connected to this OR successfully.
uint16_t last_reached_port The port at which we most recently connected to this OR successfully.
digestmap_t * link_history_map Map from hex OR2 identity digest to a link_history_t for the link from this OR to OR2.
unsigned long n_conn_fail How many times did we try to connect and fail?
unsigned long n_conn_ok How many times did we successfully connect?
time_t since When did we start tracking this OR?
time_t start_of_downtime
time_t start_of_run If the router is now online (according to stability-checking rules), when did it come online?
double total_run_weights Sum of weights for runs in weighted_run_length.
unsigned long total_weighted_time
time_t up_since If nonzero, we have been connected since this time.
unsigned long uptime How many seconds have we been connected to this OR before 'up_since'?
unsigned long weighted_run_length Weighted sum total of all times that this router has been online.
unsigned long weighted_uptime
struct bw_array_t

Structure to track bandwidth use, and remember the maxima for a given time period.

Definition at line 1249 of file rephist.c.

Class Members
int cur_obs_idx Current position in obs.
time_t cur_obs_time Time represented in obs[cur_obs_idx].
uint64_t max_total Largest value that total_obs has taken on in the current period.
uint64_t maxima Circular array of the maximum bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last NUM_TOTALS periods.
int next_max_idx Where in 'maxima' should the maximum bandwidth usage for the current period be stored?
time_t next_period When does the next period begin?
int num_maxes_set How many values in maxima/totals have been set ever?
uint64_t obs Observation array: Total number of bytes transferred in each of the last NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array.
uint64_t total_in_period Total bytes transferred in the current period.
uint64_t total_obs Total for all members of obs except obs[cur_obs_idx].
uint64_t totals Circular array of the total bandwidth usage for the last NUM_TOTALS periods.
struct predicted_port_t

A single predicted port: used to remember which ports we've made connections to, so that we can try to keep making circuits that can handle those ports.

Definition at line 1778 of file rephist.c.

Class Members
uint16_t port The port we connected to.
time_t time The time at which we last used it.
struct circ_buffer_stats_t

Statistics from a single circuit.

Collected when the circuit closes, or when we flush statistics to disk.

Definition at line 2371 of file rephist.c.

Class Members
double mean_num_cells_in_queue Average number of cells in the circuit's queue.
double mean_time_cells_in_queue Average time a cell waits in the queue.
uint32_t processed_cells Total number of cells sent over this circuit.
struct bidi_map_entry_t

Entry in a map from connection ID to the number of read and written bytes on this connection in a BIDI_INTERVAL second interval.

Definition at line 2819 of file rephist.c.


Define Documentation

#define BIDI_FACTOR   10

Definition at line 2791 of file rephist.c.

#define BIDI_INTERVAL   10

Definition at line 2795 of file rephist.c.

#define BIDI_THRESHOLD   20480

Definition at line 2786 of file rephist.c.

#define EXIT_STATS_NUM_PORTS   65536

Number of TCP ports.

Definition at line 2077 of file rephist.c.

#define EXIT_STATS_ROUND_UP_BYTES   1024

To what multiple should byte numbers be rounded up?

Definition at line 2073 of file rephist.c.

To what multiple should stream counts be rounded up?

Definition at line 2075 of file rephist.c.

#define EXIT_STATS_TOP_N_PORTS   10

Top n ports that will be included in exit stats.

Definition at line 2079 of file rephist.c.

#define LOAD (   arrname,
  st 
)
Value:
if (rep_hist_load_bwhist_state_section(                               \
                                (arrname),                              \
                                state->BWHistory ## st ## Values,       \
                                state->BWHistory ## st ## Maxima,       \
                                state->BWHistory ## st ## Ends,         \
                                state->BWHistory ## st ## Interval)<0)  \
    all_ok = 0
#define MAX_HIST_VALUE_LEN   21*NUM_TOTALS
#define MAX_STABILITY_DOC_BUILD_RATE   (3*60)

Shortest allowable time between building two stability documents.

Definition at line 917 of file rephist.c.

#define NUM_SECS_BW_SUM_INTERVAL   (15*60)

How large are the intervals for which we track and report bandwidth use?

Definition at line 1240 of file rephist.c.

#define NUM_SECS_BW_SUM_IS_VALID   (24*60*60)

How far in the past do we remember and publish bandwidth use?

Definition at line 1242 of file rephist.c.

#define NUM_SECS_ROLLING_MEASURE   10

For how many seconds do we keep track of individual per-second bandwidth totals?

Definition at line 1236 of file rephist.c.

How many bandwidth usage intervals do we remember? (derived)

Definition at line 1244 of file rephist.c.

#define PREDICTED_CIRCS_RELEVANCE_TIME   (60*60)

For this long after we've seen a request for a given port, assume that we'll want to make connections to the same port in the future.

Definition at line 1850 of file rephist.c.

#define PRINTF (   args)    STMT_BEGIN if (fprintf args <0) goto err; STMT_END
#define PUT (   s)    STMT_BEGIN if (fputs((s),f)<0) goto err; STMT_END
#define SHARES   10
#define STABILITY_ALPHA   0.95

Value by which to discount all old intervals for MTBF purposes.

This is compounded every STABILITY_INTERVAL.

Definition at line 37 of file rephist.c.

#define STABILITY_EPSILON   0.0001

If the total weighted run count of all runs for a router ever falls below this amount, the router can be treated as having 0 MTBF.

Definition at line 34 of file rephist.c.

#define STABILITY_INTERVAL   (12*60*60)

Interval at which to discount all old intervals for MTBF purposes.

Definition at line 39 of file rephist.c.

#define SUBTRACT_CLAMPED (   var,
  penalty 
)    do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0)
#define UPDATE (   arrname,
  st 
)
Value:
rep_hist_update_bwhist_state_section(state,\
                                       (arrname),\
                                       &state->BWHistory ## st ## Values, \
                                       &state->BWHistory ## st ## Maxima, \
                                       &state->BWHistory ## st ## Ends, \
                                       &state->BWHistory ## st ## Interval)

Typedef Documentation

Entry in a map from connection ID to the number of read and written bytes on this connection in a BIDI_INTERVAL second interval.

typedef struct bw_array_t bw_array_t

Structure to track bandwidth use, and remember the maxima for a given time period.

Statistics from a single circuit.

Collected when the circuit closes, or when we flush statistics to disk.

History of an OR->OR link.

typedef struct or_history_t or_history_t

History of an OR.

A single predicted port: used to remember which ports we've made connections to, so that we can try to keep making circuits that can handle those ports.


Function Documentation

static int _buffer_stats_compare_entries ( const void **  _a,
const void **  _b 
) [static]

Sorting helper: return -1, 1, or 0 based on comparison of two circ_buffer_stats_t.

Definition at line 2442 of file rephist.c.

{
  const circ_buffer_stats_t *a = *_a, *b = *_b;
  if (a->processed_cells < b->processed_cells)
    return 1;
  else if (a->processed_cells > b->processed_cells)
    return -1;
  else
    return 0;
}

Here is the caller graph for this function:

static int _compare_int ( const void *  x,
const void *  y 
) [static]

Helper for qsort: compare two ints.

Does not handle overflow properly, but works fine for sorting an array of port numbers, which is what we use it for.

Definition at line 2133 of file rephist.c.

{
  return (*(int*)x - *(int*)y);
}

Here is the caller graph for this function:

static void _free_link_history ( void *  val) [static]

Helper: free storage held by a single link history entry.

Definition at line 163 of file rephist.c.

Here is the caller graph for this function:

static INLINE void add_obs ( bw_array_t b,
time_t  when,
uint64_t  n 
) [static]

Add n bytes to the number of bytes in b for second when.

Definition at line 1326 of file rephist.c.

{
  if (when < b->cur_obs_time)
    return; /* Don't record data in the past. */

  /* 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) {
    /* Doing this one second at a time is potentially inefficient, if we start
       with a state file that is very old.  Fortunately, it doesn't seem to
       show up in profiles, so we can just ignore it for now. */
    advance_obs(b);
  }

  b->obs[b->cur_obs_idx] += n;
  b->total_in_period += n;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_predicted_port ( time_t  now,
uint16_t  port 
) [static]

We just got an application request for a connection with port port.

Remember it for the future, so we can keep some circuits open that will exit to this port.

Definition at line 1793 of file rephist.c.

{
  predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t));
  pp->port = port;
  pp->time = now;
  rephist_total_alloc += sizeof(*pp);
  smartlist_add(predicted_ports_list, pp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE void advance_obs ( bw_array_t b) [static]

Shift the current observation time of b forward by one second.

Definition at line 1300 of file rephist.c.

{
  int nextidx;
  uint64_t 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int any_predicted_circuits ( time_t  now)

Any ports used lately? These are pre-seeded if we just started up or if we're running a hidden service.

Definition at line 1947 of file rephist.c.

Here is the caller graph for this function:

static unsigned bidi_map_ent_hash ( const bidi_map_entry_t entry) [static]

Definition at line 2839 of file rephist.c.

{
  return (unsigned) entry->conn_id;
}
static void bidi_map_free ( void  ) [static]

Definition at line 2851 of file rephist.c.

{
  bidi_map_entry_t **ptr, **next, *ent;
  for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
    ent = *ptr;
    next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
    tor_free(ent);
  }
  HT_CLEAR(bidimap, &bidi_map);
}

Here is the caller graph for this function:

static bw_array_t* bw_array_new ( void  ) [static]

Allocate, initialize, and return a new bw_array.

Definition at line 1347 of file rephist.c.

{
  bw_array_t *b;
  time_t start;
  b = tor_malloc_zero(sizeof(bw_array_t));
  rephist_total_alloc += sizeof(bw_array_t);
  start = time(NULL);
  b->cur_obs_time = start;
  b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
  return b;
}

Here is the caller graph for this function:

static void bw_arrays_init ( void  ) [static]

Set up [dir-]read_array and [dir-]write_array, freeing them if they already exist.

Definition at line 1373 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void commit_max ( bw_array_t b) [static]

Shift the current period of b forward by one.

Definition at line 1280 of file rephist.c.

{
  /* Store total from current period. */
  b->totals[b->next_max_idx] = b->total_in_period;
  /* 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;
  if (b->num_maxes_set < NUM_TOTALS)
    ++b->num_maxes_set;
  /* Reset max_total. */
  b->max_total = 0;
  /* Reset total_in_period. */
  b->total_in_period = 0;
}

Here is the caller graph for this function:

static INLINE time_t correct_time ( time_t  t,
time_t  now,
time_t  stored_at,
time_t  started_measuring 
) [static]

We've read a time t from a file stored at stored_at, which says we started measuring at started_measuring.

Return a new number that's about as much before now as t was before stored_at.

Definition at line 1028 of file rephist.c.

{
  if (t < started_measuring - 24*60*60*365)
    return 0;
  else if (t < started_measuring)
    return started_measuring;
  else if (t > stored_at)
    return 0;
  else {
    long run_length = stored_at - t;
    t = now - run_length;
    if (t < started_measuring)
      t = started_measuring;
    return t;
  }
}

Here is the caller graph for this function:

void dump_pk_ops ( int  severity)

Log the number of times we've done each public/private-key operation.

Definition at line 2042 of file rephist.c.

{
  log(severity, LD_HIST,
      "PK operations: %lu directory objects signed, "
      "%lu directory objects verified, "
      "%lu routerdescs signed, "
      "%lu routerdescs verified, "
      "%lu onionskins encrypted, "
      "%lu onionskins decrypted, "
      "%lu client-side TLS handshakes, "
      "%lu server-side TLS handshakes, "
      "%lu rendezvous client operations, "
      "%lu rendezvous middle operations, "
      "%lu rendezvous server operations.",
      pk_op_counts.n_signed_dir_objs,
      pk_op_counts.n_verified_dir_objs,
      pk_op_counts.n_signed_routerdescs,
      pk_op_counts.n_verified_routerdescs,
      pk_op_counts.n_onionskins_encrypted,
      pk_op_counts.n_onionskins_decrypted,
      pk_op_counts.n_tls_client_handshakes,
      pk_op_counts.n_tls_server_handshakes,
      pk_op_counts.n_rend_client_ops,
      pk_op_counts.n_rend_mid_ops,
      pk_op_counts.n_rend_server_ops);
}

Here is the caller graph for this function:

static uint64_t find_largest_max ( bw_array_t b) [static]

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.)

Definition at line 1439 of file rephist.c.

{
  int i;
  uint64_t max;
  max=0;
  for (i=0; i<NUM_TOTALS; ++i) {
    if (b->maxima[i]>max)
      max = b->maxima[i];
  }
  return max;
}

Here is the caller graph for this function:

static int find_next_with ( smartlist_t sl,
int  i,
const char *  prefix 
) [static]

Helper: return the first j >= i such that !strcmpstart(sl[j], prefix) and such that no line sl[k] with i <= k < j starts with "R ".

Return -1 if no such line exists.

Definition at line 990 of file rephist.c.

{
  for ( ; i < smartlist_len(sl); ++i) {
    const char *line = smartlist_get(sl, i);
    if (!strcmpstart(line, prefix))
      return i;
    if (!strcmpstart(line, "R "))
      return -1;
  }
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void free_or_history ( void *  _hist) [static]

Helper: free storage held by a single OR history entry.

Definition at line 171 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static link_history_t* get_link_history ( const char *  from_id,
const char *  to_id 
) [static]

Return the link_history_t for the link from the first named OR to the second, creating it if necessary.

(ORs are identified by identity digest.)

Definition at line 142 of file rephist.c.

{
  or_history_t *orhist;
  link_history_t *lhist;
  orhist = get_or_history(from_id);
  if (!orhist)
    return NULL;
  if (tor_digest_is_zero(to_id))
    return NULL;
  lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id);
  if (!lhist) {
    lhist = tor_malloc_zero(sizeof(link_history_t));
    rephist_total_alloc += sizeof(link_history_t);
    lhist->since = lhist->changed = time(NULL);
    digestmap_set(orhist->link_history_map, to_id, lhist);
  }
  return lhist;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static or_history_t* get_or_history ( const char *  id) [static]

Return the or_history_t for the OR with identity digest id, creating it if necessary.

Definition at line 117 of file rephist.c.

{
  or_history_t *hist;

  if (tor_digest_is_zero(id))
    return NULL;

  hist = digestmap_get(history_map, id);
  if (!hist) {
    hist = tor_malloc_zero(sizeof(or_history_t));
    rephist_total_alloc += sizeof(or_history_t);
    rephist_total_num++;
    hist->link_history_map = digestmap_new();
    hist->since = hist->changed = time(NULL);
    tor_addr_make_unspec(&hist->last_reached_addr);
    digestmap_set(history_map, id, hist);
  }
  return hist;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static double get_stability ( or_history_t hist,
time_t  when 
) [static]

Helper: Return the weighted MTBF of the router with history hist.

Definition at line 473 of file rephist.c.

{
  long total = hist->weighted_run_length;
  double total_weights = hist->total_run_weights;

  if (hist->start_of_run) {
    /* We're currently in a run.  Let total and total_weights hold the values
     * they would hold if the current run were to end now. */
    total += (when-hist->start_of_run);
    total_weights += 1.0;
  }
  if (total_weights < STABILITY_EPSILON) {
    /* Round down to zero, and avoid divide-by-zero. */
    return 0.0;
  }

  return total / total_weights;
}

Here is the caller graph for this function:

static long get_total_weighted_time ( or_history_t hist,
time_t  when 
) [static]

Return the total amount of time we've been observing, with each run of time downrated by the appropriate factor.

Definition at line 495 of file rephist.c.

{
  long total = hist->total_weighted_time;
  if (hist->start_of_run) {
    total += (when - hist->start_of_run);
  } else if (hist->start_of_downtime) {
    total += (when - hist->start_of_downtime);
  }
  return total;
}

Here is the caller graph for this function:

static double get_weighted_fractional_uptime ( or_history_t hist,
time_t  when 
) [static]

Helper: Return the weighted percent-of-time-online of the router with history hist.

Definition at line 509 of file rephist.c.

{
  long total = hist->total_weighted_time;
  long up = hist->weighted_uptime;

  if (hist->start_of_run) {
    long run_length = (when - hist->start_of_run);
    up += run_length;
    total += run_length;
  } else if (hist->start_of_downtime) {
    total += (when - hist->start_of_downtime);
  }

  if (!total) {
    /* Avoid calling anybody's uptime infinity (which should be impossible if
     * the code is working), or NaN (which can happen for any router we haven't
     * observed up or down yet). */
    return 0.0;
  }

  return ((double) up) / total;
}

Here is the caller graph for this function:

HT_GENERATE ( bidimap  ,
bidi_map_entry_t  ,
node  ,
bidi_map_ent_hash  ,
bidi_map_ent_eq  ,
0.  6,
malloc  ,
realloc  ,
free   
)
static HT_HEAD ( bidimap  ,
bidi_map_entry_t   
) [static]

Map of OR connections together with the number of read and written bytes in the current BIDI_INTERVAL second interval.

Definition at line 2828 of file rephist.c.

{
  return a->conn_id == b->conn_id;
}
HT_PROTOTYPE ( bidimap  ,
bidi_map_entry_t  ,
node  ,
bidi_map_ent_hash  ,
bidi_map_ent_eq   
)
static void mark_or_down ( or_history_t hist,
time_t  when,
int  failed 
) [static]

Helper: note that we are no longer connected to the router with history hist.

If failed, the connection failed; otherwise, it was closed correctly.

Definition at line 210 of file rephist.c.

{
  if (hist->up_since) {
    hist->uptime += (when - hist->up_since);
    hist->up_since = 0;
  }
  if (failed && !hist->down_since) {
    hist->down_since = when;
  }
}

Here is the caller graph for this function:

static void mark_or_up ( or_history_t hist,
time_t  when 
) [static]

Helper: note that we are connected to the router with history hist.

Definition at line 224 of file rephist.c.

{
  if (hist->down_since) {
    hist->downtime += (when - hist->down_since);
    hist->down_since = 0;
  }
  if (!hist->up_since) {
    hist->up_since = when;
  }
}

Here is the caller graph for this function:

void note_crypto_pk_op ( pk_op_t  operation)

Increment the count of the number of times we've done operation.

Definition at line 1998 of file rephist.c.

{
  switch (operation)
    {
    case SIGN_DIR:
      pk_op_counts.n_signed_dir_objs++;
      break;
    case SIGN_RTR:
      pk_op_counts.n_signed_routerdescs++;
      break;
    case VERIFY_DIR:
      pk_op_counts.n_verified_dir_objs++;
      break;
    case VERIFY_RTR:
      pk_op_counts.n_verified_routerdescs++;
      break;
    case ENC_ONIONSKIN:
      pk_op_counts.n_onionskins_encrypted++;
      break;
    case DEC_ONIONSKIN:
      pk_op_counts.n_onionskins_decrypted++;
      break;
    case TLS_HANDSHAKE_C:
      pk_op_counts.n_tls_client_handshakes++;
      break;
    case TLS_HANDSHAKE_S:
      pk_op_counts.n_tls_server_handshakes++;
      break;
    case REND_CLIENT:
      pk_op_counts.n_rend_client_ops++;
      break;
    case REND_MID:
      pk_op_counts.n_rend_mid_ops++;
      break;
    case REND_SERVER:
      pk_op_counts.n_rend_server_ops++;
      break;
    default:
      log_warn(LD_BUG, "Unknown pk operation %d", operation);
  }
}

Here is the caller graph for this function:

static int parse_possibly_bad_iso_time ( const char *  s,
time_t *  time_out 
) [static]

Parse the ISO-formatted time in s into *time_out, but round any pre-1970 date to Jan 1, 1970.

Definition at line 1007 of file rephist.c.

{
  int year;
  char b[5];
  strlcpy(b, s, sizeof(b));
  b[4] = '\0';
  year = (int)tor_parse_long(b, 10, 0, INT_MAX, NULL, NULL);
  if (year < 1970) {
    *time_out = 0;
    ++n_bogus_times;
    return 0;
  } else
    return parse_iso_time(s, time_out);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void predicted_ports_free ( void  ) [static]

Free whatever memory is needed for predicting which ports will be used.

Definition at line 1817 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void predicted_ports_init ( void  ) [static]

Initialize whatever memory and structs are needed for predicting which ports will be used.

Also seed it with port 80, so we'll build circuits on start-up.

Definition at line 1807 of file rephist.c.

{
  predicted_ports_list = smartlist_new();
  add_predicted_port(time(NULL), 80); /* add one to kickstart us */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_add_buffer_stats ( double  mean_num_cells_in_queue,
double  mean_time_cells_in_queue,
uint32_t  processed_cells 
)

Remember cell statistics mean_num_cells_in_queue, mean_time_cells_in_queue, and processed_cells of a circuit.

Definition at line 2387 of file rephist.c.

{
  circ_buffer_stats_t *stat;
  if (!start_of_buffer_stats_interval)
    return; /* Not initialized. */
  stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
  stat->mean_num_cells_in_queue = mean_num_cells_in_queue;
  stat->mean_time_cells_in_queue = mean_time_cells_in_queue;
  stat->processed_cells = processed_cells;
  if (!circuits_for_buffer_stats)
    circuits_for_buffer_stats = smartlist_new();
  smartlist_add(circuits_for_buffer_stats, stat);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_bandwidth_assess ( void  )

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.

Definition at line 1458 of file rephist.c.

{
  uint64_t w,r;
  r = find_largest_max(read_array);
  w = find_largest_max(write_array);
  if (r>w)
    return (int)(U64_TO_DBL(w)/NUM_SECS_ROLLING_MEASURE);
  else
    return (int)(U64_TO_DBL(r)/NUM_SECS_ROLLING_MEASURE);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_buffer_stats_add_circ ( circuit_t circ,
time_t  end_of_interval 
)

Remember cell statistics for circuit circ at time end_of_interval and reset cell counters in case the circuit remains open in the next measurement interval.

Definition at line 2406 of file rephist.c.

{
  time_t start_of_interval;
  int interval_length;
  or_circuit_t *orcirc;
  double mean_num_cells_in_queue, mean_time_cells_in_queue;
  uint32_t processed_cells;
  if (CIRCUIT_IS_ORIGIN(circ))
    return;
  orcirc = TO_OR_CIRCUIT(circ);
  if (!orcirc->processed_cells)
    return;
  start_of_interval = (circ->timestamp_created.tv_sec >
                       start_of_buffer_stats_interval) ?
        circ->timestamp_created.tv_sec :
        start_of_buffer_stats_interval;
  interval_length = (int) (end_of_interval - start_of_interval);
  if (interval_length <= 0)
    return;
  processed_cells = orcirc->processed_cells;
  /* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
  mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
      (double) interval_length / 1000.0 / 2.0;
  mean_time_cells_in_queue =
      (double) orcirc->total_cell_waiting_time /
      (double) orcirc->processed_cells;
  orcirc->total_cell_waiting_time = 0;
  orcirc->processed_cells = 0;
  rep_hist_add_buffer_stats(mean_num_cells_in_queue,
                            mean_time_cells_in_queue,
                            processed_cells);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_buffer_stats_init ( time_t  now)

Initialize buffer stats.

Definition at line 2364 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_buffer_stats_term ( void  )

Stop collecting cell stats in a way that we can re-start doing so in rep_hist_buffer_stats_init().

Definition at line 2456 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_buffer_stats_write ( time_t  now)

If 24 hours have passed since the beginning of the current buffer stats period, write buffer stats to $DATADIR/stats/buffer-stats (possibly overwriting an existing file) and reset counters.

Return when we would next want to write buffer stats or 0 if we never want to write.

Definition at line 2581 of file rephist.c.

{
  circuit_t *circ;
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_buffer_stats_interval)
    return 0; /* Not initialized. */
  if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
    goto done; /* Not ready to write */

  /* Add open circuits to the history. */
  for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
    rep_hist_buffer_stats_add_circ(circ, now);
  }

  /* Generate history string. */
  str = rep_hist_format_buffer_stats(now);

  /* Reset both buffer history and counters of open circuits. */
  rep_hist_reset_buffer_stats(now);

  /* Try to write to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
    goto done;
  }
  filename = get_datadir_fname2("stats", "buffer-stats");
  if (write_str_to_file(filename, str, 0) < 0)
    log_warn(LD_HIST, "Unable to write buffer stats to disk!");

 done:
  tor_free(str);
  tor_free(filename);
  tor_free(statsdir);
  return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_circbuilding_dormant ( time_t  now)

Return 1 if we have no need for circuits currently, else return 0.

Definition at line 1955 of file rephist.c.

{
  if (any_predicted_circuits(now))
    return 0;

  /* see if we'll still need to build testing circuits */
  if (server_mode(get_options()) &&
      (!check_whether_orport_reachable() || !circuit_enough_testing_circs()))
    return 0;
  if (!check_whether_dirport_reachable())
    return 0;

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_conn_stats_init ( time_t  now)

Initialize connection stats.

Definition at line 2779 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_conn_stats_term ( void  )

Stop collecting connection stats in a way that we can re-start doing so in rep_hist_conn_stats_init().

Definition at line 2877 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_conn_stats_write ( time_t  now)

If 24 hours have passed since the beginning of the current conn stats period, write conn stats to $DATADIR/stats/conn-stats (possibly overwriting an existing file) and reset counters.

Return when we would next want to write conn stats or 0 if we never want to write.

Definition at line 2965 of file rephist.c.

{
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_conn_stats_interval)
    return 0; /* Not initialized. */
  if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
    goto done; /* Not ready to write */

  /* Generate history string. */
  str = rep_hist_format_conn_stats(now);

  /* Reset counters. */
  rep_hist_reset_conn_stats(now);

  /* Try to write to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
    goto done;
  }
  filename = get_datadir_fname2("stats", "conn-stats");
  if (write_str_to_file(filename, str, 0) < 0)
    log_warn(LD_HIST, "Unable to write conn stats to disk!");

 done:
  tor_free(str);
  tor_free(filename);
  tor_free(statsdir);
  return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_desc_stats_init ( time_t  now)

Initialize descriptor stats.

Definition at line 2635 of file rephist.c.

{
  if (served_descs) {
    log_warn(LD_BUG, "Called rep_hist_desc_stats_init() when desc stats were "
             "already initialized. This is probably harmless.");
    return; // Already initialized
  }
  served_descs = digestmap_new();
  total_descriptor_downloads = 0;
  start_of_served_descs_stats_interval = now;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_desc_stats_term ( void  )

Stop collecting served descs stats, so that rep_hist_desc_stats_init() is safe to be called again.

Definition at line 2658 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_desc_stats_write ( time_t  now)

If WRITE_STATS_INTERVAL seconds have passed since the beginning of the current served desc stats interval, write the stats to $DATADIR/stats/served-desc-stats (possibly appending to an existing file) and reset the state for the next interval.

Return when we would next want to write served desc stats or 0 if we won't want to write.

Definition at line 2725 of file rephist.c.

{
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_served_descs_stats_interval)
    return 0; /* We're not collecting stats. */
  if (start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL > now)
    return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL;

  str = rep_hist_format_desc_stats(now);
  tor_assert(str != NULL);

  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
      goto done;
  }
  filename = get_datadir_fname2("stats", "served-desc-stats");
  if (append_bytes_to_file(filename, str, strlen(str), 0) < 0)
    log_warn(LD_HIST, "Unable to write served descs statistics to disk!");

  rep_hist_reset_desc_stats(now);

 done:
  tor_free(statsdir);
  tor_free(filename);
  tor_free(str);
  return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_downrate_old_runs ( time_t  now)

Helper: Discount all old MTBF data, if it is time to do so.

Return the time at which we should next discount MTBF data.

Definition at line 428 of file rephist.c.

{
  digestmap_iter_t *orhist_it;
  const char *digest1;
  or_history_t *hist;
  void *hist_p;
  double alpha = 1.0;

  if (!history_map)
    history_map = digestmap_new();
  if (!stability_last_downrated)
    stability_last_downrated = now;
  if (stability_last_downrated + STABILITY_INTERVAL > now)
    return stability_last_downrated + STABILITY_INTERVAL;

  /* Okay, we should downrate the data.  By how much? */
  while (stability_last_downrated + STABILITY_INTERVAL < now) {
    stability_last_downrated += STABILITY_INTERVAL;
    alpha *= STABILITY_ALPHA;
  }

  log_info(LD_HIST, "Discounting all old stability info by a factor of %f",
           alpha);

  /* Multiply every w_r_l, t_r_w pair by alpha. */
  for (orhist_it = digestmap_iter_init(history_map);
       !digestmap_iter_done(orhist_it);
       orhist_it = digestmap_iter_next(history_map,orhist_it)) {
    digestmap_iter_get(orhist_it, &digest1, &hist_p);
    hist = hist_p;

    hist->weighted_run_length =
      (unsigned long)(hist->weighted_run_length * alpha);
    hist->total_run_weights *= alpha;

    hist->weighted_uptime = (unsigned long)(hist->weighted_uptime * alpha);
    hist->total_weighted_time = (unsigned long)
      (hist->total_weighted_time * alpha);
  }

  return stability_last_downrated + STABILITY_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_dump_stats ( time_t  now,
int  severity 
)

Log all the reliability data we have remembered, with the chosen severity.

Definition at line 632 of file rephist.c.

{
  digestmap_iter_t *lhist_it;
  digestmap_iter_t *orhist_it;
  const char *name1, *name2, *digest1, *digest2;
  char hexdigest1[HEX_DIGEST_LEN+1];
  char hexdigest2[HEX_DIGEST_LEN+1];
  or_history_t *or_history;
  link_history_t *link_history;
  void *or_history_p, *link_history_p;
  double uptime;
  char buffer[2048];
  size_t len;
  int ret;
  unsigned long upt, downt;
  const node_t *node;

  rep_history_clean(now - get_options()->RephistTrackTime);

  log(severity, LD_HIST, "--------------- Dumping history information:");

  for (orhist_it = digestmap_iter_init(history_map);
       !digestmap_iter_done(orhist_it);
       orhist_it = digestmap_iter_next(history_map,orhist_it)) {
    double s;
    long stability;
    digestmap_iter_get(orhist_it, &digest1, &or_history_p);
    or_history = (or_history_t*) or_history_p;

    if ((node = node_get_by_id(digest1)) && node_get_nickname(node))
      name1 = node_get_nickname(node);
    else
      name1 = "(unknown)";
    base16_encode(hexdigest1, sizeof(hexdigest1), digest1, DIGEST_LEN);
    update_or_history(or_history, now);
    upt = or_history->uptime;
    downt = or_history->downtime;
    s = get_stability(or_history, now);
    stability = (long)s;
    if (upt+downt) {
      uptime = ((double)upt) / (upt+downt);
    } else {
      uptime=1.0;
    }
    log(severity, LD_HIST,
        "OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%); "
        "wmtbf %lu:%02lu:%02lu",
        name1, hexdigest1,
        or_history->n_conn_ok, or_history->n_conn_fail+or_history->n_conn_ok,
        upt, upt+downt, uptime*100.0,
        stability/3600, (stability/60)%60, stability%60);

    if (!digestmap_isempty(or_history->link_history_map)) {
      strlcpy(buffer, "    Extend attempts: ", sizeof(buffer));
      len = strlen(buffer);
      for (lhist_it = digestmap_iter_init(or_history->link_history_map);
           !digestmap_iter_done(lhist_it);
           lhist_it = digestmap_iter_next(or_history->link_history_map,
                                          lhist_it)) {
        digestmap_iter_get(lhist_it, &digest2, &link_history_p);
        if ((node = node_get_by_id(digest2)) && node_get_nickname(node))
          name2 = node_get_nickname(node);
        else
          name2 = "(unknown)";

        link_history = (link_history_t*) link_history_p;

        base16_encode(hexdigest2, sizeof(hexdigest2), digest2, DIGEST_LEN);
        ret = tor_snprintf(buffer+len, 2048-len, "%s [%s](%ld/%ld); ",
                        name2,
                        hexdigest2,
                        link_history->n_extend_ok,
                        link_history->n_extend_ok+link_history->n_extend_fail);
        if (ret<0)
          break;
        else
          len += ret;
      }
      log(severity, LD_HIST, "%s", buffer);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_exit_stats_init ( time_t  now)

Initialize exit port stats.

Definition at line 2097 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_exit_stats_term ( void  )

Stop collecting exit port stats in a way that we can re-start doing so in rep_hist_exit_stats_init().

Definition at line 2121 of file rephist.c.

Here is the caller graph for this function:

time_t rep_hist_exit_stats_write ( time_t  now)

If 24 hours have passed since the beginning of the current exit port stats period, write exit stats to $DATADIR/stats/exit-stats (possibly overwriting an existing file) and reset counters.

Return when we would next want to write exit stats or 0 if we never want to write.

Definition at line 2297 of file rephist.c.

{
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_exit_stats_interval)
    return 0; /* Not initialized. */
  if (start_of_exit_stats_interval + WRITE_STATS_INTERVAL > now)
    goto done; /* Not ready to write. */

  log_info(LD_HIST, "Writing exit port statistics to disk.");

  /* Generate history string. */
  str = rep_hist_format_exit_stats(now);

  /* Reset counters. */
  rep_hist_reset_exit_stats(now);

  /* Try to write to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
    goto done;
  }
  filename = get_datadir_fname2("stats", "exit-stats");
  if (write_str_to_file(filename, str, 0) < 0)
    log_warn(LD_HIST, "Unable to write exit port statistics to disk!");

 done:
  tor_free(str);
  tor_free(statsdir);
  tor_free(filename);
  return start_of_exit_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static size_t rep_hist_fill_bandwidth_history ( char *  buf,
size_t  len,
const bw_array_t b 
) [static]

Print the bandwidth history of b (either [dir-]read_array or [dir-]write_array) into the buffer pointed to by buf.

The format is simply comma separated numbers, from oldest to newest.

It returns the number of bytes written.

Definition at line 1476 of file rephist.c.

{
  char *cp = buf;
  int i, n;
  const or_options_t *options = get_options();
  uint64_t cutoff;

  if (b->num_maxes_set <= b->next_max_idx) {
    /* We haven't been through the circular array yet; time starts at i=0.*/
    i = 0;
  } else {
    /* We've been around the array at least once.  The next i to be
       overwritten is the oldest. */
    i = b->next_max_idx;
  }

  if (options->RelayBandwidthRate) {
    /* We don't want to report that we used more bandwidth than the max we're
     * willing to relay; otherwise everybody will know how much traffic
     * we used ourself. */
    cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
  } else {
    cutoff = UINT64_MAX;
  }

  for (n=0; n<b->num_maxes_set; ++n,++i) {
    uint64_t total;
    if (i >= NUM_TOTALS)
      i -= NUM_TOTALS;
    tor_assert(i < NUM_TOTALS);
    /* Round the bandwidth used down to the nearest 1k. */
    total = b->totals[i] & ~0x3ff;
    if (total > cutoff)
      total = cutoff;

    if (n==(b->num_maxes_set-1))
      tor_snprintf(cp, len-(cp-buf), U64_FORMAT, U64_PRINTF_ARG(total));
    else
      tor_snprintf(cp, len-(cp-buf), U64_FORMAT",", U64_PRINTF_ARG(total));
    cp += strlen(cp);
  }
  return cp-buf;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_buffer_stats ( time_t  now)

Return a newly allocated string containing the buffer statistics until now, or NULL if we're not collecting buffer stats.

Caller must ensure start_of_buffer_stats_interval is in the past.

Definition at line 2478 of file rephist.c.

{
#define SHARES 10
  uint64_t processed_cells[SHARES];
  uint32_t circs_in_share[SHARES];
  int number_of_circuits, i;
  double queued_cells[SHARES], time_in_queue[SHARES];
  smartlist_t *processed_cells_strings, *queued_cells_strings,
              *time_in_queue_strings;
  char *processed_cells_string, *queued_cells_string,
       *time_in_queue_string;
  char t[ISO_TIME_LEN+1];
  char *result;

  if (!start_of_buffer_stats_interval)
    return NULL; /* Not initialized. */

  tor_assert(now >= start_of_buffer_stats_interval);

  /* Calculate deciles if we saw at least one circuit. */
  memset(processed_cells, 0, SHARES * sizeof(uint64_t));
  memset(circs_in_share, 0, SHARES * sizeof(uint32_t));
  memset(queued_cells, 0, SHARES * sizeof(double));
  memset(time_in_queue, 0, SHARES * sizeof(double));
  if (!circuits_for_buffer_stats)
    circuits_for_buffer_stats = smartlist_new();
  number_of_circuits = smartlist_len(circuits_for_buffer_stats);
  if (number_of_circuits > 0) {
    smartlist_sort(circuits_for_buffer_stats,
                   _buffer_stats_compare_entries);
    i = 0;
    SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
                            circ_buffer_stats_t *, stat)
    {
      int share = i++ * SHARES / number_of_circuits;
      processed_cells[share] += stat->processed_cells;
      queued_cells[share] += stat->mean_num_cells_in_queue;
      time_in_queue[share] += stat->mean_time_cells_in_queue;
      circs_in_share[share]++;
    }
    SMARTLIST_FOREACH_END(stat);
  }

  /* Write deciles to strings. */
  processed_cells_strings = smartlist_new();
  queued_cells_strings = smartlist_new();
  time_in_queue_strings = smartlist_new();
  for (i = 0; i < SHARES; i++) {
    smartlist_add_asprintf(processed_cells_strings,
                           U64_FORMAT, !circs_in_share[i] ? 0 :
                           U64_PRINTF_ARG(processed_cells[i] /
                           circs_in_share[i]));
  }
  for (i = 0; i < SHARES; i++) {
    smartlist_add_asprintf(queued_cells_strings, "%.2f",
                           circs_in_share[i] == 0 ? 0.0 :
                             queued_cells[i] / (double) circs_in_share[i]);
  }
  for (i = 0; i < SHARES; i++) {
    smartlist_add_asprintf(time_in_queue_strings, "%.0f",
                           circs_in_share[i] == 0 ? 0.0 :
                             time_in_queue[i] / (double) circs_in_share[i]);
  }

  /* Join all observations in single strings. */
  processed_cells_string = smartlist_join_strings(processed_cells_strings,
                                                  ",", 0, NULL);
  queued_cells_string = smartlist_join_strings(queued_cells_strings,
                                               ",", 0, NULL);
  time_in_queue_string = smartlist_join_strings(time_in_queue_strings,
                                                ",", 0, NULL);
  SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp));
  SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp));
  SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp));
  smartlist_free(processed_cells_strings);
  smartlist_free(queued_cells_strings);
  smartlist_free(time_in_queue_strings);

  /* Put everything together. */
  format_iso_time(t, now);
  tor_asprintf(&result, "cell-stats-end %s (%d s)\n"
               "cell-processed-cells %s\n"
               "cell-queued-cells %s\n"
               "cell-time-in-queue %s\n"
               "cell-circuits-per-decile %d\n",
               t, (unsigned) (now - start_of_buffer_stats_interval),
               processed_cells_string,
               queued_cells_string,
               time_in_queue_string,
               (number_of_circuits + SHARES - 1) / SHARES);
  tor_free(processed_cells_string);
  tor_free(queued_cells_string);
  tor_free(time_in_queue_string);
  return result;
#undef SHARES
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_conn_stats ( time_t  now)

Return a newly allocated string containing the connection statistics until now, or NULL if we're not collecting conn stats.

Caller must ensure start_of_conn_stats_interval is in the past.

Definition at line 2940 of file rephist.c.

{
  char *result, written[ISO_TIME_LEN+1];

  if (!start_of_conn_stats_interval)
    return NULL; /* Not initialized. */

  tor_assert(now >= start_of_conn_stats_interval);

  format_iso_time(written, now);
  tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n",
               written,
               (unsigned) (now - start_of_conn_stats_interval),
               below_threshold,
               mostly_read,
               mostly_written,
               both_read_and_written);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* rep_hist_format_desc_stats ( time_t  now) [static]

Helper for rep_hist_desc_stats_write().

Return a newly allocated string containing the served desc statistics until now, or NULL if we're not collecting served desc stats. Caller must ensure that now is not before start_of_served_descs_stats_interval.

Definition at line 2671 of file rephist.c.

{
  char t[ISO_TIME_LEN+1];
  char *result;

  digestmap_iter_t *iter;
  const char *key;
  void *val;
  unsigned size;
  int *vals, max = 0, q3 = 0, md = 0, q1 = 0, min = 0;
  int n = 0;

  if (!start_of_served_descs_stats_interval)
    return NULL;

  size = digestmap_size(served_descs);
  if (size > 0) {
    vals = tor_malloc(size * sizeof(int));
    for (iter = digestmap_iter_init(served_descs);
         !digestmap_iter_done(iter);
         iter = digestmap_iter_next(served_descs, iter)) {
      uintptr_t count;
      digestmap_iter_get(iter, &key, &val);
      count = (uintptr_t)val;
      vals[n++] = (int)count;
      (void)key;
    }
    max = find_nth_int(vals, size, size-1);
    q3 = find_nth_int(vals, size, (3*size-1)/4);
    md = find_nth_int(vals, size, (size-1)/2);
    q1 = find_nth_int(vals, size, (size-1)/4);
    min = find_nth_int(vals, size, 0);
    tor_free(vals);
  }

  format_iso_time(t, now);

  tor_asprintf(&result,
               "served-descs-stats-end %s (%d s) total=%lu unique=%u "
               "max=%d q3=%d md=%d q1=%d min=%d\n",
               t,
               (unsigned) (now - start_of_served_descs_stats_interval),
               total_descriptor_downloads,
               size, max, q3, md, q1, min);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_exit_stats ( time_t  now)

Return a newly allocated string containing the exit port statistics until now, or NULL if we're not collecting exit stats.

Caller must ensure start_of_exit_stats_interval is in the past.

Definition at line 2142 of file rephist.c.

{
  int i, j, top_elements = 0, cur_min_idx = 0, cur_port;
  uint64_t top_bytes[EXIT_STATS_TOP_N_PORTS];
  int top_ports[EXIT_STATS_TOP_N_PORTS];
  uint64_t cur_bytes = 0, other_read = 0, other_written = 0,
           total_read = 0, total_written = 0;
  uint32_t total_streams = 0, other_streams = 0;
  smartlist_t *written_strings, *read_strings, *streams_strings;
  char *written_string, *read_string, *streams_string;
  char t[ISO_TIME_LEN+1];
  char *result;

  if (!start_of_exit_stats_interval)
    return NULL; /* Not initialized. */

  tor_assert(now >= start_of_exit_stats_interval);

  /* Go through all ports to find the n ports that saw most written and
   * read bytes.
   *
   * Invariant: at the end of the loop for iteration i,
   *    total_read is the sum of all exit_bytes_read[0..i]
   *    total_written is the sum of all exit_bytes_written[0..i]
   *    total_stream is the sum of all exit_streams[0..i]
   *
   *    top_elements = MAX(EXIT_STATS_TOP_N_PORTS,
   *                  #{j | 0 <= j <= i && volume(i) > 0})
   *
   *    For all 0 <= j < top_elements,
   *        top_bytes[j] > 0
   *        0 <= top_ports[j] <= 65535
   *        top_bytes[j] = volume(top_ports[j])
   *
   *    There is no j in 0..i and k in 0..top_elements such that:
   *        volume(j) > top_bytes[k] AND j is not in top_ports[0..top_elements]
   *
   *    There is no j!=cur_min_idx in 0..top_elements such that:
   *        top_bytes[j] < top_bytes[cur_min_idx]
   *
   * where volume(x) == exit_bytes_read[x]+exit_bytes_written[x]
   *
   * Worst case: O(EXIT_STATS_NUM_PORTS * EXIT_STATS_TOP_N_PORTS)
   */
  for (i = 1; i < EXIT_STATS_NUM_PORTS; i++) {
    total_read += exit_bytes_read[i];
    total_written += exit_bytes_written[i];
    total_streams += exit_streams[i];
    cur_bytes = exit_bytes_read[i] + exit_bytes_written[i];
    if (cur_bytes == 0) {
      continue;
    }
    if (top_elements < EXIT_STATS_TOP_N_PORTS) {
      top_bytes[top_elements] = cur_bytes;
      top_ports[top_elements++] = i;
    } else if (cur_bytes > top_bytes[cur_min_idx]) {
      top_bytes[cur_min_idx] = cur_bytes;
      top_ports[cur_min_idx] = i;
    } else {
      continue;
    }
    cur_min_idx = 0;
    for (j = 1; j < top_elements; j++) {
      if (top_bytes[j] < top_bytes[cur_min_idx]) {
        cur_min_idx = j;
      }
    }
  }

  /* Add observations of top ports to smartlists. */
  written_strings = smartlist_new();
  read_strings = smartlist_new();
  streams_strings = smartlist_new();
  other_read = total_read;
  other_written = total_written;
  other_streams = total_streams;
  /* Sort the ports; this puts them out of sync with top_bytes, but we
   * won't be using top_bytes again anyway */
  qsort(top_ports, top_elements, sizeof(int), _compare_int);
  for (j = 0; j < top_elements; j++) {
    cur_port = top_ports[j];
    if (exit_bytes_written[cur_port] > 0) {
      uint64_t num = round_uint64_to_next_multiple_of(
                     exit_bytes_written[cur_port],
                     EXIT_STATS_ROUND_UP_BYTES);
      num /= 1024;
      smartlist_add_asprintf(written_strings, "%d="U64_FORMAT,
                             cur_port, U64_PRINTF_ARG(num));
      other_written -= exit_bytes_written[cur_port];
    }
    if (exit_bytes_read[cur_port] > 0) {
      uint64_t num = round_uint64_to_next_multiple_of(
                     exit_bytes_read[cur_port],
                     EXIT_STATS_ROUND_UP_BYTES);
      num /= 1024;
      smartlist_add_asprintf(read_strings, "%d="U64_FORMAT,
                             cur_port, U64_PRINTF_ARG(num));
      other_read -= exit_bytes_read[cur_port];
    }
    if (exit_streams[cur_port] > 0) {
      uint32_t num = round_uint32_to_next_multiple_of(
                     exit_streams[cur_port],
                     EXIT_STATS_ROUND_UP_STREAMS);
      smartlist_add_asprintf(streams_strings, "%d=%u", cur_port, num);
      other_streams -= exit_streams[cur_port];
    }
  }

  /* Add observations of other ports in a single element. */
  other_written = round_uint64_to_next_multiple_of(other_written,
                  EXIT_STATS_ROUND_UP_BYTES);
  other_written /= 1024;
  smartlist_add_asprintf(written_strings, "other="U64_FORMAT,
                         U64_PRINTF_ARG(other_written));
  other_read = round_uint64_to_next_multiple_of(other_read,
               EXIT_STATS_ROUND_UP_BYTES);
  other_read /= 1024;
  smartlist_add_asprintf(read_strings, "other="U64_FORMAT,
                         U64_PRINTF_ARG(other_read));
  other_streams = round_uint32_to_next_multiple_of(other_streams,
                  EXIT_STATS_ROUND_UP_STREAMS);
  smartlist_add_asprintf(streams_strings, "other=%u", other_streams);

  /* Join all observations in single strings. */
  written_string = smartlist_join_strings(written_strings, ",", 0, NULL);
  read_string = smartlist_join_strings(read_strings, ",", 0, NULL);
  streams_string = smartlist_join_strings(streams_strings, ",", 0, NULL);
  SMARTLIST_FOREACH(written_strings, char *, cp, tor_free(cp));
  SMARTLIST_FOREACH(read_strings, char *, cp, tor_free(cp));
  SMARTLIST_FOREACH(streams_strings, char *, cp, tor_free(cp));
  smartlist_free(written_strings);
  smartlist_free(read_strings);
  smartlist_free(streams_strings);

  /* Put everything together. */
  format_iso_time(t, now);
  tor_asprintf(&result, "exit-stats-end %s (%d s)\n"
               "exit-kibibytes-written %s\n"
               "exit-kibibytes-read %s\n"
               "exit-streams-opened %s\n",
               t, (unsigned) (now - start_of_exit_stats_interval),
               written_string,
               read_string,
               streams_string);
  tor_free(written_string);
  tor_free(read_string);
  tor_free(streams_string);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* rep_hist_format_router_status ( or_history_t hist,
time_t  now 
) [static]

Format the current tracked status of the router in hist at time now for analysis; return it in a newly allocated string.

Definition at line 869 of file rephist.c.

{
  char sor_buf[ISO_TIME_LEN+1];
  char sod_buf[ISO_TIME_LEN+1];
  double wfu;
  double mtbf;
  int up = 0, down = 0;
  char *cp = NULL;

  if (hist->start_of_run) {
    format_iso_time(sor_buf, hist->start_of_run);
    up = 1;
  }
  if (hist->start_of_downtime) {
    format_iso_time(sod_buf, hist->start_of_downtime);
    down = 1;
  }

  wfu = get_weighted_fractional_uptime(hist, now);
  mtbf = get_stability(hist, now);
  tor_asprintf(&cp,
               "%s%s%s"
               "%s%s%s"
               "wfu %0.3f\n"
               " weighted-time %lu\n"
               " weighted-uptime %lu\n"
               "mtbf %0.1f\n"
               " weighted-run-length %lu\n"
               " total-run-weights %f\n",
               up?"uptime-started ":"", up?sor_buf:"", up?" UTC\n":"",
               down?"downtime-started ":"", down?sod_buf:"", down?" UTC\n":"",
               wfu,
               hist->total_weighted_time,
               hist->weighted_uptime,
               mtbf,
               hist->weighted_run_length,
               hist->total_run_weights
               );
  return cp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_free_all ( void  )

Free all storage held by the OR/link history caches, by the bandwidth history arrays, by the port history, or by statistics .

Definition at line 3000 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_get_bandwidth_lines ( void  )

Allocate and return lines for representing this server's bandwidth history in its descriptor.

We publish these lines in our extra-info descriptor.

Definition at line 1525 of file rephist.c.

{
  char *buf, *cp;
  char t[ISO_TIME_LEN+1];
  int r;
  bw_array_t *b = NULL;
  const char *desc = NULL;
  size_t len;

  /* opt [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
 * long, plus the comma. */
#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
  len = (67+MAX_HIST_VALUE_LEN)*4;
  buf = tor_malloc_zero(len);
  cp = buf;
  for (r=0;r<4;++r) {
    char tmp[MAX_HIST_VALUE_LEN];
    size_t slen;
    switch (r) {
      case 0:
        b = write_array;
        desc = "write-history";
        break;
      case 1:
        b = read_array;
        desc = "read-history";
        break;
      case 2:
        b = dir_write_array;
        desc = "dirreq-write-history";
        break;
      case 3:
        b = dir_read_array;
        desc = "dirreq-read-history";
        break;
    }
    tor_assert(b);
    slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
    /* If we don't have anything to write, skip to the next entry. */
    if (slen == 0)
      continue;
    format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
    tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
                 desc, t, NUM_SECS_BW_SUM_INTERVAL);
    cp += strlen(cp);
    strlcat(cp, tmp, len-(cp-buf));
    cp += slen;
    strlcat(cp, "\n", len-(cp-buf));
    ++cp;
  }
  return buf;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_get_predicted_internal ( time_t  now,
int *  need_uptime,
int *  need_capacity 
)

Return 1 if we've used an internal circ recently; else return 0.

Definition at line 1927 of file rephist.c.

{
  if (!predicted_internal_time) { /* initialize it */
    predicted_internal_time = now;
    predicted_internal_uptime_time = now;
    predicted_internal_capacity_time = now;
  }
  if (predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME < now)
    return 0; /* too long ago */
  if (predicted_internal_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now)
    *need_uptime = 1;
  // Always predict that we need capacity.
  *need_capacity = 1;
  return 1;
}

Here is the caller graph for this function:

Return a newly allocated pointer to a list of uint16_t * for ports that are likely to be asked for in the near future.

Definition at line 1856 of file rephist.c.

{
  smartlist_t *out = smartlist_new();
  tor_assert(predicted_ports_list);

  /* clean out obsolete entries */
  SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
    if (pp->time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
      log_debug(LD_CIRC, "Expiring predicted port %d", pp->port);

      rephist_total_alloc -= sizeof(predicted_port_t);
      tor_free(pp);
      SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
    } else {
      smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t)));
    }
  } SMARTLIST_FOREACH_END(pp);
  return out;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* rep_hist_get_router_stability_doc ( time_t  now)

Return a pointer to a NUL-terminated document describing our view of the stability of the routers we've been tracking.

Return NULL on failure.

Definition at line 922 of file rephist.c.

{
  char *result;
  smartlist_t *chunks;
  if (built_last_stability_doc_at + MAX_STABILITY_DOC_BUILD_RATE > now)
    return last_stability_doc;

  if (!history_map)
    return NULL;

  tor_free(last_stability_doc);
  chunks = smartlist_new();

  if (rep_hist_have_measured_enough_stability()) {
    smartlist_add(chunks, tor_strdup("we-have-enough-measurements\n"));
  } else {
    smartlist_add(chunks, tor_strdup("we-do-not-have-enough-measurements\n"));
  }

  DIGESTMAP_FOREACH(history_map, id, or_history_t *, hist) {
    const node_t *node;
    char dbuf[BASE64_DIGEST_LEN+1];
    char *info;
    digest_to_base64(dbuf, id);
    node = node_get_by_id(id);
    if (node) {
      char ip[INET_NTOA_BUF_LEN+1];
      char tbuf[ISO_TIME_LEN+1];
      time_t published = node_get_published_on(node);
      node_get_address_string(node,ip,sizeof(ip));
      if (published > 0)
        format_iso_time(tbuf, published);
      else
        strlcpy(tbuf, "???", sizeof(tbuf));
      smartlist_add_asprintf(chunks,
                   "router %s %s %s\n"
                   "published %s\n"
                   "relevant-flags %s%s%s\n"
                   "declared-uptime %ld\n",
                   dbuf, node_get_nickname(node), ip,
                   tbuf,
                   node->is_running ? "Running " : "",
                   node->is_valid ? "Valid " : "",
                   node->ri && node->ri->is_hibernating ? "Hibernating " : "",
                   node_get_declared_uptime(node));
    } else {
      smartlist_add_asprintf(chunks,
                   "router %s {no descriptor}\n", dbuf);
    }
    info = rep_hist_format_router_status(hist, now);
    if (info)
      smartlist_add(chunks, info);

  } DIGESTMAP_FOREACH_END;

  result = smartlist_join_strings(chunks, "", 0, NULL);
  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
  smartlist_free(chunks);

  last_stability_doc = result;
  built_last_stability_doc_at = time(NULL);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

double rep_hist_get_stability ( const char *  id,
time_t  when 
)

Return an estimated MTBF for the router whose identity digest is id.

Return 0 if the router is unknown.

Definition at line 549 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  if (!hist)
    return 0.0;

  return get_stability(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

long rep_hist_get_uptime ( const char *  id,
time_t  when 
)

Return how long the router whose identity digest is id has been reachable.

Return 0 if the router is unknown or currently deemed unreachable.

Definition at line 536 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  if (!hist)
    return 0;
  if (!hist->start_of_run || when < hist->start_of_run)
    return 0;
  return when - hist->start_of_run;
}

Here is the call graph for this function:

Here is the caller graph for this function:

double rep_hist_get_weighted_fractional_uptime ( const char *  id,
time_t  when 
)

Return an estimated percent-of-time-online for the router whose identity digest is id.

Return 0 if the router is unknown.

Definition at line 561 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  if (!hist)
    return 0.0;

  return get_weighted_fractional_uptime(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

long rep_hist_get_weighted_time_known ( const char *  id,
time_t  when 
)

Return a number representing how long we've known about the router whose digest is id.

Return 0 if the router is unknown.

Be careful: this measure increases monotonically as we know the router for longer and longer, but it doesn't increase linearly.

Definition at line 577 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  if (!hist)
    return 0;

  return get_total_weighted_time(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true if we've been measuring MTBFs for long enough to pronounce on Stability.

Definition at line 589 of file rephist.c.

{
  /* XXXX023 This doesn't do so well when we change our opinion
   * as to whether we're tracking router stability. */
  return started_tracking_stability < time(NULL) - 4*60*60;
}

Here is the caller graph for this function:

void rep_hist_init ( void  )

Initialize the static data structures for tracking history.

Definition at line 199 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static int rep_hist_load_bwhist_state_section ( bw_array_t b,
const smartlist_t s_values,
const smartlist_t s_maxima,
const time_t  s_begins,
const int  s_interval 
) [static]

Load a single bw_array_t from its Values, Ends, Maxima, and Interval entries in an or_state_t.

Done while reading the state file.

Definition at line 1666 of file rephist.c.

{
  time_t now = time(NULL);
  int retval = 0;
  time_t start;

  uint64_t v, mv;
  int i,ok,ok_m;
  int have_maxima = (smartlist_len(s_values) == smartlist_len(s_maxima));

  if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
    start = s_begins - s_interval*(smartlist_len(s_values));
    if (start > now)
      return 0;
    b->cur_obs_time = start;
    b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
    SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
        const char *maxstr = NULL;
        v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
        if (have_maxima) {
          maxstr = smartlist_get(s_maxima, cp_sl_idx);
          mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
          mv *= NUM_SECS_ROLLING_MEASURE;
        } else {
          /* No maxima known; guess average rate to be conservative. */
          mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
        }
        if (!ok) {
          retval = -1;
          log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
        }
        if (maxstr && !ok_m) {
          retval = -1;
          log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
                     maxstr);
        }

        if (start < now) {
          time_t cur_start = start;
          time_t actual_interval_len = s_interval;
          uint64_t cur_val = 0;
          /* Calculate the average per second. This is the best we can do
           * because our state file doesn't have per-second resolution. */
          if (start + s_interval > now)
            actual_interval_len = now - start;
          cur_val = v / actual_interval_len;
          /* This is potentially inefficient, but since we don't do it very
           * often it should be ok. */
          while (cur_start < start + actual_interval_len) {
            add_obs(b, cur_start, cur_val);
            ++cur_start;
          }
          b->max_total = mv;
          /* This will result in some fairly choppy history if s_interval
           * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
          start += actual_interval_len;
        }
    } SMARTLIST_FOREACH_END(cp);
  }

  /* Clean up maxima and observed */
  for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
    b->obs[i] = 0;
  }
  b->total_obs = 0;

  return retval;
}

Here is the call graph for this function:

int rep_hist_load_mtbf_data ( time_t  now)

Load MTBF data from disk.

Returns 0 on success or recoverable error, -1 on failure.

Definition at line 1048 of file rephist.c.

{
  /* XXXX won't handle being called while history is already populated. */
  smartlist_t *lines;
  const char *line = NULL;
  int r=0, i;
  time_t last_downrated = 0, stored_at = 0, tracked_since = 0;
  time_t latest_possible_start = now;
  long format = -1;

  {
    char *filename = get_datadir_fname("router-stability");
    char *d = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
    tor_free(filename);
    if (!d)
      return -1;
    lines = smartlist_new();
    smartlist_split_string(lines, d, "\n", SPLIT_SKIP_SPACE, 0);
    tor_free(d);
  }

  {
    const char *firstline;
    if (smartlist_len(lines)>4) {
      firstline = smartlist_get(lines, 0);
      if (!strcmpstart(firstline, "format "))
        format = tor_parse_long(firstline+strlen("format "),
                                10, -1, LONG_MAX, NULL, NULL);
    }
  }
  if (format != 1 && format != 2) {
    log_warn(LD_HIST,
             "Unrecognized format in mtbf history file. Skipping.");
    goto err;
  }
  for (i = 1; i < smartlist_len(lines); ++i) {
    line = smartlist_get(lines, i);
    if (!strcmp(line, "data"))
      break;
    if (!strcmpstart(line, "last-downrated ")) {
      if (parse_iso_time(line+strlen("last-downrated "), &last_downrated)<0)
        log_warn(LD_HIST,"Couldn't parse downrate time in mtbf "
                 "history file.");
    }
    if (!strcmpstart(line, "stored-at ")) {
      if (parse_iso_time(line+strlen("stored-at "), &stored_at)<0)
        log_warn(LD_HIST,"Couldn't parse stored time in mtbf "
                 "history file.");
    }
    if (!strcmpstart(line, "tracked-since ")) {
      if (parse_iso_time(line+strlen("tracked-since "), &tracked_since)<0)
        log_warn(LD_HIST,"Couldn't parse started-tracking time in mtbf "
                 "history file.");
    }
  }
  if (last_downrated > now)
    last_downrated = now;
  if (tracked_since > now)
    tracked_since = now;

  if (!stored_at) {
    log_warn(LD_HIST, "No stored time recorded.");
    goto err;
  }

  if (line && !strcmp(line, "data"))
    ++i;

  n_bogus_times = 0;

  for (; i < smartlist_len(lines); ++i) {
    char digest[DIGEST_LEN];
    char hexbuf[HEX_DIGEST_LEN+1];
    char mtbf_timebuf[ISO_TIME_LEN+1];
    char wfu_timebuf[ISO_TIME_LEN+1];
    time_t start_of_run = 0;
    time_t start_of_downtime = 0;
    int have_mtbf = 0, have_wfu = 0;
    long wrl = 0;
    double trw = 0;
    long wt_uptime = 0, total_wt_time = 0;
    int n;
    or_history_t *hist;
    line = smartlist_get(lines, i);
    if (!strcmp(line, "."))
      break;

    mtbf_timebuf[0] = '\0';
    wfu_timebuf[0] = '\0';

    if (format == 1) {
      n = sscanf(line, "%40s %ld %lf S=%10s %8s",
                 hexbuf, &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
      if (n != 3 && n != 5) {
        log_warn(LD_HIST, "Couldn't scan line %s", escaped(line));
        continue;
      }
      have_mtbf = 1;
    } else {
      // format == 2.
      int mtbf_idx, wfu_idx;
      if (strcmpstart(line, "R ") || strlen(line) < 2+HEX_DIGEST_LEN)
        continue;
      strlcpy(hexbuf, line+2, sizeof(hexbuf));
      mtbf_idx = find_next_with(lines, i+1, "+MTBF ");
      wfu_idx = find_next_with(lines, i+1, "+WFU ");
      if (mtbf_idx >= 0) {
        const char *mtbfline = smartlist_get(lines, mtbf_idx);
        n = sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
                   &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
        if (n == 2 || n == 4) {
          have_mtbf = 1;
        } else {
          log_warn(LD_HIST, "Couldn't scan +MTBF line %s",
                   escaped(mtbfline));
        }
      }
      if (wfu_idx >= 0) {
        const char *wfuline = smartlist_get(lines, wfu_idx);
        n = sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
                   &wt_uptime, &total_wt_time,
                   wfu_timebuf, wfu_timebuf+11);
        if (n == 2 || n == 4) {
          have_wfu = 1;
        } else {
          log_warn(LD_HIST, "Couldn't scan +WFU line %s", escaped(wfuline));
        }
      }
      if (wfu_idx > i)
        i = wfu_idx;
      if (mtbf_idx > i)
        i = mtbf_idx;
    }
    if (base16_decode(digest, DIGEST_LEN, hexbuf, HEX_DIGEST_LEN) < 0) {
      log_warn(LD_HIST, "Couldn't hex string %s", escaped(hexbuf));
      continue;
    }
    hist = get_or_history(digest);
    if (!hist)
      continue;

    if (have_mtbf) {
      if (mtbf_timebuf[0]) {
        mtbf_timebuf[10] = ' ';
        if (parse_possibly_bad_iso_time(mtbf_timebuf, &start_of_run)<0)
          log_warn(LD_HIST, "Couldn't parse time %s",
                   escaped(mtbf_timebuf));
      }
      hist->start_of_run = correct_time(start_of_run, now, stored_at,
                                        tracked_since);
      if (hist->start_of_run < latest_possible_start + wrl)
        latest_possible_start = hist->start_of_run - wrl;

      hist->weighted_run_length = wrl;
      hist->total_run_weights = trw;
    }
    if (have_wfu) {
      if (wfu_timebuf[0]) {
        wfu_timebuf[10] = ' ';
        if (parse_possibly_bad_iso_time(wfu_timebuf, &start_of_downtime)<0)
          log_warn(LD_HIST, "Couldn't parse time %s", escaped(wfu_timebuf));
      }
    }
    hist->start_of_downtime = correct_time(start_of_downtime, now, stored_at,
                                           tracked_since);
    hist->weighted_uptime = wt_uptime;
    hist->total_weighted_time = total_wt_time;
  }
  if (strcmp(line, "."))
    log_warn(LD_HIST, "Truncated MTBF file.");

  if (tracked_since < 86400*365) /* Recover from insanely early value. */
    tracked_since = latest_possible_start;

  stability_last_downrated = last_downrated;
  started_tracking_stability = tracked_since;

  goto done;
 err:
  r = -1;
 done:
  SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
  smartlist_free(lines);
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_load_state ( or_state_t state,
char **  err 
)

Set bandwidth history from the state file we just loaded.

Definition at line 1741 of file rephist.c.

{
  int all_ok = 1;

  /* Assert they already have been malloced */
  tor_assert(read_array && write_array);
  tor_assert(dir_read_array && dir_write_array);

#define LOAD(arrname,st)                                                \
  if (rep_hist_load_bwhist_state_section(                               \
                                (arrname),                              \
                                state->BWHistory ## st ## Values,       \
                                state->BWHistory ## st ## Maxima,       \
                                state->BWHistory ## st ## Ends,         \
                                state->BWHistory ## st ## Interval)<0)  \
    all_ok = 0

  LOAD(write_array, Write);
  LOAD(read_array, Read);
  LOAD(dir_write_array, DirWrite);
  LOAD(dir_read_array, DirRead);

#undef LOAD
  if (!all_ok) {
    *err = tor_strdup("Parsing of bandwidth history values failed");
    /* and create fresh arrays */
    bw_arrays_init();
    return -1;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_bytes_read ( size_t  num_bytes,
time_t  when 
)

Remember that we wrote num_bytes bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1410 of file rephist.c.

{
/* if we're smart, we can make this func and the one above share code */
  add_obs(read_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_bytes_written ( size_t  num_bytes,
time_t  when 
)

Remember that we read num_bytes bytes in second when.

Add num_bytes to the current running total for when.

when can go back to time, but it's safe to ignore calls earlier than the latest when you've heard of.

Definition at line 1393 of file rephist.c.

{
/* 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.
 */
  add_obs(write_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connect_failed ( const char *  id,
time_t  when 
)

Remember that an attempt to connect to the OR with identity digest id failed at when.

Definition at line 239 of file rephist.c.

{
  or_history_t *hist;
  hist = get_or_history(id);
  if (!hist)
    return;
  ++hist->n_conn_fail;
  mark_or_down(hist, when, 1);
  hist->changed = when;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connect_succeeded ( const char *  id,
time_t  when 
)

Remember that an attempt to connect to the OR with identity digest id succeeded at when.

Definition at line 254 of file rephist.c.

{
  or_history_t *hist;
  hist = get_or_history(id);
  if (!hist)
    return;
  ++hist->n_conn_ok;
  mark_or_up(hist, when);
  hist->changed = when;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connection_died ( const char *  id,
time_t  when 
)

Remember that our connection to the OR with identity digest id had an error and stopped working at when.

Definition at line 283 of file rephist.c.

{
  or_history_t *hist;
  if (!id) {
    /* If conn has no identity, it didn't complete its handshake, or something
     * went wrong.  Ignore it.
     */
    return;
  }
  hist = get_or_history(id);
  if (!hist)
    return;
  mark_or_down(hist, when, 1);
  hist->changed = when;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_desc_served ( const char *  desc)

Definition at line 2757 of file rephist.c.

{
  void *val;
  uintptr_t count;
  if (!served_descs)
    return; // We're not collecting stats
  val = digestmap_get(served_descs, desc);
  count = (uintptr_t)val;
  if (count != INT_MAX)
    ++count;
  digestmap_set(served_descs, desc, (void*)count);
  total_descriptor_downloads++;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_dir_bytes_read ( size_t  num_bytes,
time_t  when 
)

Remember that we read num_bytes directory bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1429 of file rephist.c.

{
  add_obs(dir_read_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_dir_bytes_written ( size_t  num_bytes,
time_t  when 
)

Remember that we wrote num_bytes directory bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1420 of file rephist.c.

{
  add_obs(dir_write_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_disconnect ( const char *  id,
time_t  when 
)

Remember that we intentionally closed our connection to the OR with identity digest id at when.

Definition at line 269 of file rephist.c.

{
  or_history_t *hist;
  hist = get_or_history(id);
  if (!hist)
    return;
  mark_or_down(hist, when, 0);
  hist->changed = when;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_exit_bytes ( uint16_t  port,
size_t  num_written,
size_t  num_read 
)

Note that we wrote num_written bytes and read num_read bytes to/from an exit connection to port.

Definition at line 2334 of file rephist.c.

{
  if (!start_of_exit_stats_interval)
    return; /* Not initialized. */
  exit_bytes_written[port] += num_written;
  exit_bytes_read[port] += num_read;
  log_debug(LD_HIST, "Written %lu bytes and read %lu bytes to/from an "
            "exit connection to port %d.",
            (unsigned long)num_written, (unsigned long)num_read, port);
}

Here is the caller graph for this function:

void rep_hist_note_exit_stream_opened ( uint16_t  port)

Note that we opened an exit stream to port.

Definition at line 2348 of file rephist.c.

{
  if (!start_of_exit_stats_interval)
    return; /* Not initialized. */
  exit_streams[port]++;
  log_debug(LD_HIST, "Opened exit stream to port %d", port);
}

Here is the caller graph for this function:

void rep_hist_note_extend_failed ( const char *  from_id,
const char *  to_id 
)

Remember that we tried to extend from the OR with identity digest from_id to the OR with identity digest to_name, but failed.

Definition at line 617 of file rephist.c.

{
  link_history_t *hist;
  /* log_fn(LOG_WARN, "EXTEND FAILED: %s->%s",from_name,to_name); */
  hist = get_link_history(from_id, to_id);
  if (!hist)
    return;
  ++hist->n_extend_fail;
  hist->changed = time(NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_extend_succeeded ( const char *  from_id,
const char *  to_id 
)

Remember that we successfully extended from the OR with identity digest from_id to the OR with identity digest to_name.

Definition at line 601 of file rephist.c.

{
  link_history_t *hist;
  /* log_fn(LOG_WARN, "EXTEND SUCCEEDED: %s->%s",from_name,to_name); */
  hist = get_link_history(from_id, to_id);
  if (!hist)
    return;
  ++hist->n_extend_ok;
  hist->changed = time(NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_or_conn_bytes ( uint64_t  conn_id,
size_t  num_read,
size_t  num_written,
time_t  when 
)

We read num_read bytes and wrote num_written from/to OR connection conn_id in second when.

If this is the first observation in a new interval, sum up the last observations. Add bytes for this connection.

Definition at line 2887 of file rephist.c.

{
  if (!start_of_conn_stats_interval)
    return;
  /* Initialize */
  if (bidi_next_interval == 0)
    bidi_next_interval = when + BIDI_INTERVAL;
  /* Sum up last period's statistics */
  if (when >= bidi_next_interval) {
    bidi_map_entry_t **ptr, **next, *ent;
    for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
      ent = *ptr;
      if (ent->read + ent->written < BIDI_THRESHOLD)
        below_threshold++;
      else if (ent->read >= ent->written * BIDI_FACTOR)
        mostly_read++;
      else if (ent->written >= ent->read * BIDI_FACTOR)
        mostly_written++;
      else
        both_read_and_written++;
      next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
      tor_free(ent);
    }
    while (when >= bidi_next_interval)
      bidi_next_interval += BIDI_INTERVAL;
    log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
             "%d mostly written, %d both read and written.",
             below_threshold, mostly_read, mostly_written,
             both_read_and_written);
  }
  /* Add this connection's bytes. */
  if (num_read > 0 || num_written > 0) {
    bidi_map_entry_t *entry, lookup;
    lookup.conn_id = conn_id;
    entry = HT_FIND(bidimap, &bidi_map, &lookup);
    if (entry) {
      entry->written += num_written;
      entry->read += num_read;
    } else {
      entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
      entry->conn_id = conn_id;
      entry->written = num_written;
      entry->read = num_read;
      HT_INSERT(bidimap, &bidi_map, entry);
    }
  }
}

Here is the caller graph for this function:

void rep_hist_note_router_reachable ( const char *  id,
const tor_addr_t at_addr,
const uint16_t  at_port,
time_t  when 
)

We have just decided that this router with identity digest id is reachable, meaning we will give it a "Running" flag for the next while.

Definition at line 302 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  int was_in_run = 1;
  char tbuf[ISO_TIME_LEN+1];
  int addr_changed, port_changed;

  tor_assert(hist);
  tor_assert((!at_addr && !at_port) || (at_addr && at_port));

  addr_changed = at_addr &&
    tor_addr_compare(at_addr, &hist->last_reached_addr, CMP_EXACT) != 0;
  port_changed = at_port && at_port != hist->last_reached_port;

  if (!started_tracking_stability)
    started_tracking_stability = time(NULL);
  if (!hist->start_of_run) {
    hist->start_of_run = when;
    was_in_run = 0;
  }
  if (hist->start_of_downtime) {
    long down_length;

    format_local_iso_time(tbuf, hist->start_of_downtime);
    log_info(LD_HIST, "Router %s is now Running; it had been down since %s.",
             hex_str(id, DIGEST_LEN), tbuf);
    if (was_in_run)
      log_info(LD_HIST, "  (Paradoxically, it was already Running too.)");

    down_length = when - hist->start_of_downtime;
    hist->total_weighted_time += down_length;
    hist->start_of_downtime = 0;
  } else if (addr_changed || port_changed) {
    /* If we're reachable, but the address changed, treat this as some
     * downtime. */
    int penalty = get_options()->TestingTorNetwork ? 240 : 3600;
    networkstatus_t *ns;

    if ((ns = networkstatus_get_latest_consensus())) {
      int fresh_interval = (int)(ns->fresh_until - ns->valid_after);
      int live_interval = (int)(ns->valid_until - ns->valid_after);
      /* on average, a descriptor addr change takes .5 intervals to make it
       * into a consensus, and half a liveness period to make it to
       * clients. */
      penalty = (int)(fresh_interval + live_interval) / 2;
    }
    format_local_iso_time(tbuf, hist->start_of_run);
    log_info(LD_HIST,"Router %s still seems Running, but its address appears "
             "to have changed since the last time it was reachable.  I'm "
             "going to treat it as having been down for %d seconds",
             hex_str(id, DIGEST_LEN), penalty);
    rep_hist_note_router_unreachable(id, when-penalty);
    rep_hist_note_router_reachable(id, NULL, 0, when);
  } else {
    format_local_iso_time(tbuf, hist->start_of_run);
    if (was_in_run)
      log_debug(LD_HIST, "Router %s is still Running; it has been Running "
                "since %s", hex_str(id, DIGEST_LEN), tbuf);
    else
      log_info(LD_HIST,"Router %s is now Running; it was previously untracked",
               hex_str(id, DIGEST_LEN));
  }
  if (at_addr)
    tor_addr_copy(&hist->last_reached_addr, at_addr);
  if (at_port)
    hist->last_reached_port = at_port;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_router_unreachable ( const char *  id,
time_t  when 
)

We have just decided that this router is unreachable, meaning we are taking away its "Running" flag.

Definition at line 374 of file rephist.c.

{
  or_history_t *hist = get_or_history(id);
  char tbuf[ISO_TIME_LEN+1];
  int was_running = 0;
  if (!started_tracking_stability)
    started_tracking_stability = time(NULL);

  tor_assert(hist);
  if (hist->start_of_run) {
    /*XXXX We could treat failed connections differently from failed
     * connect attempts. */
    long run_length = when - hist->start_of_run;
    format_local_iso_time(tbuf, hist->start_of_run);

    hist->total_run_weights += 1.0;
    hist->start_of_run = 0;
    if (run_length < 0) {
      unsigned long penalty = -run_length;
#define SUBTRACT_CLAMPED(var, penalty) \
      do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0)

      SUBTRACT_CLAMPED(hist->weighted_run_length, penalty);
      SUBTRACT_CLAMPED(hist->weighted_uptime, penalty);
    } else {
      hist->weighted_run_length += run_length;
      hist->weighted_uptime += run_length;
      hist->total_weighted_time += run_length;
    }
    was_running = 1;
    log_info(LD_HIST, "Router %s is now non-Running: it had previously been "
             "Running since %s.  Its total weighted uptime is %lu/%lu.",
             hex_str(id, DIGEST_LEN), tbuf, hist->weighted_uptime,
             hist->total_weighted_time);
  }
  if (!hist->start_of_downtime) {
    hist->start_of_downtime = when;

    if (!was_running)
      log_info(LD_HIST, "Router %s is now non-Running; it was previously "
               "untracked.", hex_str(id, DIGEST_LEN));
  } else {
    if (!was_running) {
      format_local_iso_time(tbuf, hist->start_of_downtime);

      log_info(LD_HIST, "Router %s is still non-Running; it has been "
               "non-Running since %s.", hex_str(id, DIGEST_LEN), tbuf);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_used_internal ( time_t  now,
int  need_uptime,
int  need_capacity 
)

Remember that we used an internal circ at time now.

Definition at line 1916 of file rephist.c.

{
  predicted_internal_time = now;
  if (need_uptime)
    predicted_internal_uptime_time = now;
  if (need_capacity)
    predicted_internal_capacity_time = now;
}

Here is the caller graph for this function:

void rep_hist_note_used_port ( time_t  now,
uint16_t  port 
)

Remember that port has been asked for as of time now.

This is used for predicting what sorts of streams we'll make in the future and making exit circuits to anticipate that.

Definition at line 1831 of file rephist.c.

{
  tor_assert(predicted_ports_list);

  if (!port) /* record nothing */
    return;

  SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
    if (pp->port == port) {
      pp->time = now;
      return;
    }
  } SMARTLIST_FOREACH_END(pp);
  /* it's not there yet; we need to add it */
  add_predicted_port(now, port);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_used_resolve ( time_t  now)

The user asked us to do a resolve.

Rather than keeping track of timings and such of resolves, we fake it for now by 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.

Definition at line 1902 of file rephist.c.

Here is the call graph for this function:

int rep_hist_record_mtbf_data ( time_t  now,
int  missing_means_down 
)

Write MTBF data to disk.

Return 0 on success, negative on failure.

If missing_means_down, then if we're about to write an entry that is still considered up but isn't in our routerlist, consider it to be down.

Definition at line 765 of file rephist.c.

{
  char time_buf[ISO_TIME_LEN+1];

  digestmap_iter_t *orhist_it;
  const char *digest;
  void *or_history_p;
  or_history_t *hist;
  open_file_t *open_file = NULL;
  FILE *f;

  {
    char *filename = get_datadir_fname("router-stability");
    f = start_writing_to_stdio_file(filename, OPEN_FLAGS_REPLACE|O_TEXT, 0600,
                                    &open_file);
    tor_free(filename);
    if (!f)
      return -1;
  }

  /* File format is:
   *   FormatLine *KeywordLine Data
   *
   *   FormatLine = "format 1" NL
   *   KeywordLine = Keyword SP Arguments NL
   *   Data = "data" NL *RouterMTBFLine "." NL
   *   RouterMTBFLine = Fingerprint SP WeightedRunLen SP
   *           TotalRunWeights [SP S=StartRunTime] NL
   */
#define PUT(s) STMT_BEGIN if (fputs((s),f)<0) goto err; STMT_END
#define PRINTF(args) STMT_BEGIN if (fprintf args <0) goto err; STMT_END

  PUT("format 2\n");

  format_iso_time(time_buf, time(NULL));
  PRINTF((f, "stored-at %s\n", time_buf));

  if (started_tracking_stability) {
    format_iso_time(time_buf, started_tracking_stability);
    PRINTF((f, "tracked-since %s\n", time_buf));
  }
  if (stability_last_downrated) {
    format_iso_time(time_buf, stability_last_downrated);
    PRINTF((f, "last-downrated %s\n", time_buf));
  }

  PUT("data\n");

  /* XXX Nick: now bridge auths record this for all routers too.
   * Should we make them record it only for bridge routers? -RD
   * Not for 0.2.0. -NM */
  for (orhist_it = digestmap_iter_init(history_map);
       !digestmap_iter_done(orhist_it);
       orhist_it = digestmap_iter_next(history_map,orhist_it)) {
    char dbuf[HEX_DIGEST_LEN+1];
    const char *t = NULL;
    digestmap_iter_get(orhist_it, &digest, &or_history_p);
    hist = (or_history_t*) or_history_p;

    base16_encode(dbuf, sizeof(dbuf), digest, DIGEST_LEN);

    if (missing_means_down && hist->start_of_run &&
        !router_get_by_id_digest(digest)) {
      /* We think this relay is running, but it's not listed in our
       * routerlist. Somehow it fell out without telling us it went
       * down. Complain and also correct it. */
      log_info(LD_HIST,
               "Relay '%s' is listed as up in rephist, but it's not in "
               "our routerlist. Correcting.", dbuf);
      rep_hist_note_router_unreachable(digest, now);
    }

    PRINTF((f, "R %s\n", dbuf));
    if (hist->start_of_run > 0) {
      format_iso_time(time_buf, hist->start_of_run);
      t = time_buf;
    }
    PRINTF((f, "+MTBF %lu %.5f%s%s\n",
            hist->weighted_run_length, hist->total_run_weights,
            t ? " S=" : "", t ? t : ""));
    t = NULL;
    if (hist->start_of_downtime > 0) {
      format_iso_time(time_buf, hist->start_of_downtime);
      t = time_buf;
    }
    PRINTF((f, "+WFU %lu %lu%s%s\n",
            hist->weighted_uptime, hist->total_weighted_time,
            t ? " S=" : "", t ? t : ""));
  }

  PUT(".\n");

#undef PUT
#undef PRINTF

  return finish_writing_to_file(open_file);
 err:
  abort_writing_to_file(open_file);
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_remove_predicted_ports ( const smartlist_t rmv_ports)

Take a list of uint16_t *, and remove every port in the list from the current list of predicted ports.

Definition at line 1881 of file rephist.c.

{
  /* Let's do this on O(N), not O(N^2). */
  bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX);
  SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p,
                    bitarray_set(remove_ports, *p));
  SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) {
    if (bitarray_is_set(remove_ports, pp->port)) {
      tor_free(pp);
      SMARTLIST_DEL_CURRENT(predicted_ports_list, pp);
    }
  } SMARTLIST_FOREACH_END(pp);
  bitarray_free(remove_ports);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_buffer_stats ( time_t  now)

Clear history of circuit statistics and set the measurement interval start to now.

Definition at line 2464 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_conn_stats ( time_t  now)

Reset counters for conn statistics.

Definition at line 2864 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void rep_hist_reset_desc_stats ( time_t  now) [static]

Reset served descs stats to empty, starting a new interval now.

Definition at line 2649 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_exit_stats ( time_t  now)

Reset counters for exit port statistics.

Definition at line 2110 of file rephist.c.

{
  start_of_exit_stats_interval = now;
  memset(exit_bytes_read, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
  memset(exit_bytes_written, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
  memset(exit_streams, 0, EXIT_STATS_NUM_PORTS * sizeof(uint32_t));
}

Here is the caller graph for this function:

static void rep_hist_update_bwhist_state_section ( or_state_t state,
const bw_array_t b,
smartlist_t **  s_values,
smartlist_t **  s_maxima,
time_t *  s_begins,
int *  s_interval 
) [static]

Write a single bw_array_t into the Values, Ends, Interval, and Maximum entries of an or_state_t.

Done before writing out a new state file.

Definition at line 1582 of file rephist.c.

{
  int i,j;
  uint64_t maxval;

  if (*s_values) {
    SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
    smartlist_free(*s_values);
  }
  if (*s_maxima) {
    SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
    smartlist_free(*s_maxima);
  }
  if (! server_mode(get_options())) {
    /* Clients don't need to store bandwidth history persistently;
     * force these values to the defaults. */
    /* FFFF we should pull the default out of config.c's state table,
     * so we don't have two defaults. */
    if (*s_begins != 0 || *s_interval != 900) {
      time_t now = time(NULL);
      time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
      or_state_mark_dirty(state, save_at);
    }
    *s_begins = 0;
    *s_interval = 900;
    *s_values = smartlist_new();
    *s_maxima = smartlist_new();
    return;
  }
  *s_begins = b->next_period;
  *s_interval = NUM_SECS_BW_SUM_INTERVAL;

  *s_values = smartlist_new();
  *s_maxima = smartlist_new();
  /* Set i to first position in circular array */
  i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
  for (j=0; j < b->num_maxes_set; ++j,++i) {
    if (i >= NUM_TOTALS)
      i = 0;
    smartlist_add_asprintf(*s_values, U64_FORMAT,
                           U64_PRINTF_ARG(b->totals[i] & ~0x3ff));
    maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
    smartlist_add_asprintf(*s_maxima, U64_FORMAT,
                           U64_PRINTF_ARG(maxval & ~0x3ff));
  }
  smartlist_add_asprintf(*s_values, U64_FORMAT,
                         U64_PRINTF_ARG(b->total_in_period & ~0x3ff));
  maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
  smartlist_add_asprintf(*s_maxima, U64_FORMAT,
                         U64_PRINTF_ARG(maxval & ~0x3ff));
}

Here is the call graph for this function:

void rep_hist_update_state ( or_state_t state)

Update state with the newest bandwidth history.

Done before writing out a new state file.

Definition at line 1642 of file rephist.c.

{
#define UPDATE(arrname,st) \
  rep_hist_update_bwhist_state_section(state,\
                                       (arrname),\
                                       &state->BWHistory ## st ## Values, \
                                       &state->BWHistory ## st ## Maxima, \
                                       &state->BWHistory ## st ## Ends, \
                                       &state->BWHistory ## st ## Interval)

  UPDATE(write_array, Write);
  UPDATE(read_array, Read);
  UPDATE(dir_write_array, DirWrite);
  UPDATE(dir_read_array, DirRead);

  if (server_mode(get_options())) {
    or_state_mark_dirty(state, time(NULL)+(2*3600));
  }
#undef UPDATE
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_history_clean ( time_t  before)

Remove history info for routers/links that haven't changed since before.

Definition at line 719 of file rephist.c.

{
  int authority = authdir_mode(get_options());
  or_history_t *or_history;
  link_history_t *link_history;
  void *or_history_p, *link_history_p;
  digestmap_iter_t *orhist_it, *lhist_it;
  const char *d1, *d2;

  orhist_it = digestmap_iter_init(history_map);
  while (!digestmap_iter_done(orhist_it)) {
    int remove;
    digestmap_iter_get(orhist_it, &d1, &or_history_p);
    or_history = or_history_p;

    remove = authority ? (or_history->total_run_weights < STABILITY_EPSILON &&
                          !or_history->start_of_run)
                       : (or_history->changed < before);
    if (remove) {
      orhist_it = digestmap_iter_next_rmv(history_map, orhist_it);
      free_or_history(or_history);
      continue;
    }
    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);
      link_history = link_history_p;
      if (link_history->changed < before) {
        lhist_it = digestmap_iter_next_rmv(or_history->link_history_map,
                                           lhist_it);
        rephist_total_alloc -= sizeof(link_history_t);
        tor_free(link_history);
        continue;
      }
      lhist_it = digestmap_iter_next(or_history->link_history_map,lhist_it);
    }
    orhist_it = digestmap_iter_next(history_map, orhist_it);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void update_or_history ( or_history_t hist,
time_t  when 
) [static]

Update an or_history_t object hist so that its uptime/downtime count is up-to-date as of when.

Definition at line 184 of file rephist.c.

{
  tor_assert(hist);
  if (hist->up_since) {
    tor_assert(!hist->down_since);
    hist->uptime += (when - hist->up_since);
    hist->up_since = when;
  } else if (hist->down_since) {
    hist->downtime += (when - hist->down_since);
    hist->down_since = when;
  }
}

Here is the caller graph for this function:


Variable Documentation

uint32_t below_threshold = 0 [static]

Number of connections that we read and wrote less than BIDI_THRESHOLD bytes from/to in BIDI_INTERVAL seconds.

Definition at line 2802 of file rephist.c.

time_t bidi_next_interval = 0 [static]

Start of next BIDI_INTERVAL second interval.

Definition at line 2798 of file rephist.c.

uint32_t both_read_and_written = 0 [static]

Number of connections that we read and wrote at least BIDI_THRESHOLD bytes from/to, but not BIDI_FACTOR times more in either direction in BIDI_INTERVAL seconds.

Definition at line 2815 of file rephist.c.

time_t built_last_stability_doc_at = 0 [static]

The last time we created a stability analysis document, or 0 if we never have created one.

Definition at line 915 of file rephist.c.

List of circ_buffer_stats_t.

Definition at line 2381 of file rephist.c.

bw_array_t* dir_read_array = NULL [static]

Recent history of bandwidth observations for read operations for the directory protocol.

Definition at line 1365 of file rephist.c.

bw_array_t* dir_write_array = NULL [static]

Recent history of bandwidth observations for write operations for the directory protocol.

Definition at line 1368 of file rephist.c.

uint64_t* exit_bytes_read = NULL [static]

Number of bytes read in current period by exit port.

Definition at line 2086 of file rephist.c.

uint64_t* exit_bytes_written = NULL [static]

Number of bytes written in current period by exit port.

Definition at line 2088 of file rephist.c.

uint32_t* exit_streams = NULL [static]

Number of streams opened in current period by exit port.

Definition at line 2090 of file rephist.c.

digestmap_t* history_map = NULL [static]

Map from hex OR identity digest to or_history_t.

Definition at line 112 of file rephist.c.

char* last_stability_doc = NULL [static]

The last stability analysis document that we created, or NULL if we never have created one.

Definition at line 912 of file rephist.c.

uint32_t mostly_read = 0 [static]

Number of connections that we read at least BIDI_FACTOR times more bytes from than we wrote to in BIDI_INTERVAL seconds.

Definition at line 2806 of file rephist.c.

uint32_t mostly_written = 0 [static]

Number of connections that we wrote at least BIDI_FACTOR times more bytes to than we read from in BIDI_INTERVAL seconds.

Definition at line 2810 of file rephist.c.

int n_bogus_times = 0 [static]

How many bad times has parse_possibly_bad_iso_time() parsed?

Definition at line 1003 of file rephist.c.

struct { ... } pk_op_counts [static]

Structure to track how many times we've done each public key operation.

time_t predicted_internal_capacity_time = 0 [static]

The last time we needed an internal circ with good capacity.

Definition at line 1912 of file rephist.c.

time_t predicted_internal_time = 0 [static]

The last time at which we needed an internal circ.

Definition at line 1908 of file rephist.c.

time_t predicted_internal_uptime_time = 0 [static]

The last time we needed an internal circ with good uptime.

Definition at line 1910 of file rephist.c.

A list of port numbers that have been used recently.

Definition at line 1786 of file rephist.c.

bw_array_t* read_array = NULL [static]

Recent history of bandwidth observations for read operations.

Definition at line 1360 of file rephist.c.

uint64_t rephist_total_alloc = 0

Total number of bytes currently allocated in fields used by rephist.c.

Definition at line 28 of file rephist.c.

uint32_t rephist_total_num = 0

Number of or_history_t objects currently allocated.

Definition at line 30 of file rephist.c.

digestmap_t* served_descs = NULL [static]

Digestmap to track which descriptors were downloaded this stats collection interval.

It maps descriptor digest to pointers to 1, effectively turning this into a list.

Definition at line 2624 of file rephist.c.

time_t stability_last_downrated = 0 [static]

When did we last multiply all routers' weighted_run_length and total_run_weights by STABILITY_ALPHA?

Definition at line 106 of file rephist.c.

Start of the current buffer stats interval or 0 if we're not collecting buffer statistics.

Definition at line 2360 of file rephist.c.

Start of the current connection stats interval or 0 if we're not collecting connection statistics.

Definition at line 2775 of file rephist.c.

Start time of exit stats or 0 if we're not collecting exit stats.

Definition at line 2093 of file rephist.c.

Start time of served descs stats or 0 if we're not collecting those.

Definition at line 2631 of file rephist.c.

time_t started_tracking_stability = 0 [static]

Definition at line 109 of file rephist.c.

unsigned long total_descriptor_downloads [static]

Number of how many descriptors were downloaded in total during this interval.

Definition at line 2628 of file rephist.c.

bw_array_t* write_array = NULL [static]

Recent history of bandwidth observations for write operations.

Definition at line 1362 of file rephist.c.