Tor  0.4.3.0-alpha-dev
rephist.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2  * Copyright (c) 2007-2020, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
4 
5 /**
6  * \file rephist.c
7  * \brief Basic history and performance-tracking functionality.
8  *
9  * Basic history and performance-tracking functionality to remember
10  * which servers have worked in the past, how much bandwidth we've
11  * been using, which ports we tend to want, and so on; further,
12  * exit port statistics, cell statistics, and connection statistics.
13  *
14  * The history and information tracked in this module could sensibly be
15  * divided into several categories:
16  *
17  * <ul><li>Statistics used by authorities to remember the uptime and
18  * stability information about various relays, including "uptime",
19  * "weighted fractional uptime" and "mean time between failures".
20  *
21  * <li>Bandwidth usage history, used by relays to self-report how much
22  * bandwidth they've used for different purposes over last day or so,
23  * in order to generate the {dirreq-,}{read,write}-history lines in
24  * that they publish.
25  *
26  * <li>Predicted ports, used by clients to remember how long it's been
27  * since they opened an exit connection to each given target
28  * port. Clients use this information in order to try to keep circuits
29  * open to exit nodes that can connect to the ports that they care
30  * about. (The predicted ports mechanism also handles predicted circuit
31  * usage that _isn't_ port-specific, such as resolves, internal circuits,
32  * and so on.)
33  *
34  * <li>Public key operation counters, for tracking how many times we've
35  * done each public key operation. (This is unmaintained and we should
36  * remove it.)
37  *
38  * <li>Exit statistics by port, used by exits to keep track of the
39  * number of streams and bytes they've served at each exit port, so they
40  * can generate their exit-kibibytes-{read,written} and
41  * exit-streams-opened statistics.
42  *
43  * <li>Circuit stats, used by relays instances to tract circuit
44  * queue fullness and delay over time, and generate cell-processed-cells,
45  * cell-queued-cells, cell-time-in-queue, and cell-circuits-per-decile
46  * statistics.
47  *
48  * <li>Descriptor serving statistics, used by directory caches to track
49  * how many descriptors they've served.
50  *
51  * <li>Connection statistics, used by relays to track one-way and
52  * bidirectional connections.
53  *
54  * <li>Onion handshake statistics, used by relays to count how many
55  * TAP and ntor handshakes they've handled.
56  *
57  * <li>Hidden service statistics, used by relays to count rendezvous
58  * traffic and HSDir-stored descriptors.
59  *
60  * <li>Link protocol statistics, used by relays to count how many times
61  * each link protocol has been used.
62  *
63  * </ul>
64  *
65  * The entry points for this module are scattered throughout the
66  * codebase. Sending data, receiving data, connecting to a relay,
67  * losing a connection to a relay, and so on can all trigger a change in
68  * our current stats. Relays also invoke this module in order to
69  * extract their statistics when building routerinfo and extrainfo
70  * objects in router.c.
71  *
72  * TODO: This module should be broken up.
73  *
74  * (The "rephist" name originally stood for "reputation and history". )
75  **/
76 
77 #define REPHIST_PRIVATE
78 #include "core/or/or.h"
79 #include "app/config/config.h"
80 #include "app/config/statefile.h"
81 #include "core/or/circuitlist.h"
82 #include "core/or/connection_or.h"
88 #include "feature/stats/rephist.h"
89 #include "lib/container/order.h"
91 #include "lib/math/laplace.h"
92 
94 #include "core/or/or_circuit_st.h"
95 #include "app/config/or_state_st.h"
96 
97 #ifdef HAVE_FCNTL_H
98 #include <fcntl.h>
99 #endif
100 
101 static void bw_arrays_init(void);
102 
103 /** Total number of bytes currently allocated in fields used by rephist.c. */
105 /** Number of or_history_t objects currently allocated. */
106 uint32_t rephist_total_num=0;
107 
108 /** If the total weighted run count of all runs for a router ever falls
109  * below this amount, the router can be treated as having 0 MTBF. */
110 #define STABILITY_EPSILON 0.0001
111 /** Value by which to discount all old intervals for MTBF purposes. This
112  * is compounded every STABILITY_INTERVAL. */
113 #define STABILITY_ALPHA 0.95
114 /** Interval at which to discount all old intervals for MTBF purposes. */
115 #define STABILITY_INTERVAL (12*60*60)
116 /* (This combination of ALPHA, INTERVAL, and EPSILON makes it so that an
117  * interval that just ended counts twice as much as one that ended a week ago,
118  * 20X as much as one that ended a month ago, and routers that have had no
119  * uptime data for about half a year will get forgotten.) */
120 
121 /** History of an OR. */
122 typedef struct or_history_t {
123  /** When did we start tracking this OR? */
124  time_t since;
125  /** When did we most recently note a change to this OR? */
126  time_t changed;
127 
128  /** The address at which we most recently connected to this OR
129  * successfully. */
131 
132  /** The port at which we most recently connected to this OR successfully */
134 
135  /* === For MTBF tracking: */
136  /** Weighted sum total of all times that this router has been online.
137  */
138  unsigned long weighted_run_length;
139  /** If the router is now online (according to stability-checking rules),
140  * when did it come online? */
141  time_t start_of_run;
142  /** Sum of weights for runs in weighted_run_length. */
144  /* === For fractional uptime tracking: */
145  time_t start_of_downtime;
146  unsigned long weighted_uptime;
147  unsigned long total_weighted_time;
148 } or_history_t;
149 
150 /**
151  * This structure holds accounting needed to calculate the padding overhead.
152  */
153 typedef struct padding_counts_t {
154  /** Total number of cells we have received, including padding */
155  uint64_t read_cell_count;
156  /** Total number of cells we have sent, including padding */
158  /** Total number of CELL_PADDING cells we have received */
160  /** Total number of CELL_PADDING cells we have sent */
162  /** Total number of read cells on padding-enabled conns */
164  /** Total number of sent cells on padding-enabled conns */
166  /** Total number of read CELL_PADDING cells on padding-enabled cons */
168  /** Total number of sent CELL_PADDING cells on padding-enabled cons */
170  /** Total number of RELAY_DROP cells we have received */
172  /** Total number of RELAY_DROP cells we have sent */
174  /** The maximum number of padding timers we've seen in 24 hours */
176  /** When did we first copy padding_current into padding_published? */
177  char first_published_at[ISO_TIME_LEN+1];
179 
180 /** Holds the current values of our padding statistics.
181  * It is not published until it is transferred to padding_published. */
183 
184 /** Remains fixed for a 24 hour period, and then is replaced
185  * by a redacted copy of padding_current */
187 
188 /** When did we last multiply all routers' weighted_run_length and
189  * total_run_weights by STABILITY_ALPHA? */
190 static time_t stability_last_downrated = 0;
191 
192 /** */
193 static time_t started_tracking_stability = 0;
194 
195 /** Map from hex OR identity digest to or_history_t. */
196 static digestmap_t *history_map = NULL;
197 
198 /** Return the or_history_t for the OR with identity digest <b>id</b>,
199  * creating it if necessary. */
200 static or_history_t *
201 get_or_history(const char* id)
202 {
203  or_history_t *hist;
204 
205  if (tor_digest_is_zero(id))
206  return NULL;
207 
208  hist = digestmap_get(history_map, id);
209  if (!hist) {
210  hist = tor_malloc_zero(sizeof(or_history_t));
213  hist->since = hist->changed = time(NULL);
215  digestmap_set(history_map, id, hist);
216  }
217  return hist;
218 }
219 
220 /** Helper: free storage held by a single OR history entry. */
221 static void
222 free_or_history(void *_hist)
223 {
224  or_history_t *hist = _hist;
227  tor_free(hist);
228 }
229 
230 /** Initialize the static data structures for tracking history. */
231 void
233 {
234  history_map = digestmap_new();
235  bw_arrays_init();
236 }
237 
238 /** We have just decided that this router with identity digest <b>id</b> is
239  * reachable, meaning we will give it a "Running" flag for the next while. */
240 void
241 rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
242  const uint16_t at_port, time_t when)
243 {
244  or_history_t *hist = get_or_history(id);
245  int was_in_run = 1;
246  char tbuf[ISO_TIME_LEN+1];
247  int addr_changed, port_changed;
248 
249  tor_assert(hist);
250  tor_assert((!at_addr && !at_port) || (at_addr && at_port));
251 
252  addr_changed = at_addr && !tor_addr_is_null(&hist->last_reached_addr) &&
253  tor_addr_compare(at_addr, &hist->last_reached_addr, CMP_EXACT) != 0;
254  port_changed = at_port && hist->last_reached_port &&
255  at_port != hist->last_reached_port;
256 
257  if (!started_tracking_stability)
258  started_tracking_stability = time(NULL);
259  if (!hist->start_of_run) {
260  hist->start_of_run = when;
261  was_in_run = 0;
262  }
263  if (hist->start_of_downtime) {
264  long down_length;
265 
266  format_local_iso_time(tbuf, hist->start_of_downtime);
267  log_info(LD_HIST, "Router %s is now Running; it had been down since %s.",
268  hex_str(id, DIGEST_LEN), tbuf);
269  if (was_in_run)
270  log_info(LD_HIST, " (Paradoxically, it was already Running too.)");
271 
272  down_length = when - hist->start_of_downtime;
273  hist->total_weighted_time += down_length;
274  hist->start_of_downtime = 0;
275  } else if (addr_changed || port_changed) {
276  /* If we're reachable, but the address changed, treat this as some
277  * downtime. */
278  int penalty = get_options()->TestingTorNetwork ? 240 : 3600;
279  networkstatus_t *ns;
280 
281  if ((ns = networkstatus_get_latest_consensus())) {
282  int fresh_interval = (int)(ns->fresh_until - ns->valid_after);
283  int live_interval = (int)(ns->valid_until - ns->valid_after);
284  /* on average, a descriptor addr change takes .5 intervals to make it
285  * into a consensus, and half a liveness period to make it to
286  * clients. */
287  penalty = (int)(fresh_interval + live_interval) / 2;
288  }
289  format_local_iso_time(tbuf, hist->start_of_run);
290  log_info(LD_HIST,"Router %s still seems Running, but its address appears "
291  "to have changed since the last time it was reachable. I'm "
292  "going to treat it as having been down for %d seconds",
293  hex_str(id, DIGEST_LEN), penalty);
294  rep_hist_note_router_unreachable(id, when-penalty);
295  rep_hist_note_router_reachable(id, NULL, 0, when);
296  } else {
297  format_local_iso_time(tbuf, hist->start_of_run);
298  if (was_in_run)
299  log_debug(LD_HIST, "Router %s is still Running; it has been Running "
300  "since %s", hex_str(id, DIGEST_LEN), tbuf);
301  else
302  log_info(LD_HIST,"Router %s is now Running; it was previously untracked",
303  hex_str(id, DIGEST_LEN));
304  }
305  if (at_addr)
306  tor_addr_copy(&hist->last_reached_addr, at_addr);
307  if (at_port)
308  hist->last_reached_port = at_port;
309 }
310 
311 /** We have just decided that this router is unreachable, meaning
312  * we are taking away its "Running" flag. */
313 void
314 rep_hist_note_router_unreachable(const char *id, time_t when)
315 {
316  or_history_t *hist = get_or_history(id);
317  char tbuf[ISO_TIME_LEN+1];
318  int was_running = 0;
319  if (!started_tracking_stability)
320  started_tracking_stability = time(NULL);
321 
322  tor_assert(hist);
323  if (hist->start_of_run) {
324  /*XXXX We could treat failed connections differently from failed
325  * connect attempts. */
326  long run_length = when - hist->start_of_run;
327  format_local_iso_time(tbuf, hist->start_of_run);
328 
329  hist->total_run_weights += 1.0;
330  hist->start_of_run = 0;
331  if (run_length < 0) {
332  unsigned long penalty = -run_length;
333 #define SUBTRACT_CLAMPED(var, penalty) \
334  do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0)
335 
336  SUBTRACT_CLAMPED(hist->weighted_run_length, penalty);
337  SUBTRACT_CLAMPED(hist->weighted_uptime, penalty);
338  } else {
339  hist->weighted_run_length += run_length;
340  hist->weighted_uptime += run_length;
341  hist->total_weighted_time += run_length;
342  }
343  was_running = 1;
344  log_info(LD_HIST, "Router %s is now non-Running: it had previously been "
345  "Running since %s. Its total weighted uptime is %lu/%lu.",
346  hex_str(id, DIGEST_LEN), tbuf, hist->weighted_uptime,
347  hist->total_weighted_time);
348  }
349  if (!hist->start_of_downtime) {
350  hist->start_of_downtime = when;
351 
352  if (!was_running)
353  log_info(LD_HIST, "Router %s is now non-Running; it was previously "
354  "untracked.", hex_str(id, DIGEST_LEN));
355  } else {
356  if (!was_running) {
357  format_local_iso_time(tbuf, hist->start_of_downtime);
358 
359  log_info(LD_HIST, "Router %s is still non-Running; it has been "
360  "non-Running since %s.", hex_str(id, DIGEST_LEN), tbuf);
361  }
362  }
363 }
364 
365 /** Mark a router with ID <b>id</b> as non-Running, and retroactively declare
366  * that it has never been running: give it no stability and no WFU. */
367 void
368 rep_hist_make_router_pessimal(const char *id, time_t when)
369 {
370  or_history_t *hist = get_or_history(id);
371  tor_assert(hist);
372 
374 
375  hist->weighted_run_length = 0;
376  hist->weighted_uptime = 0;
377 }
378 
379 /** Helper: Discount all old MTBF data, if it is time to do so. Return
380  * the time at which we should next discount MTBF data. */
381 time_t
383 {
384  digestmap_iter_t *orhist_it;
385  const char *digest1;
386  or_history_t *hist;
387  void *hist_p;
388  double alpha = 1.0;
389 
390  if (!history_map)
391  history_map = digestmap_new();
396 
397  /* Okay, we should downrate the data. By how much? */
400  alpha *= STABILITY_ALPHA;
401  }
402 
403  log_info(LD_HIST, "Discounting all old stability info by a factor of %f",
404  alpha);
405 
406  /* Multiply every w_r_l, t_r_w pair by alpha. */
407  for (orhist_it = digestmap_iter_init(history_map);
408  !digestmap_iter_done(orhist_it);
409  orhist_it = digestmap_iter_next(history_map,orhist_it)) {
410  digestmap_iter_get(orhist_it, &digest1, &hist_p);
411  hist = hist_p;
412 
413  hist->weighted_run_length =
414  (unsigned long)(hist->weighted_run_length * alpha);
415  hist->total_run_weights *= alpha;
416 
417  hist->weighted_uptime = (unsigned long)(hist->weighted_uptime * alpha);
418  hist->total_weighted_time = (unsigned long)
419  (hist->total_weighted_time * alpha);
420  }
421 
423 }
424 
425 /** Helper: Return the weighted MTBF of the router with history <b>hist</b>. */
426 static double
427 get_stability(or_history_t *hist, time_t when)
428 {
429  long total = hist->weighted_run_length;
430  double total_weights = hist->total_run_weights;
431 
432  if (hist->start_of_run) {
433  /* We're currently in a run. Let total and total_weights hold the values
434  * they would hold if the current run were to end now. */
435  total += (when-hist->start_of_run);
436  total_weights += 1.0;
437  }
438  if (total_weights < STABILITY_EPSILON) {
439  /* Round down to zero, and avoid divide-by-zero. */
440  return 0.0;
441  }
442 
443  return total / total_weights;
444 }
445 
446 /** Return the total amount of time we've been observing, with each run of
447  * time downrated by the appropriate factor. */
448 static long
450 {
451  long total = hist->total_weighted_time;
452  if (hist->start_of_run) {
453  total += (when - hist->start_of_run);
454  } else if (hist->start_of_downtime) {
455  total += (when - hist->start_of_downtime);
456  }
457  return total;
458 }
459 
460 /** Helper: Return the weighted percent-of-time-online of the router with
461  * history <b>hist</b>. */
462 static double
464 {
465  long total = hist->total_weighted_time;
466  long up = hist->weighted_uptime;
467 
468  if (hist->start_of_run) {
469  long run_length = (when - hist->start_of_run);
470  up += run_length;
471  total += run_length;
472  } else if (hist->start_of_downtime) {
473  total += (when - hist->start_of_downtime);
474  }
475 
476  if (!total) {
477  /* Avoid calling anybody's uptime infinity (which should be impossible if
478  * the code is working), or NaN (which can happen for any router we haven't
479  * observed up or down yet). */
480  return 0.0;
481  }
482 
483  return ((double) up) / total;
484 }
485 
486 /** Return how long the router whose identity digest is <b>id</b> has
487  * been reachable. Return 0 if the router is unknown or currently deemed
488  * unreachable. */
489 long
490 rep_hist_get_uptime(const char *id, time_t when)
491 {
492  or_history_t *hist = get_or_history(id);
493  if (!hist)
494  return 0;
495  if (!hist->start_of_run || when < hist->start_of_run)
496  return 0;
497  return when - hist->start_of_run;
498 }
499 
500 /** Return an estimated MTBF for the router whose identity digest is
501  * <b>id</b>. Return 0 if the router is unknown. */
502 double
503 rep_hist_get_stability(const char *id, time_t when)
504 {
505  or_history_t *hist = get_or_history(id);
506  if (!hist)
507  return 0.0;
508 
509  return get_stability(hist, when);
510 }
511 
512 /** Return an estimated percent-of-time-online for the router whose identity
513  * digest is <b>id</b>. Return 0 if the router is unknown. */
514 double
515 rep_hist_get_weighted_fractional_uptime(const char *id, time_t when)
516 {
517  or_history_t *hist = get_or_history(id);
518  if (!hist)
519  return 0.0;
520 
521  return get_weighted_fractional_uptime(hist, when);
522 }
523 
524 /** Return a number representing how long we've known about the router whose
525  * digest is <b>id</b>. Return 0 if the router is unknown.
526  *
527  * Be careful: this measure increases monotonically as we know the router for
528  * longer and longer, but it doesn't increase linearly.
529  */
530 long
531 rep_hist_get_weighted_time_known(const char *id, time_t when)
532 {
533  or_history_t *hist = get_or_history(id);
534  if (!hist)
535  return 0;
536 
537  return get_total_weighted_time(hist, when);
538 }
539 
540 /** Return true if we've been measuring MTBFs for long enough to
541  * pronounce on Stability. */
542 int
544 {
545  /* XXXX++ This doesn't do so well when we change our opinion
546  * as to whether we're tracking router stability. */
547  return started_tracking_stability < time(NULL) - 4*60*60;
548 }
549 
550 /** Log all the reliability data we have remembered, with the chosen
551  * severity.
552  */
553 void
554 rep_hist_dump_stats(time_t now, int severity)
555 {
556  digestmap_iter_t *orhist_it;
557  const char *name1, *digest1;
558  char hexdigest1[HEX_DIGEST_LEN+1];
559  or_history_t *or_history;
560  void *or_history_p;
561  const node_t *node;
562 
563  rep_history_clean(now - get_options()->RephistTrackTime);
564 
565  tor_log(severity, LD_HIST, "--------------- Dumping history information:");
566 
567  for (orhist_it = digestmap_iter_init(history_map);
568  !digestmap_iter_done(orhist_it);
569  orhist_it = digestmap_iter_next(history_map,orhist_it)) {
570  double s;
571  long stability;
572  digestmap_iter_get(orhist_it, &digest1, &or_history_p);
573  or_history = (or_history_t*) or_history_p;
574 
575  if ((node = node_get_by_id(digest1)) && node_get_nickname(node))
576  name1 = node_get_nickname(node);
577  else
578  name1 = "(unknown)";
579  base16_encode(hexdigest1, sizeof(hexdigest1), digest1, DIGEST_LEN);
580  s = get_stability(or_history, now);
581  stability = (long)s;
582  tor_log(severity, LD_HIST,
583  "OR %s [%s]: wmtbf %lu:%02lu:%02lu",
584  name1, hexdigest1,
585  stability/3600, (stability/60)%60, stability%60);
586  }
587 }
588 
589 /** Remove history info for routers/links that haven't changed since
590  * <b>before</b>.
591  */
592 void
593 rep_history_clean(time_t before)
594 {
595  int authority = authdir_mode(get_options());
596  or_history_t *or_history;
597  void *or_history_p;
598  digestmap_iter_t *orhist_it;
599  const char *d1;
600 
601  orhist_it = digestmap_iter_init(history_map);
602  while (!digestmap_iter_done(orhist_it)) {
603  int should_remove;
604  digestmap_iter_get(orhist_it, &d1, &or_history_p);
605  or_history = or_history_p;
606 
607  should_remove = authority ?
608  (or_history->total_run_weights < STABILITY_EPSILON &&
609  !or_history->start_of_run)
610  : (or_history->changed < before);
611  if (should_remove) {
612  orhist_it = digestmap_iter_next_rmv(history_map, orhist_it);
613  free_or_history(or_history);
614  continue;
615  }
616  orhist_it = digestmap_iter_next(history_map, orhist_it);
617  }
618 }
619 
620 /** Write MTBF data to disk. Return 0 on success, negative on failure.
621  *
622  * If <b>missing_means_down</b>, then if we're about to write an entry
623  * that is still considered up but isn't in our routerlist, consider it
624  * to be down. */
625 int
626 rep_hist_record_mtbf_data(time_t now, int missing_means_down)
627 {
628  char time_buf[ISO_TIME_LEN+1];
629 
630  digestmap_iter_t *orhist_it;
631  const char *digest;
632  void *or_history_p;
633  or_history_t *hist;
634  open_file_t *open_file = NULL;
635  FILE *f;
636 
637  {
638  char *filename = get_datadir_fname("router-stability");
639  f = start_writing_to_stdio_file(filename, OPEN_FLAGS_REPLACE|O_TEXT, 0600,
640  &open_file);
641  tor_free(filename);
642  if (!f)
643  return -1;
644  }
645 
646  /* File format is:
647  * FormatLine *KeywordLine Data
648  *
649  * FormatLine = "format 1" NL
650  * KeywordLine = Keyword SP Arguments NL
651  * Data = "data" NL *RouterMTBFLine "." NL
652  * RouterMTBFLine = Fingerprint SP WeightedRunLen SP
653  * TotalRunWeights [SP S=StartRunTime] NL
654  */
655 #define PUT(s) STMT_BEGIN if (fputs((s),f)<0) goto err; STMT_END
656 #define PRINTF(args) STMT_BEGIN if (fprintf args <0) goto err; STMT_END
657 
658  PUT("format 2\n");
659 
660  format_iso_time(time_buf, time(NULL));
661  PRINTF((f, "stored-at %s\n", time_buf));
662 
663  if (started_tracking_stability) {
664  format_iso_time(time_buf, started_tracking_stability);
665  PRINTF((f, "tracked-since %s\n", time_buf));
666  }
669  PRINTF((f, "last-downrated %s\n", time_buf));
670  }
671 
672  PUT("data\n");
673 
674  /* XXX Nick: now bridge auths record this for all routers too.
675  * Should we make them record it only for bridge routers? -RD
676  * Not for 0.2.0. -NM */
677  for (orhist_it = digestmap_iter_init(history_map);
678  !digestmap_iter_done(orhist_it);
679  orhist_it = digestmap_iter_next(history_map,orhist_it)) {
680  char dbuf[HEX_DIGEST_LEN+1];
681  const char *t = NULL;
682  digestmap_iter_get(orhist_it, &digest, &or_history_p);
683  hist = (or_history_t*) or_history_p;
684 
685  base16_encode(dbuf, sizeof(dbuf), digest, DIGEST_LEN);
686 
687  if (missing_means_down && hist->start_of_run &&
689  /* We think this relay is running, but it's not listed in our
690  * consensus. Somehow it fell out without telling us it went
691  * down. Complain and also correct it. */
692  log_info(LD_HIST,
693  "Relay '%s' is listed as up in rephist, but it's not in "
694  "our routerlist. Correcting.", dbuf);
696  }
697 
698  PRINTF((f, "R %s\n", dbuf));
699  if (hist->start_of_run > 0) {
700  format_iso_time(time_buf, hist->start_of_run);
701  t = time_buf;
702  }
703  PRINTF((f, "+MTBF %lu %.5f%s%s\n",
705  t ? " S=" : "", t ? t : ""));
706  t = NULL;
707  if (hist->start_of_downtime > 0) {
708  format_iso_time(time_buf, hist->start_of_downtime);
709  t = time_buf;
710  }
711  PRINTF((f, "+WFU %lu %lu%s%s\n",
712  hist->weighted_uptime, hist->total_weighted_time,
713  t ? " S=" : "", t ? t : ""));
714  }
715 
716  PUT(".\n");
717 
718 #undef PUT
719 #undef PRINTF
720 
721  return finish_writing_to_file(open_file);
722  err:
723  abort_writing_to_file(open_file);
724  return -1;
725 }
726 
727 /** Helper: return the first j >= i such that !strcmpstart(sl[j], prefix) and
728  * such that no line sl[k] with i <= k < j starts with "R ". Return -1 if no
729  * such line exists. */
730 static int
731 find_next_with(smartlist_t *sl, int i, const char *prefix)
732 {
733  for ( ; i < smartlist_len(sl); ++i) {
734  const char *line = smartlist_get(sl, i);
735  if (!strcmpstart(line, prefix))
736  return i;
737  if (!strcmpstart(line, "R "))
738  return -1;
739  }
740  return -1;
741 }
742 
743 /** How many bad times has parse_possibly_bad_iso_time() parsed? */
744 static int n_bogus_times = 0;
745 /** Parse the ISO-formatted time in <b>s</b> into *<b>time_out</b>, but
746  * round any pre-1970 date to Jan 1, 1970. */
747 static int
748 parse_possibly_bad_iso_time(const char *s, time_t *time_out)
749 {
750  int year;
751  char b[5];
752  strlcpy(b, s, sizeof(b));
753  b[4] = '\0';
754  year = (int)tor_parse_long(b, 10, 0, INT_MAX, NULL, NULL);
755  if (year < 1970) {
756  *time_out = 0;
757  ++n_bogus_times;
758  return 0;
759  } else
760  return parse_iso_time(s, time_out);
761 }
762 
763 /** We've read a time <b>t</b> from a file stored at <b>stored_at</b>, which
764  * says we started measuring at <b>started_measuring</b>. Return a new number
765  * that's about as much before <b>now</b> as <b>t</b> was before
766  * <b>stored_at</b>.
767  */
768 static inline time_t
769 correct_time(time_t t, time_t now, time_t stored_at, time_t started_measuring)
770 {
771  if (t < started_measuring - 24*60*60*365)
772  return 0;
773  else if (t < started_measuring)
774  return started_measuring;
775  else if (t > stored_at)
776  return 0;
777  else {
778  long run_length = stored_at - t;
779  t = (time_t)(now - run_length);
780  if (t < started_measuring)
781  t = started_measuring;
782  return t;
783  }
784 }
785 
786 /** Load MTBF data from disk. Returns 0 on success or recoverable error, -1
787  * on failure. */
788 int
790 {
791  /* XXXX won't handle being called while history is already populated. */
792  smartlist_t *lines;
793  const char *line = NULL;
794  int r=0, i;
795  time_t last_downrated = 0, stored_at = 0, tracked_since = 0;
796  time_t latest_possible_start = now;
797  long format = -1;
798 
799  {
800  char *filename = get_datadir_fname("router-stability");
801  char *d = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
802  tor_free(filename);
803  if (!d)
804  return -1;
805  lines = smartlist_new();
806  smartlist_split_string(lines, d, "\n", SPLIT_SKIP_SPACE, 0);
807  tor_free(d);
808  }
809 
810  {
811  const char *firstline;
812  if (smartlist_len(lines)>4) {
813  firstline = smartlist_get(lines, 0);
814  if (!strcmpstart(firstline, "format "))
815  format = tor_parse_long(firstline+strlen("format "),
816  10, -1, LONG_MAX, NULL, NULL);
817  }
818  }
819  if (format != 1 && format != 2) {
820  log_warn(LD_HIST,
821  "Unrecognized format in mtbf history file. Skipping.");
822  goto err;
823  }
824  for (i = 1; i < smartlist_len(lines); ++i) {
825  line = smartlist_get(lines, i);
826  if (!strcmp(line, "data"))
827  break;
828  if (!strcmpstart(line, "last-downrated ")) {
829  if (parse_iso_time(line+strlen("last-downrated "), &last_downrated)<0)
830  log_warn(LD_HIST,"Couldn't parse downrate time in mtbf "
831  "history file.");
832  }
833  if (!strcmpstart(line, "stored-at ")) {
834  if (parse_iso_time(line+strlen("stored-at "), &stored_at)<0)
835  log_warn(LD_HIST,"Couldn't parse stored time in mtbf "
836  "history file.");
837  }
838  if (!strcmpstart(line, "tracked-since ")) {
839  if (parse_iso_time(line+strlen("tracked-since "), &tracked_since)<0)
840  log_warn(LD_HIST,"Couldn't parse started-tracking time in mtbf "
841  "history file.");
842  }
843  }
844  if (last_downrated > now)
845  last_downrated = now;
846  if (tracked_since > now)
847  tracked_since = now;
848 
849  if (!stored_at) {
850  log_warn(LD_HIST, "No stored time recorded.");
851  goto err;
852  }
853 
854  if (line && !strcmp(line, "data"))
855  ++i;
856 
857  n_bogus_times = 0;
858 
859  for (; i < smartlist_len(lines); ++i) {
860  char digest[DIGEST_LEN];
861  char hexbuf[HEX_DIGEST_LEN+1];
862  char mtbf_timebuf[ISO_TIME_LEN+1];
863  char wfu_timebuf[ISO_TIME_LEN+1];
864  time_t start_of_run = 0;
865  time_t start_of_downtime = 0;
866  int have_mtbf = 0, have_wfu = 0;
867  long wrl = 0;
868  double trw = 0;
869  long wt_uptime = 0, total_wt_time = 0;
870  int n;
871  or_history_t *hist;
872  line = smartlist_get(lines, i);
873  if (!strcmp(line, "."))
874  break;
875 
876  mtbf_timebuf[0] = '\0';
877  wfu_timebuf[0] = '\0';
878 
879  if (format == 1) {
880  n = tor_sscanf(line, "%40s %ld %lf S=%10s %8s",
881  hexbuf, &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
882  if (n != 3 && n != 5) {
883  log_warn(LD_HIST, "Couldn't scan line %s", escaped(line));
884  continue;
885  }
886  have_mtbf = 1;
887  } else {
888  // format == 2.
889  int mtbf_idx, wfu_idx;
890  if (strcmpstart(line, "R ") || strlen(line) < 2+HEX_DIGEST_LEN)
891  continue;
892  strlcpy(hexbuf, line+2, sizeof(hexbuf));
893  mtbf_idx = find_next_with(lines, i+1, "+MTBF ");
894  wfu_idx = find_next_with(lines, i+1, "+WFU ");
895  if (mtbf_idx >= 0) {
896  const char *mtbfline = smartlist_get(lines, mtbf_idx);
897  n = tor_sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
898  &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
899  if (n == 2 || n == 4) {
900  have_mtbf = 1;
901  } else {
902  log_warn(LD_HIST, "Couldn't scan +MTBF line %s",
903  escaped(mtbfline));
904  }
905  }
906  if (wfu_idx >= 0) {
907  const char *wfuline = smartlist_get(lines, wfu_idx);
908  n = tor_sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
909  &wt_uptime, &total_wt_time,
910  wfu_timebuf, wfu_timebuf+11);
911  if (n == 2 || n == 4) {
912  have_wfu = 1;
913  } else {
914  log_warn(LD_HIST, "Couldn't scan +WFU line %s", escaped(wfuline));
915  }
916  }
917  if (wfu_idx > i)
918  i = wfu_idx;
919  if (mtbf_idx > i)
920  i = mtbf_idx;
921  }
922  if (base16_decode(digest, DIGEST_LEN,
923  hexbuf, HEX_DIGEST_LEN) != DIGEST_LEN) {
924  log_warn(LD_HIST, "Couldn't hex string %s", escaped(hexbuf));
925  continue;
926  }
927  hist = get_or_history(digest);
928  if (!hist)
929  continue;
930 
931  if (have_mtbf) {
932  if (mtbf_timebuf[0]) {
933  mtbf_timebuf[10] = ' ';
934  if (parse_possibly_bad_iso_time(mtbf_timebuf, &start_of_run)<0)
935  log_warn(LD_HIST, "Couldn't parse time %s",
936  escaped(mtbf_timebuf));
937  }
938  hist->start_of_run = correct_time(start_of_run, now, stored_at,
939  tracked_since);
940  if (hist->start_of_run < latest_possible_start + wrl)
941  latest_possible_start = (time_t)(hist->start_of_run - wrl);
942 
943  hist->weighted_run_length = wrl;
944  hist->total_run_weights = trw;
945  }
946  if (have_wfu) {
947  if (wfu_timebuf[0]) {
948  wfu_timebuf[10] = ' ';
949  if (parse_possibly_bad_iso_time(wfu_timebuf, &start_of_downtime)<0)
950  log_warn(LD_HIST, "Couldn't parse time %s", escaped(wfu_timebuf));
951  }
952  }
953  hist->start_of_downtime = correct_time(start_of_downtime, now, stored_at,
954  tracked_since);
955  hist->weighted_uptime = wt_uptime;
956  hist->total_weighted_time = total_wt_time;
957  }
958  if (strcmp(line, "."))
959  log_warn(LD_HIST, "Truncated MTBF file.");
960 
961  if (tracked_since < 86400*365) /* Recover from insanely early value. */
962  tracked_since = latest_possible_start;
963 
964  stability_last_downrated = last_downrated;
965  started_tracking_stability = tracked_since;
966 
967  goto done;
968  err:
969  r = -1;
970  done:
971  SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
972  smartlist_free(lines);
973  return r;
974 }
975 
976 /** For how many seconds do we keep track of individual per-second bandwidth
977  * totals? */
978 #define NUM_SECS_ROLLING_MEASURE 10
979 /** How large are the intervals for which we track and report bandwidth use? */
980 #define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
981 /** How far in the past do we remember and publish bandwidth use? */
982 #define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
983 /** How many bandwidth usage intervals do we remember? (derived) */
984 #define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
985 
986 /** Structure to track bandwidth use, and remember the maxima for a given
987  * time period.
988  */
989 struct bw_array_t {
990  /** Observation array: Total number of bytes transferred in each of the last
991  * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
993  int cur_obs_idx; /**< Current position in obs. */
994  time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
995  uint64_t total_obs; /**< Total for all members of obs except
996  * obs[cur_obs_idx] */
997  uint64_t max_total; /**< Largest value that total_obs has taken on in the
998  * current period. */
999  uint64_t total_in_period; /**< Total bytes transferred in the current
1000  * period. */
1001 
1002  /** When does the next period begin? */
1003  time_t next_period;
1004  /** Where in 'maxima' should the maximum bandwidth usage for the current
1005  * period be stored? */
1007  /** How many values in maxima/totals have been set ever? */
1009  /** Circular array of the maximum
1010  * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
1011  * NUM_TOTALS periods */
1012  uint64_t maxima[NUM_TOTALS];
1013  /** Circular array of the total bandwidth usage for the last NUM_TOTALS
1014  * periods */
1015  uint64_t totals[NUM_TOTALS];
1016 };
1017 
1018 /** Shift the current period of b forward by one. */
1019 STATIC void
1021 {
1022  /* Store total from current period. */
1023  b->totals[b->next_max_idx] = b->total_in_period;
1024  /* Store maximum from current period. */
1025  b->maxima[b->next_max_idx++] = b->max_total;
1026  /* Advance next_period and next_max_idx */
1028  if (b->next_max_idx == NUM_TOTALS)
1029  b->next_max_idx = 0;
1030  if (b->num_maxes_set < NUM_TOTALS)
1031  ++b->num_maxes_set;
1032  /* Reset max_total. */
1033  b->max_total = 0;
1034  /* Reset total_in_period. */
1035  b->total_in_period = 0;
1036 }
1037 
1038 /** Shift the current observation time of <b>b</b> forward by one second. */
1039 STATIC void
1041 {
1042  int nextidx;
1043  uint64_t total;
1044 
1045  /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
1046  * seconds; adjust max_total as needed.*/
1047  total = b->total_obs + b->obs[b->cur_obs_idx];
1048  if (total > b->max_total)
1049  b->max_total = total;
1050 
1051  nextidx = b->cur_obs_idx+1;
1052  if (nextidx == NUM_SECS_ROLLING_MEASURE)
1053  nextidx = 0;
1054 
1055  b->total_obs = total - b->obs[nextidx];
1056  b->obs[nextidx]=0;
1057  b->cur_obs_idx = nextidx;
1058 
1059  if (++b->cur_obs_time >= b->next_period)
1060  commit_max(b);
1061 }
1062 
1063 /** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second
1064  * <b>when</b>. */
1065 static inline void
1066 add_obs(bw_array_t *b, time_t when, uint64_t n)
1067 {
1068  if (when < b->cur_obs_time)
1069  return; /* Don't record data in the past. */
1070 
1071  /* If we're currently adding observations for an earlier second than
1072  * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
1073  * appropriate number of seconds, and do all the other housekeeping. */
1074  while (when > b->cur_obs_time) {
1075  /* Doing this one second at a time is potentially inefficient, if we start
1076  with a state file that is very old. Fortunately, it doesn't seem to
1077  show up in profiles, so we can just ignore it for now. */
1078  advance_obs(b);
1079  }
1080 
1081  b->obs[b->cur_obs_idx] += n;
1082  b->total_in_period += n;
1083 }
1084 
1085 /** Allocate, initialize, and return a new bw_array. */
1086 static bw_array_t *
1088 {
1089  bw_array_t *b;
1090  time_t start;
1091  b = tor_malloc_zero(sizeof(bw_array_t));
1092  rephist_total_alloc += sizeof(bw_array_t);
1093  start = time(NULL);
1094  b->cur_obs_time = start;
1096  return b;
1097 }
1098 
1099 #define bw_array_free(val) \
1100  FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
1101 
1102 /** Free storage held by bandwidth array <b>b</b>. */
1103 static void
1105 {
1106  if (!b) {
1107  return;
1108  }
1109 
1110  rephist_total_alloc -= sizeof(bw_array_t);
1111  tor_free(b);
1112 }
1113 
1114 /** Recent history of bandwidth observations for read operations. */
1115 static bw_array_t *read_array = NULL;
1116 /** Recent history of bandwidth observations for write operations. */
1118 /** Recent history of bandwidth observations for read operations for the
1119  directory protocol. */
1121 /** Recent history of bandwidth observations for write operations for the
1122  directory protocol. */
1124 
1125 /** Set up [dir-]read_array and [dir-]write_array, freeing them if they
1126  * already exist. */
1127 static void
1129 {
1130  bw_array_free(read_array);
1131  bw_array_free(write_array);
1132  bw_array_free(dir_read_array);
1133  bw_array_free(dir_write_array);
1134 
1139 }
1140 
1141 /** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
1142  *
1143  * Add num_bytes to the current running total for <b>when</b>.
1144  *
1145  * <b>when</b> can go back to time, but it's safe to ignore calls
1146  * earlier than the latest <b>when</b> you've heard of.
1147  */
1148 void
1149 rep_hist_note_bytes_written(uint64_t num_bytes, time_t when)
1150 {
1151 /* Maybe a circular array for recent seconds, and step to a new point
1152  * every time a new second shows up. Or simpler is to just to have
1153  * a normal array and push down each item every second; it's short.
1154  */
1155 /* When a new second has rolled over, compute the sum of the bytes we've
1156  * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
1157  * somewhere. See rep_hist_bandwidth_assess() below.
1158  */
1159  add_obs(write_array, when, num_bytes);
1160 }
1161 
1162 /** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
1163  * (like rep_hist_note_bytes_written() above)
1164  */
1165 void
1166 rep_hist_note_bytes_read(uint64_t num_bytes, time_t when)
1167 {
1168 /* if we're smart, we can make this func and the one above share code */
1169  add_obs(read_array, when, num_bytes);
1170 }
1171 
1172 /** Remember that we wrote <b>num_bytes</b> directory bytes in second
1173  * <b>when</b>. (like rep_hist_note_bytes_written() above)
1174  */
1175 void
1176 rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
1177 {
1178  add_obs(dir_write_array, when, num_bytes);
1179 }
1180 
1181 /** Remember that we read <b>num_bytes</b> directory bytes in second
1182  * <b>when</b>. (like rep_hist_note_bytes_written() above)
1183  */
1184 void
1185 rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
1186 {
1187  add_obs(dir_read_array, when, num_bytes);
1188 }
1189 
1190 /** Helper: Return the largest value in b->maxima. (This is equal to the
1191  * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
1192  * NUM_SECS_BW_SUM_IS_VALID seconds.)
1193  */
1194 STATIC uint64_t
1196 {
1197  int i;
1198  uint64_t max;
1199  max=0;
1200  for (i=0; i<NUM_TOTALS; ++i) {
1201  if (b->maxima[i]>max)
1202  max = b->maxima[i];
1203  }
1204  return max;
1205 }
1206 
1207 /** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
1208  * seconds. Find one sum for reading and one for writing. They don't have
1209  * to be at the same time.
1210  *
1211  * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
1212  */
1213 MOCK_IMPL(int,
1215 {
1216  uint64_t w,r;
1219  if (r>w)
1220  return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
1221  else
1222  return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
1223 }
1224 
1225 /** Print the bandwidth history of b (either [dir-]read_array or
1226  * [dir-]write_array) into the buffer pointed to by buf. The format is
1227  * simply comma separated numbers, from oldest to newest.
1228  *
1229  * It returns the number of bytes written.
1230  */
1231 static size_t
1232 rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
1233 {
1234  char *cp = buf;
1235  int i, n;
1236  const or_options_t *options = get_options();
1237  uint64_t cutoff;
1238 
1239  if (b->num_maxes_set <= b->next_max_idx) {
1240  /* We haven't been through the circular array yet; time starts at i=0.*/
1241  i = 0;
1242  } else {
1243  /* We've been around the array at least once. The next i to be
1244  overwritten is the oldest. */
1245  i = b->next_max_idx;
1246  }
1247 
1248  if (options->RelayBandwidthRate) {
1249  /* We don't want to report that we used more bandwidth than the max we're
1250  * willing to relay; otherwise everybody will know how much traffic
1251  * we used ourself. */
1252  cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
1253  } else {
1254  cutoff = UINT64_MAX;
1255  }
1256 
1257  for (n=0; n<b->num_maxes_set; ++n,++i) {
1258  uint64_t total;
1259  if (i >= NUM_TOTALS)
1260  i -= NUM_TOTALS;
1261  tor_assert(i < NUM_TOTALS);
1262  /* Round the bandwidth used down to the nearest 1k. */
1263  total = b->totals[i] & ~0x3ff;
1264  if (total > cutoff)
1265  total = cutoff;
1266 
1267  if (n==(b->num_maxes_set-1))
1268  tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
1269  else
1270  tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
1271  cp += strlen(cp);
1272  }
1273  return cp-buf;
1274 }
1275 
1276 /** Allocate and return lines for representing this server's bandwidth
1277  * history in its descriptor. We publish these lines in our extra-info
1278  * descriptor.
1279  */
1280 char *
1282 {
1283  char *buf, *cp;
1284  char t[ISO_TIME_LEN+1];
1285  int r;
1286  bw_array_t *b = NULL;
1287  const char *desc = NULL;
1288  size_t len;
1289 
1290  /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
1291 /* The n,n,n part above. Largest representation of a uint64_t is 20 chars
1292  * long, plus the comma. */
1293 #define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
1294  len = (67+MAX_HIST_VALUE_LEN)*4;
1295  buf = tor_malloc_zero(len);
1296  cp = buf;
1297  for (r=0;r<4;++r) {
1298  char tmp[MAX_HIST_VALUE_LEN];
1299  size_t slen;
1300  switch (r) {
1301  case 0:
1302  b = write_array;
1303  desc = "write-history";
1304  break;
1305  case 1:
1306  b = read_array;
1307  desc = "read-history";
1308  break;
1309  case 2:
1310  b = dir_write_array;
1311  desc = "dirreq-write-history";
1312  break;
1313  case 3:
1314  b = dir_read_array;
1315  desc = "dirreq-read-history";
1316  break;
1317  }
1318  tor_assert(b);
1319  slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
1320  /* If we don't have anything to write, skip to the next entry. */
1321  if (slen == 0)
1322  continue;
1324  tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
1325  desc, t, NUM_SECS_BW_SUM_INTERVAL);
1326  cp += strlen(cp);
1327  strlcat(cp, tmp, len-(cp-buf));
1328  cp += slen;
1329  strlcat(cp, "\n", len-(cp-buf));
1330  ++cp;
1331  }
1332  return buf;
1333 }
1334 
1335 /** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
1336  * entries of an or_state_t. Done before writing out a new state file. */
1337 static void
1339  const bw_array_t *b,
1340  smartlist_t **s_values,
1341  smartlist_t **s_maxima,
1342  time_t *s_begins,
1343  int *s_interval)
1344 {
1345  int i,j;
1346  uint64_t maxval;
1347 
1348  if (*s_values) {
1349  SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
1350  smartlist_free(*s_values);
1351  }
1352  if (*s_maxima) {
1353  SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
1354  smartlist_free(*s_maxima);
1355  }
1356  if (! server_mode(get_options())) {
1357  /* Clients don't need to store bandwidth history persistently;
1358  * force these values to the defaults. */
1359  /* FFFF we should pull the default out of config.c's state table,
1360  * so we don't have two defaults. */
1361  if (*s_begins != 0 || *s_interval != 900) {
1362  time_t now = time(NULL);
1363  time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
1364  or_state_mark_dirty(state, save_at);
1365  }
1366  *s_begins = 0;
1367  *s_interval = 900;
1368  *s_values = smartlist_new();
1369  *s_maxima = smartlist_new();
1370  return;
1371  }
1372  *s_begins = b->next_period;
1373  *s_interval = NUM_SECS_BW_SUM_INTERVAL;
1374 
1375  *s_values = smartlist_new();
1376  *s_maxima = smartlist_new();
1377  /* Set i to first position in circular array */
1378  i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
1379  for (j=0; j < b->num_maxes_set; ++j,++i) {
1380  if (i >= NUM_TOTALS)
1381  i = 0;
1382  smartlist_add_asprintf(*s_values, "%"PRIu64,
1383  (b->totals[i] & ~0x3ff));
1384  maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
1385  smartlist_add_asprintf(*s_maxima, "%"PRIu64,
1386  (maxval & ~0x3ff));
1387  }
1388  smartlist_add_asprintf(*s_values, "%"PRIu64,
1389  (b->total_in_period & ~0x3ff));
1390  maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
1391  smartlist_add_asprintf(*s_maxima, "%"PRIu64,
1392  (maxval & ~0x3ff));
1393 }
1394 
1395 /** Update <b>state</b> with the newest bandwidth history. Done before
1396  * writing out a new state file. */
1397 void
1399 {
1400 #define UPDATE(arrname,st) \
1401  rep_hist_update_bwhist_state_section(state,\
1402  (arrname),\
1403  &state->BWHistory ## st ## Values, \
1404  &state->BWHistory ## st ## Maxima, \
1405  &state->BWHistory ## st ## Ends, \
1406  &state->BWHistory ## st ## Interval)
1407 
1408  UPDATE(write_array, Write);
1409  UPDATE(read_array, Read);
1410  UPDATE(dir_write_array, DirWrite);
1411  UPDATE(dir_read_array, DirRead);
1412 
1413  if (server_mode(get_options())) {
1414  or_state_mark_dirty(state, time(NULL)+(2*3600));
1415  }
1416 #undef UPDATE
1417 }
1418 
1419 /** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
1420  * entries in an or_state_t. Done while reading the state file. */
1421 static int
1423  const smartlist_t *s_values,
1424  const smartlist_t *s_maxima,
1425  const time_t s_begins,
1426  const int s_interval)
1427 {
1428  time_t now = time(NULL);
1429  int retval = 0;
1430  time_t start;
1431 
1432  uint64_t v, mv;
1433  int i,ok,ok_m = 0;
1434  int have_maxima = s_maxima && s_values &&
1435  (smartlist_len(s_values) == smartlist_len(s_maxima));
1436 
1437  if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
1438  start = s_begins - s_interval*(smartlist_len(s_values));
1439  if (start > now)
1440  return 0;
1441  b->cur_obs_time = start;
1443  SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
1444  const char *maxstr = NULL;
1445  v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
1446  if (have_maxima) {
1447  maxstr = smartlist_get(s_maxima, cp_sl_idx);
1448  mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
1450  } else {
1451  /* No maxima known; guess average rate to be conservative. */
1452  mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
1453  }
1454  if (!ok) {
1455  retval = -1;
1456  log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
1457  }
1458  if (maxstr && !ok_m) {
1459  retval = -1;
1460  log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
1461  maxstr);
1462  }
1463 
1464  if (start < now) {
1465  time_t cur_start = start;
1466  time_t actual_interval_len = s_interval;
1467  uint64_t cur_val = 0;
1468  /* Calculate the average per second. This is the best we can do
1469  * because our state file doesn't have per-second resolution. */
1470  if (start + s_interval > now)
1471  actual_interval_len = now - start;
1472  cur_val = v / actual_interval_len;
1473  /* This is potentially inefficient, but since we don't do it very
1474  * often it should be ok. */
1475  while (cur_start < start + actual_interval_len) {
1476  add_obs(b, cur_start, cur_val);
1477  ++cur_start;
1478  }
1479  b->max_total = mv;
1480  /* This will result in some fairly choppy history if s_interval
1481  * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
1482  start += actual_interval_len;
1483  }
1484  } SMARTLIST_FOREACH_END(cp);
1485  }
1486 
1487  /* Clean up maxima and observed */
1488  for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
1489  b->obs[i] = 0;
1490  }
1491  b->total_obs = 0;
1492 
1493  return retval;
1494 }
1495 
1496 /** Set bandwidth history from the state file we just loaded. */
1497 int
1498 rep_hist_load_state(or_state_t *state, char **err)
1499 {
1500  int all_ok = 1;
1501 
1502  /* Assert they already have been malloced */
1505 
1506 #define LOAD(arrname,st) \
1507  if (rep_hist_load_bwhist_state_section( \
1508  (arrname), \
1509  state->BWHistory ## st ## Values, \
1510  state->BWHistory ## st ## Maxima, \
1511  state->BWHistory ## st ## Ends, \
1512  state->BWHistory ## st ## Interval)<0) \
1513  all_ok = 0
1514 
1515  LOAD(write_array, Write);
1516  LOAD(read_array, Read);
1517  LOAD(dir_write_array, DirWrite);
1518  LOAD(dir_read_array, DirRead);
1519 
1520 #undef LOAD
1521  if (!all_ok) {
1522  *err = tor_strdup("Parsing of bandwidth history values failed");
1523  /* and create fresh arrays */
1524  bw_arrays_init();
1525  return -1;
1526  }
1527  return 0;
1528 }
1529 
1530 /*** Exit port statistics ***/
1531 
1532 /* Some constants */
1533 /** To what multiple should byte numbers be rounded up? */
1534 #define EXIT_STATS_ROUND_UP_BYTES 1024
1535 /** To what multiple should stream counts be rounded up? */
1536 #define EXIT_STATS_ROUND_UP_STREAMS 4
1537 /** Number of TCP ports */
1538 #define EXIT_STATS_NUM_PORTS 65536
1539 /** Top n ports that will be included in exit stats. */
1540 #define EXIT_STATS_TOP_N_PORTS 10
1541 
1542 /* The following data structures are arrays and no fancy smartlists or maps,
1543  * so that all write operations can be done in constant time. This comes at
1544  * the price of some memory (1.25 MB) and linear complexity when writing
1545  * stats for measuring relays. */
1546 /** Number of bytes read in current period by exit port */
1547 static uint64_t *exit_bytes_read = NULL;
1548 /** Number of bytes written in current period by exit port */
1549 static uint64_t *exit_bytes_written = NULL;
1550 /** Number of streams opened in current period by exit port */
1551 static uint32_t *exit_streams = NULL;
1552 
1553 /** Start time of exit stats or 0 if we're not collecting exit stats. */
1555 
1556 /** Initialize exit port stats. */
1557 void
1559 {
1561  exit_bytes_read = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t));
1562  exit_bytes_written = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t));
1563  exit_streams = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint32_t));
1564 }
1565 
1566 /** Reset counters for exit port statistics. */
1567 void
1569 {
1571  memset(exit_bytes_read, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
1572  memset(exit_bytes_written, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
1573  memset(exit_streams, 0, EXIT_STATS_NUM_PORTS * sizeof(uint32_t));
1574 }
1575 
1576 /** Stop collecting exit port stats in a way that we can re-start doing
1577  * so in rep_hist_exit_stats_init(). */
1578 void
1580 {
1585 }
1586 
1587 /** Helper for qsort: compare two ints. Does not handle overflow properly,
1588  * but works fine for sorting an array of port numbers, which is what we use
1589  * it for. */
1590 static int
1591 compare_int_(const void *x, const void *y)
1592 {
1593  return (*(int*)x - *(int*)y);
1594 }
1595 
1596 /** Return a newly allocated string containing the exit port statistics
1597  * until <b>now</b>, or NULL if we're not collecting exit stats. Caller
1598  * must ensure start_of_exit_stats_interval is in the past. */
1599 char *
1601 {
1602  int i, j, top_elements = 0, cur_min_idx = 0, cur_port;
1603  uint64_t top_bytes[EXIT_STATS_TOP_N_PORTS];
1604  int top_ports[EXIT_STATS_TOP_N_PORTS];
1605  uint64_t cur_bytes = 0, other_read = 0, other_written = 0,
1606  total_read = 0, total_written = 0;
1607  uint32_t total_streams = 0, other_streams = 0;
1608  smartlist_t *written_strings, *read_strings, *streams_strings;
1609  char *written_string, *read_string, *streams_string;
1610  char t[ISO_TIME_LEN+1];
1611  char *result;
1612 
1614  return NULL; /* Not initialized. */
1615 
1617 
1618  /* Go through all ports to find the n ports that saw most written and
1619  * read bytes.
1620  *
1621  * Invariant: at the end of the loop for iteration i,
1622  * total_read is the sum of all exit_bytes_read[0..i]
1623  * total_written is the sum of all exit_bytes_written[0..i]
1624  * total_stream is the sum of all exit_streams[0..i]
1625  *
1626  * top_elements = MAX(EXIT_STATS_TOP_N_PORTS,
1627  * #{j | 0 <= j <= i && volume(i) > 0})
1628  *
1629  * For all 0 <= j < top_elements,
1630  * top_bytes[j] > 0
1631  * 0 <= top_ports[j] <= 65535
1632  * top_bytes[j] = volume(top_ports[j])
1633  *
1634  * There is no j in 0..i and k in 0..top_elements such that:
1635  * volume(j) > top_bytes[k] AND j is not in top_ports[0..top_elements]
1636  *
1637  * There is no j!=cur_min_idx in 0..top_elements such that:
1638  * top_bytes[j] < top_bytes[cur_min_idx]
1639  *
1640  * where volume(x) == exit_bytes_read[x]+exit_bytes_written[x]
1641  *
1642  * Worst case: O(EXIT_STATS_NUM_PORTS * EXIT_STATS_TOP_N_PORTS)
1643  */
1644  for (i = 1; i < EXIT_STATS_NUM_PORTS; i++) {
1645  total_read += exit_bytes_read[i];
1646  total_written += exit_bytes_written[i];
1647  total_streams += exit_streams[i];
1648  cur_bytes = exit_bytes_read[i] + exit_bytes_written[i];
1649  if (cur_bytes == 0) {
1650  continue;
1651  }
1652  if (top_elements < EXIT_STATS_TOP_N_PORTS) {
1653  top_bytes[top_elements] = cur_bytes;
1654  top_ports[top_elements++] = i;
1655  } else if (cur_bytes > top_bytes[cur_min_idx]) {
1656  top_bytes[cur_min_idx] = cur_bytes;
1657  top_ports[cur_min_idx] = i;
1658  } else {
1659  continue;
1660  }
1661  cur_min_idx = 0;
1662  for (j = 1; j < top_elements; j++) {
1663  if (top_bytes[j] < top_bytes[cur_min_idx]) {
1664  cur_min_idx = j;
1665  }
1666  }
1667  }
1668 
1669  /* Add observations of top ports to smartlists. */
1670  written_strings = smartlist_new();
1671  read_strings = smartlist_new();
1672  streams_strings = smartlist_new();
1673  other_read = total_read;
1674  other_written = total_written;
1675  other_streams = total_streams;
1676  /* Sort the ports; this puts them out of sync with top_bytes, but we
1677  * won't be using top_bytes again anyway */
1678  qsort(top_ports, top_elements, sizeof(int), compare_int_);
1679  for (j = 0; j < top_elements; j++) {
1680  cur_port = top_ports[j];
1681  if (exit_bytes_written[cur_port] > 0) {
1682  uint64_t num = round_uint64_to_next_multiple_of(
1683  exit_bytes_written[cur_port],
1685  num /= 1024;
1686  smartlist_add_asprintf(written_strings, "%d=%"PRIu64,
1687  cur_port, (num));
1688  other_written -= exit_bytes_written[cur_port];
1689  }
1690  if (exit_bytes_read[cur_port] > 0) {
1691  uint64_t num = round_uint64_to_next_multiple_of(
1692  exit_bytes_read[cur_port],
1694  num /= 1024;
1695  smartlist_add_asprintf(read_strings, "%d=%"PRIu64,
1696  cur_port, (num));
1697  other_read -= exit_bytes_read[cur_port];
1698  }
1699  if (exit_streams[cur_port] > 0) {
1700  uint32_t num = round_uint32_to_next_multiple_of(
1701  exit_streams[cur_port],
1703  smartlist_add_asprintf(streams_strings, "%d=%u", cur_port, num);
1704  other_streams -= exit_streams[cur_port];
1705  }
1706  }
1707 
1708  /* Add observations of other ports in a single element. */
1709  other_written = round_uint64_to_next_multiple_of(other_written,
1711  other_written /= 1024;
1712  smartlist_add_asprintf(written_strings, "other=%"PRIu64,
1713  (other_written));
1714  other_read = round_uint64_to_next_multiple_of(other_read,
1716  other_read /= 1024;
1717  smartlist_add_asprintf(read_strings, "other=%"PRIu64,
1718  (other_read));
1719  other_streams = round_uint32_to_next_multiple_of(other_streams,
1721  smartlist_add_asprintf(streams_strings, "other=%u", other_streams);
1722 
1723  /* Join all observations in single strings. */
1724  written_string = smartlist_join_strings(written_strings, ",", 0, NULL);
1725  read_string = smartlist_join_strings(read_strings, ",", 0, NULL);
1726  streams_string = smartlist_join_strings(streams_strings, ",", 0, NULL);
1727  SMARTLIST_FOREACH(written_strings, char *, cp, tor_free(cp));
1728  SMARTLIST_FOREACH(read_strings, char *, cp, tor_free(cp));
1729  SMARTLIST_FOREACH(streams_strings, char *, cp, tor_free(cp));
1730  smartlist_free(written_strings);
1731  smartlist_free(read_strings);
1732  smartlist_free(streams_strings);
1733 
1734  /* Put everything together. */
1735  format_iso_time(t, now);
1736  tor_asprintf(&result, "exit-stats-end %s (%d s)\n"
1737  "exit-kibibytes-written %s\n"
1738  "exit-kibibytes-read %s\n"
1739  "exit-streams-opened %s\n",
1740  t, (unsigned) (now - start_of_exit_stats_interval),
1741  written_string,
1742  read_string,
1743  streams_string);
1744  tor_free(written_string);
1745  tor_free(read_string);
1746  tor_free(streams_string);
1747  return result;
1748 }
1749 
1750 /** If 24 hours have passed since the beginning of the current exit port
1751  * stats period, write exit stats to $DATADIR/stats/exit-stats (possibly
1752  * overwriting an existing file) and reset counters. Return when we would
1753  * next want to write exit stats or 0 if we never want to write. */
1754 time_t
1756 {
1757  char *str = NULL;
1758 
1760  return 0; /* Not initialized. */
1761  if (start_of_exit_stats_interval + WRITE_STATS_INTERVAL > now)
1762  goto done; /* Not ready to write. */
1763 
1764  log_info(LD_HIST, "Writing exit port statistics to disk.");
1765 
1766  /* Generate history string. */
1767  str = rep_hist_format_exit_stats(now);
1768 
1769  /* Reset counters. */
1771 
1772  /* Try to write to disk. */
1773  if (!check_or_create_data_subdir("stats")) {
1774  write_to_data_subdir("stats", "exit-stats", str, "exit port statistics");
1775  }
1776 
1777  done:
1778  tor_free(str);
1779  return start_of_exit_stats_interval + WRITE_STATS_INTERVAL;
1780 }
1781 
1782 /** Note that we wrote <b>num_written</b> bytes and read <b>num_read</b>
1783  * bytes to/from an exit connection to <b>port</b>. */
1784 void
1785 rep_hist_note_exit_bytes(uint16_t port, size_t num_written,
1786  size_t num_read)
1787 {
1789  return; /* Not initialized. */
1790  exit_bytes_written[port] += num_written;
1791  exit_bytes_read[port] += num_read;
1792  log_debug(LD_HIST, "Written %lu bytes and read %lu bytes to/from an "
1793  "exit connection to port %d.",
1794  (unsigned long)num_written, (unsigned long)num_read, port);
1795 }
1796 
1797 /** Note that we opened an exit stream to <b>port</b>. */
1798 void
1800 {
1802  return; /* Not initialized. */
1803  exit_streams[port]++;
1804  log_debug(LD_HIST, "Opened exit stream to port %d", port);
1805 }
1806 
1807 /*** cell statistics ***/
1808 
1809 /** Start of the current buffer stats interval or 0 if we're not
1810  * collecting buffer statistics. */
1812 
1813 /** Initialize buffer stats. */
1814 void
1816 {
1818 }
1819 
1820 /** Statistics from a single circuit. Collected when the circuit closes, or
1821  * when we flush statistics to disk. */
1822 typedef struct circ_buffer_stats_t {
1823  /** Average number of cells in the circuit's queue */
1825  /** Average time a cell waits in the queue. */
1827  /** Total number of cells sent over this circuit */
1830 
1831 /** List of circ_buffer_stats_t. */
1833 
1834 /** Remember cell statistics <b>mean_num_cells_in_queue</b>,
1835  * <b>mean_time_cells_in_queue</b>, and <b>processed_cells</b> of a
1836  * circuit. */
1837 void
1838 rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
1839  double mean_time_cells_in_queue, uint32_t processed_cells)
1840 {
1841  circ_buffer_stats_t *stats;
1843  return; /* Not initialized. */
1844  stats = tor_malloc_zero(sizeof(circ_buffer_stats_t));
1845  stats->mean_num_cells_in_queue = mean_num_cells_in_queue;
1846  stats->mean_time_cells_in_queue = mean_time_cells_in_queue;
1847  stats->processed_cells = processed_cells;
1851 }
1852 
1853 /** Remember cell statistics for circuit <b>circ</b> at time
1854  * <b>end_of_interval</b> and reset cell counters in case the circuit
1855  * remains open in the next measurement interval. */
1856 void
1857 rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
1858 {
1859  time_t start_of_interval;
1860  int interval_length;
1861  or_circuit_t *orcirc;
1862  double mean_num_cells_in_queue, mean_time_cells_in_queue;
1863  uint32_t processed_cells;
1864  if (CIRCUIT_IS_ORIGIN(circ))
1865  return;
1866  orcirc = TO_OR_CIRCUIT(circ);
1867  if (!orcirc->processed_cells)
1868  return;
1869  start_of_interval = (circ->timestamp_created.tv_sec >
1871  (time_t)circ->timestamp_created.tv_sec :
1873  interval_length = (int) (end_of_interval - start_of_interval);
1874  if (interval_length <= 0)
1875  return;
1876  processed_cells = orcirc->processed_cells;
1877  /* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
1878  mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
1879  (double) interval_length / 1000.0 / 2.0;
1880  mean_time_cells_in_queue =
1881  (double) orcirc->total_cell_waiting_time /
1882  (double) orcirc->processed_cells;
1883  orcirc->total_cell_waiting_time = 0;
1884  orcirc->processed_cells = 0;
1885  rep_hist_add_buffer_stats(mean_num_cells_in_queue,
1886  mean_time_cells_in_queue,
1887  processed_cells);
1888 }
1889 
1890 /** Sorting helper: return -1, 1, or 0 based on comparison of two
1891  * circ_buffer_stats_t */
1892 static int
1893 buffer_stats_compare_entries_(const void **_a, const void **_b)
1894 {
1895  const circ_buffer_stats_t *a = *_a, *b = *_b;
1896  if (a->processed_cells < b->processed_cells)
1897  return 1;
1898  else if (a->processed_cells > b->processed_cells)
1899  return -1;
1900  else
1901  return 0;
1902 }
1903 
1904 /** Stop collecting cell stats in a way that we can re-start doing so in
1905  * rep_hist_buffer_stats_init(). */
1906 void
1908 {
1910 }
1911 
1912 /** Clear history of circuit statistics and set the measurement interval
1913  * start to <b>now</b>. */
1914 void
1916 {
1920  stats, tor_free(stats));
1923 }
1924 
1925 /** Return a newly allocated string containing the buffer statistics until
1926  * <b>now</b>, or NULL if we're not collecting buffer stats. Caller must
1927  * ensure start_of_buffer_stats_interval is in the past. */
1928 char *
1930 {
1931 #define SHARES 10
1932  uint64_t processed_cells[SHARES];
1933  uint32_t circs_in_share[SHARES];
1934  int number_of_circuits, i;
1935  double queued_cells[SHARES], time_in_queue[SHARES];
1936  smartlist_t *processed_cells_strings, *queued_cells_strings,
1937  *time_in_queue_strings;
1938  char *processed_cells_string, *queued_cells_string,
1939  *time_in_queue_string;
1940  char t[ISO_TIME_LEN+1];
1941  char *result;
1942 
1944  return NULL; /* Not initialized. */
1945 
1947 
1948  /* Calculate deciles if we saw at least one circuit. */
1949  memset(processed_cells, 0, SHARES * sizeof(uint64_t));
1950  memset(circs_in_share, 0, SHARES * sizeof(uint32_t));
1951  memset(queued_cells, 0, SHARES * sizeof(double));
1952  memset(time_in_queue, 0, SHARES * sizeof(double));
1955  number_of_circuits = smartlist_len(circuits_for_buffer_stats);
1956  if (number_of_circuits > 0) {
1959  i = 0;
1961  circ_buffer_stats_t *, stats)
1962  {
1963  int share = i++ * SHARES / number_of_circuits;
1964  processed_cells[share] += stats->processed_cells;
1965  queued_cells[share] += stats->mean_num_cells_in_queue;
1966  time_in_queue[share] += stats->mean_time_cells_in_queue;
1967  circs_in_share[share]++;
1968  }
1969  SMARTLIST_FOREACH_END(stats);
1970  }
1971 
1972  /* Write deciles to strings. */
1973  processed_cells_strings = smartlist_new();
1974  queued_cells_strings = smartlist_new();
1975  time_in_queue_strings = smartlist_new();
1976  for (i = 0; i < SHARES; i++) {
1977  smartlist_add_asprintf(processed_cells_strings,
1978  "%"PRIu64, !circs_in_share[i] ? 0 :
1979  (processed_cells[i] /
1980  circs_in_share[i]));
1981  }
1982  for (i = 0; i < SHARES; i++) {
1983  smartlist_add_asprintf(queued_cells_strings, "%.2f",
1984  circs_in_share[i] == 0 ? 0.0 :
1985  queued_cells[i] / (double) circs_in_share[i]);
1986  }
1987  for (i = 0; i < SHARES; i++) {
1988  smartlist_add_asprintf(time_in_queue_strings, "%.0f",
1989  circs_in_share[i] == 0 ? 0.0 :
1990  time_in_queue[i] / (double) circs_in_share[i]);
1991  }
1992 
1993  /* Join all observations in single strings. */
1994  processed_cells_string = smartlist_join_strings(processed_cells_strings,
1995  ",", 0, NULL);
1996  queued_cells_string = smartlist_join_strings(queued_cells_strings,
1997  ",", 0, NULL);
1998  time_in_queue_string = smartlist_join_strings(time_in_queue_strings,
1999  ",", 0, NULL);
2000  SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp));
2001  SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp));
2002  SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp));
2003  smartlist_free(processed_cells_strings);
2004  smartlist_free(queued_cells_strings);
2005  smartlist_free(time_in_queue_strings);
2006 
2007  /* Put everything together. */
2008  format_iso_time(t, now);
2009  tor_asprintf(&result, "cell-stats-end %s (%d s)\n"
2010  "cell-processed-cells %s\n"
2011  "cell-queued-cells %s\n"
2012  "cell-time-in-queue %s\n"
2013  "cell-circuits-per-decile %d\n",
2014  t, (unsigned) (now - start_of_buffer_stats_interval),
2015  processed_cells_string,
2016  queued_cells_string,
2017  time_in_queue_string,
2018  CEIL_DIV(number_of_circuits, SHARES));
2019  tor_free(processed_cells_string);
2020  tor_free(queued_cells_string);
2021  tor_free(time_in_queue_string);
2022  return result;
2023 #undef SHARES
2024 }
2025 
2026 /** If 24 hours have passed since the beginning of the current buffer
2027  * stats period, write buffer stats to $DATADIR/stats/buffer-stats
2028  * (possibly overwriting an existing file) and reset counters. Return
2029  * when we would next want to write buffer stats or 0 if we never want to
2030  * write. */
2031 time_t
2033 {
2034  char *str = NULL;
2035 
2037  return 0; /* Not initialized. */
2038  if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
2039  goto done; /* Not ready to write */
2040 
2041  /* Add open circuits to the history. */
2043  rep_hist_buffer_stats_add_circ(circ, now);
2044  }
2045  SMARTLIST_FOREACH_END(circ);
2046 
2047  /* Generate history string. */
2048  str = rep_hist_format_buffer_stats(now);
2049 
2050  /* Reset both buffer history and counters of open circuits. */
2052 
2053  /* Try to write to disk. */
2054  if (!check_or_create_data_subdir("stats")) {
2055  write_to_data_subdir("stats", "buffer-stats", str, "buffer statistics");
2056  }
2057 
2058  done:
2059  tor_free(str);
2060  return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
2061 }
2062 
2063 /*** Descriptor serving statistics ***/
2064 
2065 /** Digestmap to track which descriptors were downloaded this stats
2066  * collection interval. It maps descriptor digest to pointers to 1,
2067  * effectively turning this into a list. */
2068 static digestmap_t *served_descs = NULL;
2069 
2070 /** Number of how many descriptors were downloaded in total during this
2071  * interval. */
2072 static unsigned long total_descriptor_downloads;
2073 
2074 /** Start time of served descs stats or 0 if we're not collecting those. */
2076 
2077 /** Initialize descriptor stats. */
2078 void
2080 {
2081  if (served_descs) {
2082  log_warn(LD_BUG, "Called rep_hist_desc_stats_init() when desc stats were "
2083  "already initialized. This is probably harmless.");
2084  return; // Already initialized
2085  }
2086  served_descs = digestmap_new();
2089 }
2090 
2091 /** Reset served descs stats to empty, starting a new interval <b>now</b>. */
2092 static void
2094 {
2097 }
2098 
2099 /** Stop collecting served descs stats, so that rep_hist_desc_stats_init() is
2100  * safe to be called again. */
2101 void
2103 {
2104  digestmap_free(served_descs, NULL);
2105  served_descs = NULL;
2108 }
2109 
2110 /** Helper for rep_hist_desc_stats_write(). Return a newly allocated string
2111  * containing the served desc statistics until now, or NULL if we're not
2112  * collecting served desc stats. Caller must ensure that now is not before
2113  * start_of_served_descs_stats_interval. */
2114 static char *
2116 {
2117  char t[ISO_TIME_LEN+1];
2118  char *result;
2119 
2120  digestmap_iter_t *iter;
2121  const char *key;
2122  void *val;
2123  unsigned size;
2124  int *vals, max = 0, q3 = 0, md = 0, q1 = 0, min = 0;
2125  int n = 0;
2126 
2128  return NULL;
2129 
2130  size = digestmap_size(served_descs);
2131  if (size > 0) {
2132  vals = tor_calloc(size, sizeof(int));
2133  for (iter = digestmap_iter_init(served_descs);
2134  !digestmap_iter_done(iter);
2135  iter = digestmap_iter_next(served_descs, iter)) {
2136  uintptr_t count;
2137  digestmap_iter_get(iter, &key, &val);
2138  count = (uintptr_t)val;
2139  vals[n++] = (int)count;
2140  (void)key;
2141  }
2142  max = find_nth_int(vals, size, size-1);
2143  q3 = find_nth_int(vals, size, (3*size-1)/4);
2144  md = find_nth_int(vals, size, (size-1)/2);
2145  q1 = find_nth_int(vals, size, (size-1)/4);
2146  min = find_nth_int(vals, size, 0);
2147  tor_free(vals);
2148  }
2149 
2150  format_iso_time(t, now);
2151 
2152  tor_asprintf(&result,
2153  "served-descs-stats-end %s (%d s) total=%lu unique=%u "
2154  "max=%d q3=%d md=%d q1=%d min=%d\n",
2155  t,
2156  (unsigned) (now - start_of_served_descs_stats_interval),
2158  size, max, q3, md, q1, min);
2159 
2160  return result;
2161 }
2162 
2163 /** If WRITE_STATS_INTERVAL seconds have passed since the beginning of
2164  * the current served desc stats interval, write the stats to
2165  * $DATADIR/stats/served-desc-stats (possibly appending to an existing file)
2166  * and reset the state for the next interval. Return when we would next want
2167  * to write served desc stats or 0 if we won't want to write. */
2168 time_t
2170 {
2171  char *filename = NULL, *str = NULL;
2172 
2174  return 0; /* We're not collecting stats. */
2175  if (start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL > now)
2176  return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL;
2177 
2178  str = rep_hist_format_desc_stats(now);
2179  tor_assert(str != NULL);
2180 
2181  if (check_or_create_data_subdir("stats") < 0) {
2182  goto done;
2183  }
2184  filename = get_datadir_fname2("stats", "served-desc-stats");
2185  if (append_bytes_to_file(filename, str, strlen(str), 0) < 0)
2186  log_warn(LD_HIST, "Unable to write served descs statistics to disk!");
2187 
2189 
2190  done:
2191  tor_free(filename);
2192  tor_free(str);
2193  return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL;
2194 }
2195 
2196 /** Called to note that we've served a given descriptor (by
2197  * digest). Increments the count of descriptors served, and the number
2198  * of times we've served this descriptor. */
2199 void
2200 rep_hist_note_desc_served(const char * desc)
2201 {
2202  void *val;
2203  uintptr_t count;
2204  if (!served_descs)
2205  return; // We're not collecting stats
2206  val = digestmap_get(served_descs, desc);
2207  count = (uintptr_t)val;
2208  if (count != INT_MAX)
2209  ++count;
2210  digestmap_set(served_descs, desc, (void*)count);
2212 }
2213 
2214 /*** Connection statistics ***/
2215 
2216 /** Start of the current connection stats interval or 0 if we're not
2217  * collecting connection statistics. */
2219 
2220 /** Initialize connection stats. */
2221 void
2223 {
2225 }
2226 
2227 /* Count connections that we read and wrote less than these many bytes
2228  * from/to as below threshold. */
2229 #define BIDI_THRESHOLD 20480
2230 
2231 /* Count connections that we read or wrote at least this factor as many
2232  * bytes from/to than we wrote or read to/from as mostly reading or
2233  * writing. */
2234 #define BIDI_FACTOR 10
2235 
2236 /* Interval length in seconds for considering read and written bytes for
2237  * connection stats. */
2238 #define BIDI_INTERVAL 10
2239 
2240 /** Start of next BIDI_INTERVAL second interval. */
2241 static time_t bidi_next_interval = 0;
2242 
2243 /** Number of connections that we read and wrote less than BIDI_THRESHOLD
2244  * bytes from/to in BIDI_INTERVAL seconds. */
2245 static uint32_t below_threshold = 0;
2246 
2247 /** Number of connections that we read at least BIDI_FACTOR times more
2248  * bytes from than we wrote to in BIDI_INTERVAL seconds. */
2249 static uint32_t mostly_read = 0;
2250 
2251 /** Number of connections that we wrote at least BIDI_FACTOR times more
2252  * bytes to than we read from in BIDI_INTERVAL seconds. */
2253 static uint32_t mostly_written = 0;
2254 
2255 /** Number of connections that we read and wrote at least BIDI_THRESHOLD
2256  * bytes from/to, but not BIDI_FACTOR times more in either direction in
2257  * BIDI_INTERVAL seconds. */
2258 static uint32_t both_read_and_written = 0;
2259 
2260 /** Entry in a map from connection ID to the number of read and written
2261  * bytes on this connection in a BIDI_INTERVAL second interval. */
2262 typedef struct bidi_map_entry_t {
2263  HT_ENTRY(bidi_map_entry_t) node;
2264  uint64_t conn_id; /**< Connection ID */
2265  size_t read; /**< Number of read bytes */
2266  size_t written; /**< Number of written bytes */
2268 
2269 /** Map of OR connections together with the number of read and written
2270  * bytes in the current BIDI_INTERVAL second interval. */
2271 static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
2272  HT_INITIALIZER();
2273 
2274 static int
2275 bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
2276 {
2277  return a->conn_id == b->conn_id;
2278 }
2279 
2280 /* DOCDOC bidi_map_ent_hash */
2281 static unsigned
2282 bidi_map_ent_hash(const bidi_map_entry_t *entry)
2283 {
2284  return (unsigned) entry->conn_id;
2285 }
2286 
2287 HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
2288  bidi_map_ent_eq)
2289 HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
2290  bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
2291 
2292 /* DOCDOC bidi_map_free */
2293 static void
2294 bidi_map_free_all(void)
2295 {
2296  bidi_map_entry_t **ptr, **next, *ent;
2297  for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
2298  ent = *ptr;
2299  next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
2300  tor_free(ent);
2301  }
2302  HT_CLEAR(bidimap, &bidi_map);
2303 }
2304 
2305 /** Reset counters for conn statistics. */
2306 void
2308 {
2310  below_threshold = 0;
2311  mostly_read = 0;
2312  mostly_written = 0;
2314  bidi_map_free_all();
2315 }
2316 
2317 /** Stop collecting connection stats in a way that we can re-start doing
2318  * so in rep_hist_conn_stats_init(). */
2319 void
2321 {
2323 }
2324 
2325 /** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
2326  * connection <b>conn_id</b> in second <b>when</b>. If this is the first
2327  * observation in a new interval, sum up the last observations. Add bytes
2328  * for this connection. */
2329 void
2330 rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
2331  size_t num_written, time_t when)
2332 {
2334  return;
2335  /* Initialize */
2336  if (bidi_next_interval == 0)
2337  bidi_next_interval = when + BIDI_INTERVAL;
2338  /* Sum up last period's statistics */
2339  if (when >= bidi_next_interval) {
2340  bidi_map_entry_t **ptr, **next, *ent;
2341  for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
2342  ent = *ptr;
2343  if (ent->read + ent->written < BIDI_THRESHOLD)
2344  below_threshold++;
2345  else if (ent->read >= ent->written * BIDI_FACTOR)
2346  mostly_read++;
2347  else if (ent->written >= ent->read * BIDI_FACTOR)
2348  mostly_written++;
2349  else
2351  next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
2352  tor_free(ent);
2353  }
2354  while (when >= bidi_next_interval)
2355  bidi_next_interval += BIDI_INTERVAL;
2356  log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
2357  "%d mostly written, %d both read and written.",
2360  }
2361  /* Add this connection's bytes. */
2362  if (num_read > 0 || num_written > 0) {
2363  bidi_map_entry_t *entry, lookup;
2364  lookup.conn_id = conn_id;
2365  entry = HT_FIND(bidimap, &bidi_map, &lookup);
2366  if (entry) {
2367  entry->written += num_written;
2368  entry->read += num_read;
2369  } else {
2370  entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
2371  entry->conn_id = conn_id;
2372  entry->written = num_written;
2373  entry->read = num_read;
2374  HT_INSERT(bidimap, &bidi_map, entry);
2375  }
2376  }
2377 }
2378 
2379 /** Return a newly allocated string containing the connection statistics
2380  * until <b>now</b>, or NULL if we're not collecting conn stats. Caller must
2381  * ensure start_of_conn_stats_interval is in the past. */
2382 char *
2384 {
2385  char *result, written[ISO_TIME_LEN+1];
2386 
2388  return NULL; /* Not initialized. */
2389 
2391 
2392  format_iso_time(written, now);
2393  tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n",
2394  written,
2395  (unsigned) (now - start_of_conn_stats_interval),
2397  mostly_read,
2400  return result;
2401 }
2402 
2403 /** If 24 hours have passed since the beginning of the current conn stats
2404  * period, write conn stats to $DATADIR/stats/conn-stats (possibly
2405  * overwriting an existing file) and reset counters. Return when we would
2406  * next want to write conn stats or 0 if we never want to write. */
2407 time_t
2409 {
2410  char *str = NULL;
2411 
2413  return 0; /* Not initialized. */
2414  if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
2415  goto done; /* Not ready to write */
2416 
2417  /* Generate history string. */
2418  str = rep_hist_format_conn_stats(now);
2419 
2420  /* Reset counters. */
2422 
2423  /* Try to write to disk. */
2424  if (!check_or_create_data_subdir("stats")) {
2425  write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
2426  }
2427 
2428  done:
2429  tor_free(str);
2430  return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
2431 }
2432 
2433 /** Internal statistics to track how many requests of each type of
2434  * handshake we've received, and how many we've assigned to cpuworkers.
2435  * Useful for seeing trends in cpu load.
2436  * @{ */
2437 STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
2438 STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
2439 /**@}*/
2440 
2441 /** A new onionskin (using the <b>type</b> handshake) has arrived. */
2442 void
2444 {
2445  if (type <= MAX_ONION_HANDSHAKE_TYPE)
2447 }
2448 
2449 /** We've sent an onionskin (using the <b>type</b> handshake) to a
2450  * cpuworker. */
2451 void
2453 {
2454  if (type <= MAX_ONION_HANDSHAKE_TYPE)
2455  onion_handshakes_assigned[type]++;
2456 }
2457 
2458 /** Log our onionskin statistics since the last time we were called. */
2459 void
2461 {
2462  (void)now;
2463  log_notice(LD_HEARTBEAT, "Circuit handshake stats since last time: "
2464  "%d/%d TAP, %d/%d NTor.",
2465  onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP],
2466  onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP],
2467  onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR],
2468  onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]);
2469  memset(onion_handshakes_assigned, 0, sizeof(onion_handshakes_assigned));
2471 }
2472 
2473 /* Hidden service statistics section */
2474 
2475 /** Start of the current hidden service stats interval or 0 if we're
2476  * not collecting hidden service statistics. */
2478 
2479 /** Carries the various hidden service statistics, and any other
2480  * information needed. */
2481 typedef struct hs_stats_t {
2482  /** How many relay cells have we seen as rendezvous points? */
2484 
2485  /** Set of unique public key digests we've seen this stat period
2486  * (could also be implemented as sorted smartlist). */
2488 } hs_stats_t;
2489 
2490 /** Our statistics structure singleton. */
2491 static hs_stats_t *hs_stats = NULL;
2492 
2493 /** Allocate, initialize and return an hs_stats_t structure. */
2494 static hs_stats_t *
2496 {
2497  hs_stats_t *new_hs_stats = tor_malloc_zero(sizeof(hs_stats_t));
2498  new_hs_stats->onions_seen_this_period = digestmap_new();
2499 
2500  return new_hs_stats;
2501 }
2502 
2503 #define hs_stats_free(val) \
2504  FREE_AND_NULL(hs_stats_t, hs_stats_free_, (val))
2505 
2506 /** Free an hs_stats_t structure. */
2507 static void
2508 hs_stats_free_(hs_stats_t *victim_hs_stats)
2509 {
2510  if (!victim_hs_stats) {
2511  return;
2512  }
2513 
2514  digestmap_free(victim_hs_stats->onions_seen_this_period, NULL);
2515  tor_free(victim_hs_stats);
2516 }
2517 
2518 /** Initialize hidden service statistics. */
2519 void
2521 {
2522  if (!hs_stats) {
2523  hs_stats = hs_stats_new();
2524  }
2525 
2527 }
2528 
2529 /** Clear history of hidden service statistics and set the measurement
2530  * interval start to <b>now</b>. */
2531 static void
2533 {
2534  if (!hs_stats) {
2535  hs_stats = hs_stats_new();
2536  }
2537 
2539 
2540  digestmap_free(hs_stats->onions_seen_this_period, NULL);
2541  hs_stats->onions_seen_this_period = digestmap_new();
2542 
2544 }
2545 
2546 /** Stop collecting hidden service stats in a way that we can re-start
2547  * doing so in rep_hist_buffer_stats_init(). */
2548 void
2550 {
2552 }
2553 
2554 /** We saw a new HS relay cell, Count it! */
2555 void
2557 {
2558  if (!hs_stats) {
2559  return; // We're not collecting stats
2560  }
2561 
2563 }
2564 
2565 /** As HSDirs, we saw another hidden service with public key
2566  * <b>pubkey</b>. Check whether we have counted it before, if not
2567  * count it now! */
2568 void
2570 {
2571  char pubkey_hash[DIGEST_LEN];
2572 
2573  if (!hs_stats) {
2574  return; // We're not collecting stats
2575  }
2576 
2577  /* Get the digest of the pubkey which will be used to detect whether
2578  we've seen this hidden service before or not. */
2579  if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) {
2580  /* This fail should not happen; key has been validated by
2581  descriptor parsing code first. */
2582  return;
2583  }
2584 
2585  /* Check if this is the first time we've seen this hidden
2586  service. If it is, count it as new. */
2587  if (!digestmap_get(hs_stats->onions_seen_this_period,
2588  pubkey_hash)) {
2589  digestmap_set(hs_stats->onions_seen_this_period,
2590  pubkey_hash, (void*)(uintptr_t)1);
2591  }
2592 }
2593 
2594 /* The number of cells that are supposed to be hidden from the adversary
2595  * by adding noise from the Laplace distribution. This value, divided by
2596  * EPSILON, is Laplace parameter b. It must be greather than 0. */
2597 #define REND_CELLS_DELTA_F 2048
2598 /* Security parameter for obfuscating number of cells with a value between
2599  * ]0.0, 1.0]. Smaller values obfuscate observations more, but at the same
2600  * time make statistics less usable. */
2601 #define REND_CELLS_EPSILON 0.3
2602 /* The number of cells that are supposed to be hidden from the adversary
2603  * by rounding up to the next multiple of this number. */
2604 #define REND_CELLS_BIN_SIZE 1024
2605 /* The number of service identities that are supposed to be hidden from the
2606  * adversary by adding noise from the Laplace distribution. This value,
2607  * divided by EPSILON, is Laplace parameter b. It must be greater than 0. */
2608 #define ONIONS_SEEN_DELTA_F 8
2609 /* Security parameter for obfuscating number of service identities with a
2610  * value between ]0.0, 1.0]. Smaller values obfuscate observations more, but
2611  * at the same time make statistics less usable. */
2612 #define ONIONS_SEEN_EPSILON 0.3
2613 /* The number of service identities that are supposed to be hidden from
2614  * the adversary by rounding up to the next multiple of this number. */
2615 #define ONIONS_SEEN_BIN_SIZE 8
2616 
2617 /** Allocate and return a string containing hidden service stats that
2618  * are meant to be placed in the extra-info descriptor. */
2619 static char *
2621 {
2622  char t[ISO_TIME_LEN+1];
2623  char *hs_stats_string;
2624  int64_t obfuscated_cells_seen;
2625  int64_t obfuscated_onions_seen;
2626 
2627  uint64_t rounded_cells_seen
2629  REND_CELLS_BIN_SIZE);
2630  rounded_cells_seen = MIN(rounded_cells_seen, INT64_MAX);
2631  obfuscated_cells_seen = add_laplace_noise((int64_t)rounded_cells_seen,
2633  REND_CELLS_DELTA_F, REND_CELLS_EPSILON);
2634 
2635  uint64_t rounded_onions_seen =
2636  round_uint64_to_next_multiple_of((size_t)digestmap_size(
2638  ONIONS_SEEN_BIN_SIZE);
2639  rounded_onions_seen = MIN(rounded_onions_seen, INT64_MAX);
2640  obfuscated_onions_seen = add_laplace_noise((int64_t)rounded_onions_seen,
2641  crypto_rand_double(), ONIONS_SEEN_DELTA_F,
2642  ONIONS_SEEN_EPSILON);
2643 
2644  format_iso_time(t, now);
2645  tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n"
2646  "hidserv-rend-relayed-cells %"PRId64" delta_f=%d "
2647  "epsilon=%.2f bin_size=%d\n"
2648  "hidserv-dir-onions-seen %"PRId64" delta_f=%d "
2649  "epsilon=%.2f bin_size=%d\n",
2650  t, (unsigned) (now - start_of_hs_stats_interval),
2651  (obfuscated_cells_seen), REND_CELLS_DELTA_F,
2652  REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE,
2653  (obfuscated_onions_seen),
2654  ONIONS_SEEN_DELTA_F,
2655  ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE);
2656 
2657  return hs_stats_string;
2658 }
2659 
2660 /** If 24 hours have passed since the beginning of the current HS
2661  * stats period, write buffer stats to $DATADIR/stats/hidserv-stats
2662  * (possibly overwriting an existing file) and reset counters. Return
2663  * when we would next want to write buffer stats or 0 if we never want to
2664  * write. */
2665 time_t
2667 {
2668  char *str = NULL;
2669 
2671  return 0; /* Not initialized. */
2672  }
2673 
2674  if (start_of_hs_stats_interval + WRITE_STATS_INTERVAL > now) {
2675  goto done; /* Not ready to write */
2676  }
2677 
2678  /* Generate history string. */
2679  str = rep_hist_format_hs_stats(now);
2680 
2681  /* Reset HS history. */
2683 
2684  /* Try to write to disk. */
2685  if (!check_or_create_data_subdir("stats")) {
2686  write_to_data_subdir("stats", "hidserv-stats", str,
2687  "hidden service stats");
2688  }
2689 
2690  done:
2691  tor_free(str);
2692  return start_of_hs_stats_interval + WRITE_STATS_INTERVAL;
2693 }
2694 
2695 static uint64_t link_proto_count[MAX_LINK_PROTO+1][2];
2696 
2697 /** Note that we negotiated link protocol version <b>link_proto</b>, on
2698  * a connection that started here iff <b>started_here</b> is true.
2699  */
2700 void
2701 rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here)
2702 {
2703  started_here = !!started_here; /* force to 0 or 1 */
2704  if (link_proto > MAX_LINK_PROTO) {
2705  log_warn(LD_BUG, "Can't log link protocol %u", link_proto);
2706  return;
2707  }
2708 
2709  link_proto_count[link_proto][started_here]++;
2710 }
2711 
2712 /**
2713  * Update the maximum count of total pending channel padding timers
2714  * in this period.
2715  */
2716 void
2717 rep_hist_padding_count_timers(uint64_t num_timers)
2718 {
2719  if (num_timers > padding_current.maximum_chanpad_timers) {
2721  }
2722 }
2723 
2724 /**
2725  * Count a cell that we sent for padding overhead statistics.
2726  *
2727  * RELAY_COMMAND_DROP and CELL_PADDING are accounted separately. Both should be
2728  * counted for PADDING_TYPE_TOTAL.
2729  */
2730 void
2732 {
2733  switch (type) {
2734  case PADDING_TYPE_DROP:
2736  break;
2737  case PADDING_TYPE_CELL:
2739  break;
2740  case PADDING_TYPE_TOTAL:
2742  break;
2745  break;
2748  break;
2749  }
2750 }
2751 
2752 /**
2753  * Count a cell that we've received for padding overhead statistics.
2754  *
2755  * RELAY_COMMAND_DROP and CELL_PADDING are accounted separately. Both should be
2756  * counted for PADDING_TYPE_TOTAL.
2757  */
2758 void
2760 {
2761  switch (type) {
2762  case PADDING_TYPE_DROP:
2764  break;
2765  case PADDING_TYPE_CELL:
2767  break;
2768  case PADDING_TYPE_TOTAL:
2770  break;
2773  break;
2776  break;
2777  }
2778 }
2779 
2780 /**
2781  * Reset our current padding statistics. Called once every 24 hours.
2782  */
2783 void
2785 {
2786  memset(&padding_current, 0, sizeof(padding_current));
2787 }
2788 
2789 /**
2790  * Copy our current cell counts into a structure for listing in our
2791  * extra-info descriptor. Also perform appropriate rounding and redaction.
2792  *
2793  * This function is called once every 24 hours.
2794  */
2795 #define MIN_CELL_COUNTS_TO_PUBLISH 1
2796 #define ROUND_CELL_COUNTS_TO 10000
2797 void
2798 rep_hist_prep_published_padding_counts(time_t now)
2799 {
2801 
2804  memset(&padding_published, 0, sizeof(padding_published));
2805  return;
2806  }
2807 
2809 #define ROUND_AND_SET_COUNT(x) (x) = round_uint64_to_next_multiple_of((x), \
2810  ROUND_CELL_COUNTS_TO)
2811  ROUND_AND_SET_COUNT(padding_published.read_pad_cell_count);
2812  ROUND_AND_SET_COUNT(padding_published.write_pad_cell_count);
2813  ROUND_AND_SET_COUNT(padding_published.read_drop_cell_count);
2814  ROUND_AND_SET_COUNT(padding_published.write_drop_cell_count);
2815  ROUND_AND_SET_COUNT(padding_published.write_cell_count);
2816  ROUND_AND_SET_COUNT(padding_published.read_cell_count);
2817  ROUND_AND_SET_COUNT(padding_published.enabled_read_cell_count);
2818  ROUND_AND_SET_COUNT(padding_published.enabled_read_pad_cell_count);
2819  ROUND_AND_SET_COUNT(padding_published.enabled_write_cell_count);
2820  ROUND_AND_SET_COUNT(padding_published.enabled_write_pad_cell_count);
2821 #undef ROUND_AND_SET_COUNT
2822 }
2823 
2824 /**
2825  * Returns an allocated string for extra-info documents for publishing
2826  * padding statistics from the last 24 hour interval.
2827  */
2828 char *
2830 {
2831  char *result = NULL;
2832 
2835  return NULL;
2836  }
2837 
2838  tor_asprintf(&result, "padding-counts %s (%d s)"
2839  " bin-size=%"PRIu64
2840  " write-drop=%"PRIu64
2841  " write-pad=%"PRIu64
2842  " write-total=%"PRIu64
2843  " read-drop=%"PRIu64
2844  " read-pad=%"PRIu64
2845  " read-total=%"PRIu64
2846  " enabled-read-pad=%"PRIu64
2847  " enabled-read-total=%"PRIu64
2848  " enabled-write-pad=%"PRIu64
2849  " enabled-write-total=%"PRIu64
2850  " max-chanpad-timers=%"PRIu64
2851  "\n",
2854  (uint64_t)ROUND_CELL_COUNTS_TO,
2866  );
2867 
2868  return result;
2869 }
2870 
2871 /** Log a heartbeat message explaining how many connections of each link
2872  * protocol version we have used.
2873  */
2874 void
2876 {
2877  smartlist_t *lines = smartlist_new();
2878 
2879  for (int i = 1; i <= MAX_LINK_PROTO; i++) {
2880  char *line = NULL;
2881  tor_asprintf(&line, "initiated %"PRIu64" and received "
2882  "%"PRIu64" v%d connections", link_proto_count[i][1],
2883  link_proto_count[i][0], i);
2884  smartlist_add(lines, line);
2885  }
2886 
2887  char *log_line = smartlist_join_strings(lines, "; ", 0, NULL);
2888 
2889  log_notice(LD_HEARTBEAT, "Since startup we %s.", log_line);
2890 
2891  SMARTLIST_FOREACH(lines, char *, s, tor_free(s));
2892  smartlist_free(lines);
2893  tor_free(log_line);
2894 }
2895 
2896 /** Free all storage held by the OR/link history caches, by the
2897  * bandwidth history arrays, by the port history, or by statistics . */
2898 void
2900 {
2901  hs_stats_free(hs_stats);
2902  digestmap_free(history_map, free_or_history);
2903 
2904  bw_array_free(read_array);
2905  read_array = NULL;
2906 
2907  bw_array_free(write_array);
2908  write_array = NULL;
2909 
2910  bw_array_free(dir_read_array);
2911  dir_read_array = NULL;
2912 
2913  bw_array_free(dir_write_array);
2914  dir_write_array = NULL;
2915 
2920  bidi_map_free_all();
2921 
2924  tor_free(s));
2925  smartlist_free(circuits_for_buffer_stats);
2927  }
2930 
2931  tor_assert_nonfatal(rephist_total_alloc == 0);
2932  tor_assert_nonfatal_once(rephist_total_num == 0);
2933 }
void rep_hist_free_all(void)
Definition: rephist.c:2899
#define NUM_SECS_BW_SUM_INTERVAL
Definition: rephist.c:980
uint64_t read_pad_cell_count
Definition: rephist.c:159
void rep_hist_desc_stats_init(time_t now)
Definition: rephist.c:2079
void rep_hist_note_bytes_read(uint64_t num_bytes, time_t when)
Definition: rephist.c:1166
void rep_hist_padding_count_timers(uint64_t num_timers)
Definition: rephist.c:2717
time_t start_of_run
Definition: rephist.c:141
Header for statefile.c.
static digestmap_t * history_map
Definition: rephist.c:196
int tor_sscanf(const char *buf, const char *pattern,...)
Definition: scanf.c:309
uint64_t read_drop_cell_count
Definition: rephist.c:171
uint64_t rephist_total_alloc
Definition: rephist.c:104
char * rep_hist_format_conn_stats(time_t now)
Definition: rephist.c:2383
static uint32_t mostly_written
Definition: rephist.c:2253
void rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
Definition: rephist.c:1176
int64_t add_laplace_noise(int64_t signal_, double random_, double delta_f, double epsilon)
Definition: laplace.c:51
time_t rep_hist_downrate_old_runs(time_t now)
Definition: rephist.c:382
static hs_stats_t * hs_stats_new(void)
Definition: rephist.c:2495
Common functions for using (pseudo-)random number generators.
Definition: node_st.h:34
static uint32_t * exit_streams
Definition: rephist.c:1551
#define NUM_TOTALS
Definition: rephist.c:984
static hs_stats_t * hs_stats
Definition: rephist.c:2491
uint32_t processed_cells
Definition: rephist.c:1828
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
void rep_hist_reset_exit_stats(time_t now)
Definition: rephist.c:1568
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
void tor_addr_make_unspec(tor_addr_t *a)
Definition: address.c:225
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:110
void rep_hist_exit_stats_term(void)
Definition: rephist.c:1579
Header for laplace.c.
long rep_hist_get_uptime(const char *id, time_t when)
Definition: rephist.c:490
static uint32_t both_read_and_written
Definition: rephist.c:2258
#define EXIT_STATS_NUM_PORTS
Definition: rephist.c:1538
void format_local_iso_time(char *buf, time_t t)
Definition: time_fmt.c:285
void rep_hist_note_exit_stream_opened(uint16_t port)
Definition: rephist.c:1799
double mean_num_cells_in_queue
Definition: rephist.c:1824
int rep_hist_have_measured_enough_stability(void)
Definition: rephist.c:543
void rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
Definition: rephist.c:1857
int rep_hist_load_mtbf_data(time_t now)
Definition: rephist.c:789
#define LD_GENERAL
Definition: log.h:62
#define NUM_SECS_ROLLING_MEASURE
Definition: rephist.c:978
#define CIRCUIT_IS_ORIGIN(c)
Definition: circuitlist.h:146
void rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here)
Definition: rephist.c:2701
uint64_t max_total
Definition: rephist.c:997
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, tor_addr_comparison_t how)
Definition: address.c:954
int authdir_mode(const or_options_t *options)
Definition: authmode.c:25
static HT_HEAD(bidimap, bidi_map_entry_t)
Definition: rephist.c:2271
double mean_time_cells_in_queue
Definition: rephist.c:1826
static void hs_stats_free_(hs_stats_t *victim_hs_stats)
Definition: rephist.c:2508
void rep_hist_conn_stats_term(void)
Definition: rephist.c:2320
Header file for nodelist.c.
static void rep_hist_reset_hs_stats(time_t now)
Definition: rephist.c:2532
char first_published_at[ISO_TIME_LEN+1]
Definition: rephist.c:177
void tor_log(int severity, log_domain_mask_t domain, const char *format,...)
Definition: log.c:628
char * rep_hist_get_bandwidth_lines(void)
Definition: rephist.c:1281
void smartlist_add(smartlist_t *sl, void *element)
void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr, const uint16_t at_port, time_t when)
Definition: rephist.c:241
#define STABILITY_EPSILON
Definition: rephist.c:110
uint64_t RelayBandwidthRate
static size_t rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
Definition: rephist.c:1232
static or_history_t * get_or_history(const char *id)
Definition: rephist.c:201
static time_t stability_last_downrated
Definition: rephist.c:190
int connection_or_digest_is_known_relay(const char *id_digest)
static digestmap_t * served_descs
Definition: rephist.c:2068
void rep_hist_add_buffer_stats(double mean_num_cells_in_queue, double mean_time_cells_in_queue, uint32_t processed_cells)
Definition: rephist.c:1838
Header file for config.c.
void rep_hist_buffer_stats_init(time_t now)
Definition: rephist.c:1815
#define STABILITY_INTERVAL
Definition: rephist.c:115
const or_options_t * get_options(void)
Definition: config.c:926
#define tor_assert(expr)
Definition: util_bug.h:102
void rep_hist_note_desc_served(const char *desc)
Definition: rephist.c:2200
void rep_hist_log_link_protocol_counts(void)
Definition: rephist.c:2875
void rep_history_clean(time_t before)
Definition: rephist.c:593
#define EXIT_STATS_ROUND_UP_BYTES
Definition: rephist.c:1534
double crypto_rand_double(void)
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:206
static double get_weighted_fractional_uptime(or_history_t *hist, time_t when)
Definition: rephist.c:463
#define tor_free(p)
Definition: malloc.h:52
void rep_hist_buffer_stats_term(void)
Definition: rephist.c:1907
STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1]
Definition: rephist.c:2437
void rep_hist_exit_stats_init(time_t now)
Definition: rephist.c:1558
#define REPHIST_CELL_PADDING_COUNTS_INTERVAL
Definition: rephist.h:125
uint32_t rephist_total_num
Definition: rephist.c:106
uint64_t totals[NUM_TOTALS]
Definition: rephist.c:1015
time_t rep_hist_hs_stats_write(time_t now)
Definition: rephist.c:2666
uint64_t read_cell_count
Definition: rephist.c:155
struct timeval timestamp_created
Definition: circuit_st.h:168
static time_t start_of_hs_stats_interval
Definition: rephist.c:2477
smartlist_t * smartlist_new(void)
time_t since
Definition: rephist.c:124
uint64_t maximum_chanpad_timers
Definition: rephist.c:175
#define EXIT_STATS_ROUND_UP_STREAMS
Definition: rephist.c:1536
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
static uint32_t below_threshold
Definition: rephist.c:2245
void rep_hist_reset_buffer_stats(time_t now)
Definition: rephist.c:1915
#define STATIC
Definition: testsupport.h:32
static long get_total_weighted_time(or_history_t *hist, time_t when)
Definition: rephist.c:449
int write_to_data_subdir(const char *subdir, const char *fname, const char *str, const char *descr)
Definition: config.c:7178
FILE * start_writing_to_stdio_file(const char *fname, int open_flags, int mode, open_file_t **data_out)
Definition: files.c:382
double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when)
Definition: rephist.c:515
static int n_bogus_times
Definition: rephist.c:744
padding_type_t
Definition: rephist.h:111
Definition: rephist.c:2262
Header file for directory authority mode.
void rep_hist_padding_count_read(padding_type_t type)
Definition: rephist.c:2759
smartlist_t * circuit_get_global_list(void)
Definition: circuitlist.c:691
char * rep_hist_format_buffer_stats(time_t now)
Definition: rephist.c:1929
STATIC void commit_max(bw_array_t *b)
Definition: rephist.c:1020
networkstatus_t * networkstatus_get_latest_consensus(void)
uint32_t processed_cells
Definition: or_circuit_st.h:68
digestmap_t * onions_seen_this_period
Definition: rephist.c:2487
static bw_array_t * bw_array_new(void)
Definition: rephist.c:1087
static time_t bidi_next_interval
Definition: rephist.c:2241
time_t cur_obs_time
Definition: rephist.c:994
time_t rep_hist_conn_stats_write(time_t now)
Definition: rephist.c:2408
uint64_t enabled_read_cell_count
Definition: rephist.c:163
static char * rep_hist_format_hs_stats(time_t now)
Definition: rephist.c:2620
int next_max_idx
Definition: rephist.c:1006
void rep_hist_update_state(or_state_t *state)
Definition: rephist.c:1398
time_t changed
Definition: rephist.c:126
void rep_hist_reset_padding_counts(void)
Definition: rephist.c:2784
static int buffer_stats_compare_entries_(const void **_a, const void **_b)
Definition: rephist.c:1893
const char * node_get_nickname(const node_t *node)
Definition: nodelist.c:1301
static padding_counts_t padding_current
Definition: rephist.c:182
uint64_t obs[NUM_SECS_ROLLING_MEASURE]
Definition: rephist.c:992
void rep_hist_desc_stats_term(void)
Definition: rephist.c:2102
int append_bytes_to_file(const char *fname, const char *str, size_t len, int bin)
Definition: files.c:538
Header file for routermode.c.
int finish_writing_to_file(open_file_t *file_data)
Definition: files.c:449
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
static smartlist_t * circuits_for_buffer_stats
Definition: rephist.c:1832
uint64_t write_cell_count
Definition: rephist.c:157
#define DIGEST_LEN
Definition: digest_sizes.h:20
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
Master header file for Tor-specific functionality.
void rep_hist_dump_stats(time_t now, int severity)
Definition: rephist.c:554
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
Definition: muldiv.c:50
const char * hex_str(const char *from, size_t fromlen)
Definition: binascii.c:34
HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq, 0.6, tor_reallocarray, tor_free_) static void cdm_diff_free_(cdm_diff_t *diff)
Definition: consdiffmgr.c:222
time_t next_period
Definition: rephist.c:1003
void rep_hist_note_circuit_handshake_assigned(uint16_t type)
Definition: rephist.c:2452
long rep_hist_get_weighted_time_known(const char *id, time_t when)
Definition: rephist.c:531
time_t rep_hist_buffer_stats_write(time_t now)
Definition: rephist.c:2032
const node_t * node_get_by_id(const char *identity_digest)
Definition: nodelist.c:223
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)
Definition: rephist.c:1422
Header file for rephist.c.
uint64_t enabled_read_pad_cell_count
Definition: rephist.c:167
int tor_addr_is_null(const tor_addr_t *addr)
Definition: address.c:770
void rep_hist_note_circuit_handshake_requested(uint16_t type)
Definition: rephist.c:2443
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:478
void tor_free_(void *mem)
Definition: malloc.c:227
void rep_hist_hs_stats_term(void)
Definition: rephist.c:2549
static uint32_t mostly_read
Definition: rephist.c:2249
double rep_hist_get_stability(const char *id, time_t when)
Definition: rephist.c:503
void rep_hist_hs_stats_init(time_t now)
Definition: rephist.c:2520
void rep_hist_init(void)
Definition: rephist.c:232
#define RFTS_IGNORE_MISSING
Definition: files.h:97
Header file for circuitlist.c.
static void free_or_history(void *_hist)
Definition: rephist.c:222
int tor_digest_is_zero(const char *digest)
Definition: util_string.c:96
static int find_next_with(smartlist_t *sl, int i, const char *prefix)
Definition: rephist.c:731
#define STABILITY_ALPHA
Definition: rephist.c:113
Header for order.c.
static uint64_t * exit_bytes_read
Definition: rephist.c:1547
uint64_t write_pad_cell_count
Definition: rephist.c:161
static bw_array_t * read_array
Definition: rephist.c:1115
int rep_hist_load_state(or_state_t *state, char **err)
Definition: rephist.c:1498
static int parse_possibly_bad_iso_time(const char *s, time_t *time_out)
Definition: rephist.c:748
#define HEX_DIGEST_LEN
Definition: crypto_digest.h:35
STATIC uint64_t find_largest_max(bw_array_t *b)
Definition: rephist.c:1195
static unsigned long total_descriptor_downloads
Definition: rephist.c:2072
static bw_array_t * dir_write_array
Definition: rephist.c:1123
void rep_hist_conn_stats_init(time_t now)
Definition: rephist.c:2222
void rep_hist_note_router_unreachable(const char *id, time_t when)
Definition: rephist.c:314
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
uint16_t last_reached_port
Definition: rephist.c:133
void format_iso_time(char *buf, time_t t)
Definition: time_fmt.c:295
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
#define EXIT_STATS_TOP_N_PORTS
Definition: rephist.c:1540
int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
Definition: crypto_rsa.c:356
void rep_hist_note_exit_bytes(uint16_t port, size_t num_written, size_t num_read)
Definition: rephist.c:1785
char * rep_hist_get_padding_count_lines(void)
Definition: rephist.c:2829
void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read, size_t num_written, time_t when)
Definition: rephist.c:2330
static time_t start_of_buffer_stats_interval
Definition: rephist.c:1811
void rep_hist_padding_count_write(padding_type_t type)
Definition: rephist.c:2731
#define SMARTLIST_FOREACH(sl, type, var, cmd)
The or_state_t structure, which represents Tor's state file.
int cur_obs_idx
Definition: rephist.c:993
char * rep_hist_format_exit_stats(time_t now)
Definition: rephist.c:1600
const char * escaped(const char *s)
Definition: escape.c:126
HT_PROTOTYPE(HT_GENERATE2(channel_gid_map, HT_GENERATE2(channel_t, HT_GENERATE2(gidmap_node, HT_GENERATE2(channel_id_hash, HT_GENERATE2(channel_id_eq)
Definition: channel.c:121
int num_maxes_set
Definition: rephist.c:1008
void rep_hist_note_bytes_written(uint64_t num_bytes, time_t when)
Definition: rephist.c:1149
static time_t start_of_exit_stats_interval
Definition: rephist.c:1554
#define LD_HIST
Definition: log.h:99
static time_t correct_time(time_t t, time_t now, time_t stored_at, time_t started_measuring)
Definition: rephist.c:769
#define MIN_CELL_COUNTS_TO_PUBLISH
Definition: rephist.c:2795
uint64_t total_in_period
Definition: rephist.c:999
STATIC bw_array_t * write_array
Definition: rephist.c:1117
void rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
Definition: rephist.c:1185
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:153
void rep_hist_make_router_pessimal(const char *id, time_t when)
Definition: rephist.c:368
void rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
Definition: rephist.c:2569
uint64_t enabled_write_cell_count
Definition: rephist.c:165
tor_addr_t last_reached_addr
Definition: rephist.c:130
static void bw_arrays_init(void)
Definition: rephist.c:1128
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor)
Definition: muldiv.c:35
static bw_array_t * dir_read_array
Definition: rephist.c:1120
void or_state_mark_dirty(or_state_t *state, time_t when)
Definition: statefile.c:731
time_t rep_hist_desc_stats_write(time_t now)
Definition: rephist.c:2169
static void add_obs(bw_array_t *b, time_t when, uint64_t n)
Definition: rephist.c:1066
int rep_hist_record_mtbf_data(time_t now, int missing_means_down)
Definition: rephist.c:626
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:59
int abort_writing_to_file(open_file_t *file_data)
Definition: files.c:457
void rep_hist_seen_new_rp_cell(void)
Definition: rephist.c:2556
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
unsigned long weighted_run_length
Definition: rephist.c:138
static uint64_t * exit_bytes_written
Definition: rephist.c:1549
int check_or_create_data_subdir(const char *subdir)
Definition: config.c:7159
Header file for connection_or.c.
static char * rep_hist_format_desc_stats(time_t now)
Definition: rephist.c:2115
static void rep_hist_reset_desc_stats(time_t now)
Definition: rephist.c:2093
uint64_t rp_relay_cells_seen
Definition: rephist.c:2483
uint64_t total_cell_waiting_time
Definition: or_circuit_st.h:73
uint64_t enabled_write_pad_cell_count
Definition: rephist.c:169
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:392
static time_t start_of_served_descs_stats_interval
Definition: rephist.c:2075
uint64_t write_drop_cell_count
Definition: rephist.c:173
STATIC void advance_obs(bw_array_t *b)
Definition: rephist.c:1040
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)
Definition: rephist.c:1338
int server_mode(const or_options_t *options)
Definition: routermode.c:34
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
Definition: address.c:904
void rep_hist_reset_conn_stats(time_t now)
Definition: rephist.c:2307
void predicted_ports_free_all(void)
static padding_counts_t padding_published
Definition: rephist.c:186
void rep_hist_log_circuit_handshake_stats(time_t now)
Definition: rephist.c:2460
uint64_t total_obs
Definition: rephist.c:995
void smartlist_clear(smartlist_t *sl)
uint64_t maxima[NUM_TOTALS]
Definition: rephist.c:1012
time_t rep_hist_exit_stats_write(time_t now)
Definition: rephist.c:1755
double total_run_weights
Definition: rephist.c:143
void smartlist_sort(smartlist_t *sl, int(*compare)(const void **a, const void **b))
Definition: smartlist.c:334
static time_t start_of_conn_stats_interval
Definition: rephist.c:2218
#define LD_HEARTBEAT
Definition: log.h:103
static double get_stability(or_history_t *hist, time_t when)
Definition: rephist.c:427
Header file for networkstatus.c.
#define LD_BUG
Definition: log.h:86
static void bw_array_free_(bw_array_t *b)
Definition: rephist.c:1104
Header file for predict_ports.c.
int rep_hist_bandwidth_assess(void)
Definition: rephist.c:1214
static int compare_int_(const void *x, const void *y)
Definition: rephist.c:1591
Networkstatus consensus/vote structure.
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)