diff options
Diffstat (limited to 'src/or/rephist.c')
-rw-r--r-- | src/or/rephist.c | 503 |
1 files changed, 308 insertions, 195 deletions
diff --git a/src/or/rephist.c b/src/or/rephist.c index 2948bf8f00..fe0997c891 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2013, The Tor Project, Inc. */ + * Copyright (c) 2007-2015, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -879,126 +879,6 @@ rep_hist_record_mtbf_data(time_t now, int missing_means_down) return -1; } -/** Format the current tracked status of the router in <b>hist</b> at time - * <b>now</b> for analysis; return it in a newly allocated string. */ -static char * -rep_hist_format_router_status(or_history_t *hist, time_t now) -{ - 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; -} - -/** The last stability analysis document that we created, or NULL if we never - * have created one. */ -static char *last_stability_doc = NULL; -/** The last time we created a stability analysis document, or 0 if we never - * have created one. */ -static time_t built_last_stability_doc_at = 0; -/** Shortest allowable time between building two stability documents. */ -#define MAX_STABILITY_DOC_BUILD_RATE (3*60) - -/** 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. */ -const char * -rep_hist_get_router_stability_doc(time_t now) -{ - 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; -} - /** 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. */ @@ -1051,7 +931,7 @@ correct_time(time_t t, time_t now, time_t stored_at, time_t started_measuring) return 0; else { long run_length = stored_at - t; - t = now - run_length; + t = (time_t)(now - run_length); if (t < started_measuring) t = started_measuring; return t; @@ -1212,7 +1092,7 @@ rep_hist_load_mtbf_data(time_t now) 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; + latest_possible_start = (time_t)(hist->start_of_run - wrl); hist->weighted_run_length = wrl; hist->total_run_weights = trw; @@ -1251,9 +1131,7 @@ rep_hist_load_mtbf_data(time_t now) * totals? */ #define NUM_SECS_ROLLING_MEASURE 10 /** How large are the intervals for which we track and report bandwidth use? */ -/* XXXX Watch out! Before Tor 0.2.2.21-alpha, using any other value here would - * generate an unparseable state file. */ -#define NUM_SECS_BW_SUM_INTERVAL (15*60) +#define NUM_SECS_BW_SUM_INTERVAL (4*60*60) /** How far in the past do we remember and publish bandwidth use? */ #define NUM_SECS_BW_SUM_IS_VALID (24*60*60) /** How many bandwidth usage intervals do we remember? (derived) */ @@ -1690,7 +1568,7 @@ rep_hist_load_bwhist_state_section(bw_array_t *b, time_t start; uint64_t v, mv; - int i,ok,ok_m; + int i,ok,ok_m = 0; int have_maxima = s_maxima && s_values && (smartlist_len(s_values) == smartlist_len(s_maxima)); @@ -1862,22 +1740,20 @@ rep_hist_note_used_port(time_t now, uint16_t port) add_predicted_port(now, port); } -/** 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 PREDICTED_CIRCS_RELEVANCE_TIME (60*60) - /** Return a newly allocated pointer to a list of uint16_t * for ports that * are likely to be asked for in the near future. */ smartlist_t * rep_hist_get_predicted_ports(time_t now) { + int predicted_circs_relevance_time; smartlist_t *out = smartlist_new(); tor_assert(predicted_ports_list); + predicted_circs_relevance_time = get_options()->PredictedPortsRelevanceTime; /* clean out obsolete entries */ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) { - if (pp->time + PREDICTED_CIRCS_RELEVANCE_TIME < now) { + 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); @@ -1944,14 +1820,17 @@ int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int *need_capacity) { + int predicted_circs_relevance_time; + predicted_circs_relevance_time = get_options()->PredictedPortsRelevanceTime; + 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) + if (predicted_internal_time + predicted_circs_relevance_time < now) return 0; /* too long ago */ - if (predicted_internal_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now) + if (predicted_internal_uptime_time + predicted_circs_relevance_time >= now) *need_uptime = 1; // Always predict that we need capacity. *need_capacity = 1; @@ -1963,8 +1842,11 @@ rep_hist_get_predicted_internal(time_t now, int *need_uptime, int any_predicted_circuits(time_t now) { + int predicted_circs_relevance_time; + predicted_circs_relevance_time = get_options()->PredictedPortsRelevanceTime; + return smartlist_len(predicted_ports_list) || - predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now; + predicted_internal_time + predicted_circs_relevance_time >= now; } /** Return 1 if we have no need for circuits currently, else return 0. */ @@ -2114,12 +1996,9 @@ void rep_hist_exit_stats_init(time_t now) { start_of_exit_stats_interval = now; - exit_bytes_read = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint64_t)); - exit_bytes_written = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint64_t)); - exit_streams = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint32_t)); + exit_bytes_read = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t)); + exit_bytes_written = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t)); + exit_streams = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint32_t)); } /** Reset counters for exit port statistics. */ @@ -2313,7 +2192,7 @@ rep_hist_format_exit_stats(time_t now) time_t rep_hist_exit_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_exit_stats_interval) return 0; /* Not initialized. */ @@ -2329,19 +2208,12 @@ rep_hist_exit_stats_write(time_t now) 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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "exit-stats", str, "exit port statistics"); } - 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; } @@ -2434,7 +2306,7 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval) return; start_of_interval = (circ->timestamp_created.tv_sec > start_of_buffer_stats_interval) ? - circ->timestamp_created.tv_sec : + (time_t)circ->timestamp_created.tv_sec : start_of_buffer_stats_interval; interval_length = (int) (end_of_interval - start_of_interval); if (interval_length <= 0) @@ -2597,8 +2469,7 @@ rep_hist_format_buffer_stats(time_t now) time_t rep_hist_buffer_stats_write(time_t now) { - circuit_t *circ; - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_buffer_stats_interval) return 0; /* Not initialized. */ @@ -2606,9 +2477,10 @@ rep_hist_buffer_stats_write(time_t now) goto done; /* Not ready to write */ /* Add open circuits to the history. */ - for (circ = circuit_get_global_list_(); circ; circ = circ->next) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { rep_hist_buffer_stats_add_circ(circ, now); } + SMARTLIST_FOREACH_END(circ); /* Generate history string. */ str = rep_hist_format_buffer_stats(now); @@ -2617,19 +2489,12 @@ rep_hist_buffer_stats_write(time_t now) 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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "buffer-stats", str, "buffer statistics"); } - 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; } @@ -2702,7 +2567,7 @@ rep_hist_format_desc_stats(time_t now) size = digestmap_size(served_descs); if (size > 0) { - vals = tor_malloc(size * sizeof(int)); + vals = tor_calloc(size, sizeof(int)); for (iter = digestmap_iter_init(served_descs); !digestmap_iter_done(iter); iter = digestmap_iter_next(served_descs, iter)) { @@ -2741,7 +2606,7 @@ rep_hist_format_desc_stats(time_t now) time_t rep_hist_desc_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *filename = NULL, *str = NULL; if (!start_of_served_descs_stats_interval) return 0; /* We're not collecting stats. */ @@ -2751,10 +2616,8 @@ rep_hist_desc_stats_write(time_t now) 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; + if (check_or_create_data_subdir("stats") < 0) { + goto done; } filename = get_datadir_fname2("stats", "served-desc-stats"); if (append_bytes_to_file(filename, str, strlen(str), 0) < 0) @@ -2763,7 +2626,6 @@ rep_hist_desc_stats_write(time_t now) 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; @@ -2860,8 +2722,8 @@ 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); +HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, + bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_) /* DOCDOC bidi_map_free */ static void @@ -2981,7 +2843,7 @@ rep_hist_format_conn_stats(time_t now) time_t rep_hist_conn_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_conn_stats_interval) return 0; /* Not initialized. */ @@ -2995,28 +2857,21 @@ rep_hist_conn_stats_write(time_t now) 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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "conn-stats", str, "connection statistics"); } - 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; } /** Internal statistics to track how many requests of each type of - * handshake we've received, and how many we've completed. Useful for - * seeing trends in cpu load. + * handshake we've received, and how many we've assigned to cpuworkers. + * Useful for seeing trends in cpu load. * @{ */ -static int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; -static int onion_handshakes_completed[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; +STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; +STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; /**@}*/ /** A new onionskin (using the <b>type</b> handshake) has arrived. */ @@ -3030,10 +2885,10 @@ rep_hist_note_circuit_handshake_requested(uint16_t type) /** We've sent an onionskin (using the <b>type</b> handshake) to a * cpuworker. */ void -rep_hist_note_circuit_handshake_completed(uint16_t type) +rep_hist_note_circuit_handshake_assigned(uint16_t type) { if (type <= MAX_ONION_HANDSHAKE_TYPE) - onion_handshakes_completed[type]++; + onion_handshakes_assigned[type]++; } /** Log our onionskin statistics since the last time we were called. */ @@ -3041,31 +2896,289 @@ void rep_hist_log_circuit_handshake_stats(time_t now) { (void)now; - log_notice(LD_HIST, "Circuit handshake stats since last time: " + log_notice(LD_HEARTBEAT, "Circuit handshake stats since last time: " "%d/%d TAP, %d/%d NTor.", - onion_handshakes_completed[ONION_HANDSHAKE_TYPE_TAP], + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP], - onion_handshakes_completed[ONION_HANDSHAKE_TYPE_NTOR], + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]); - memset(onion_handshakes_completed, 0, sizeof(onion_handshakes_completed)); + memset(onion_handshakes_assigned, 0, sizeof(onion_handshakes_assigned)); memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested)); } +/* Hidden service statistics section */ + +/** Start of the current hidden service stats interval or 0 if we're + * not collecting hidden service statistics. */ +static time_t start_of_hs_stats_interval; + +/** Carries the various hidden service statistics, and any other + * information needed. */ +typedef struct hs_stats_t { + /** How many relay cells have we seen as rendezvous points? */ + int64_t rp_relay_cells_seen; + + /** Set of unique public key digests we've seen this stat period + * (could also be implemented as sorted smartlist). */ + digestmap_t *onions_seen_this_period; +} hs_stats_t; + +/** Our statistics structure singleton. */ +static hs_stats_t *hs_stats = NULL; + +/** Allocate, initialize and return an hs_stats_t structure. */ +static hs_stats_t * +hs_stats_new(void) +{ + hs_stats_t * hs_stats = tor_malloc_zero(sizeof(hs_stats_t)); + hs_stats->onions_seen_this_period = digestmap_new(); + + return hs_stats; +} + +/** Free an hs_stats_t structure. */ +static void +hs_stats_free(hs_stats_t *hs_stats) +{ + if (!hs_stats) { + return; + } + + digestmap_free(hs_stats->onions_seen_this_period, NULL); + tor_free(hs_stats); +} + +/** Initialize hidden service statistics. */ +void +rep_hist_hs_stats_init(time_t now) +{ + if (!hs_stats) { + hs_stats = hs_stats_new(); + } + + start_of_hs_stats_interval = now; +} + +/** Clear history of hidden service statistics and set the measurement + * interval start to <b>now</b>. */ +static void +rep_hist_reset_hs_stats(time_t now) +{ + if (!hs_stats) { + hs_stats = hs_stats_new(); + } + + hs_stats->rp_relay_cells_seen = 0; + + digestmap_free(hs_stats->onions_seen_this_period, NULL); + hs_stats->onions_seen_this_period = digestmap_new(); + + start_of_hs_stats_interval = now; +} + +/** Stop collecting hidden service stats in a way that we can re-start + * doing so in rep_hist_buffer_stats_init(). */ +void +rep_hist_hs_stats_term(void) +{ + rep_hist_reset_hs_stats(0); +} + +/** We saw a new HS relay cell, Count it! */ +void +rep_hist_seen_new_rp_cell(void) +{ + if (!hs_stats) { + return; // We're not collecting stats + } + + hs_stats->rp_relay_cells_seen++; +} + +/** As HSDirs, we saw another hidden service with public key + * <b>pubkey</b>. Check whether we have counted it before, if not + * count it now! */ +void +rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey) +{ + char pubkey_hash[DIGEST_LEN]; + + if (!hs_stats) { + return; // We're not collecting stats + } + + /* Get the digest of the pubkey which will be used to detect whether + we've seen this hidden service before or not. */ + if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) { + /* This fail should not happen; key has been validated by + descriptor parsing code first. */ + return; + } + + /* Check if this is the first time we've seen this hidden + service. If it is, count it as new. */ + if (!digestmap_get(hs_stats->onions_seen_this_period, + pubkey_hash)) { + digestmap_set(hs_stats->onions_seen_this_period, + pubkey_hash, (void*)(uintptr_t)1); + } +} + +/* The number of cells that are supposed to be hidden from the adversary + * by adding noise from the Laplace distribution. This value, divided by + * EPSILON, is Laplace parameter b. */ +#define REND_CELLS_DELTA_F 2048 +/* Security parameter for obfuscating number of cells with a value between + * 0 and 1. Smaller values obfuscate observations more, but at the same + * time make statistics less usable. */ +#define REND_CELLS_EPSILON 0.3 +/* The number of cells that are supposed to be hidden from the adversary + * by rounding up to the next multiple of this number. */ +#define REND_CELLS_BIN_SIZE 1024 +/* The number of service identities that are supposed to be hidden from + * the adversary by adding noise from the Laplace distribution. This + * value, divided by EPSILON, is Laplace parameter b. */ +#define ONIONS_SEEN_DELTA_F 8 +/* Security parameter for obfuscating number of service identities with a + * value between 0 and 1. Smaller values obfuscate observations more, but + * at the same time make statistics less usable. */ +#define ONIONS_SEEN_EPSILON 0.3 +/* The number of service identities that are supposed to be hidden from + * the adversary by rounding up to the next multiple of this number. */ +#define ONIONS_SEEN_BIN_SIZE 8 + +/** Allocate and return a string containing hidden service stats that + * are meant to be placed in the extra-info descriptor. */ +static char * +rep_hist_format_hs_stats(time_t now) +{ + char t[ISO_TIME_LEN+1]; + char *hs_stats_string; + int64_t obfuscated_cells_seen; + int64_t obfuscated_onions_seen; + + obfuscated_cells_seen = round_int64_to_next_multiple_of( + hs_stats->rp_relay_cells_seen, + REND_CELLS_BIN_SIZE); + obfuscated_cells_seen = add_laplace_noise(obfuscated_cells_seen, + crypto_rand_double(), + REND_CELLS_DELTA_F, REND_CELLS_EPSILON); + obfuscated_onions_seen = round_int64_to_next_multiple_of(digestmap_size( + hs_stats->onions_seen_this_period), + ONIONS_SEEN_BIN_SIZE); + obfuscated_onions_seen = add_laplace_noise(obfuscated_onions_seen, + crypto_rand_double(), ONIONS_SEEN_DELTA_F, + ONIONS_SEEN_EPSILON); + + format_iso_time(t, now); + tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n" + "hidserv-rend-relayed-cells "I64_FORMAT" delta_f=%d " + "epsilon=%.2f bin_size=%d\n" + "hidserv-dir-onions-seen "I64_FORMAT" delta_f=%d " + "epsilon=%.2f bin_size=%d\n", + t, (unsigned) (now - start_of_hs_stats_interval), + I64_PRINTF_ARG(obfuscated_cells_seen), REND_CELLS_DELTA_F, + REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE, + I64_PRINTF_ARG(obfuscated_onions_seen), + ONIONS_SEEN_DELTA_F, + ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE); + + return hs_stats_string; +} + +/** If 24 hours have passed since the beginning of the current HS + * stats period, write buffer stats to $DATADIR/stats/hidserv-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. */ +time_t +rep_hist_hs_stats_write(time_t now) +{ + char *str = NULL; + + if (!start_of_hs_stats_interval) { + return 0; /* Not initialized. */ + } + + if (start_of_hs_stats_interval + WRITE_STATS_INTERVAL > now) { + goto done; /* Not ready to write */ + } + + /* Generate history string. */ + str = rep_hist_format_hs_stats(now); + + /* Reset HS history. */ + rep_hist_reset_hs_stats(now); + + /* Try to write to disk. */ + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "hidserv-stats", str, + "hidden service stats"); + } + + done: + tor_free(str); + return start_of_hs_stats_interval + WRITE_STATS_INTERVAL; +} + +#define MAX_LINK_PROTO_TO_LOG 4 +static uint64_t link_proto_count[MAX_LINK_PROTO_TO_LOG+1][2]; + +/** Note that we negotiated link protocol version <b>link_proto</b>, on + * a connection that started here iff <b>started_here</b> is true. + */ +void +rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here) +{ + started_here = !!started_here; /* force to 0 or 1 */ + if (link_proto > MAX_LINK_PROTO_TO_LOG) { + log_warn(LD_BUG, "Can't log link protocol %u", link_proto); + return; + } + + link_proto_count[link_proto][started_here]++; +} + +/** Log a heartbeat message explaining how many connections of each link + * protocol version we have used. + */ +void +rep_hist_log_link_protocol_counts(void) +{ + log_notice(LD_HEARTBEAT, + "Since startup, we have initiated " + U64_FORMAT" v1 connections, " + U64_FORMAT" v2 connections, " + U64_FORMAT" v3 connections, and " + U64_FORMAT" v4 connections; and received " + U64_FORMAT" v1 connections, " + U64_FORMAT" v2 connections, " + U64_FORMAT" v3 connections, and " + U64_FORMAT" v4 connections.", + U64_PRINTF_ARG(link_proto_count[1][1]), + U64_PRINTF_ARG(link_proto_count[2][1]), + U64_PRINTF_ARG(link_proto_count[3][1]), + U64_PRINTF_ARG(link_proto_count[4][1]), + U64_PRINTF_ARG(link_proto_count[1][0]), + U64_PRINTF_ARG(link_proto_count[2][0]), + U64_PRINTF_ARG(link_proto_count[3][0]), + U64_PRINTF_ARG(link_proto_count[4][0])); +} + /** Free all storage held by the OR/link history caches, by the * bandwidth history arrays, by the port history, or by statistics . */ void rep_hist_free_all(void) { + hs_stats_free(hs_stats); digestmap_free(history_map, free_or_history); tor_free(read_array); tor_free(write_array); tor_free(dir_read_array); tor_free(dir_write_array); - tor_free(last_stability_doc); tor_free(exit_bytes_read); tor_free(exit_bytes_written); tor_free(exit_streams); - built_last_stability_doc_at = 0; predicted_ports_free(); bidi_map_free(); |