tor  0.4.1.1-alpha-dev
rephist.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2  * Copyright (c) 2007-2019, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
4 
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"
87 #include "feature/stats/predict_ports.h"
88 #include "feature/stats/rephist.h"
89 #include "lib/container/order.h"
91 #include "lib/math/laplace.h"
92 
93 #include "feature/nodelist/networkstatus_st.h"
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 
106 uint32_t rephist_total_num=0;
107 
110 #define STABILITY_EPSILON 0.0001
111 
113 #define STABILITY_ALPHA 0.95
114 
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 
122 typedef struct or_history_t {
124  time_t since;
126  time_t changed;
127 
131 
134 
135  /* === For MTBF tracking: */
138  unsigned long weighted_run_length;
141  time_t start_of_run;
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 
153 typedef struct padding_counts_t {
155  uint64_t read_cell_count;
177  char first_published_at[ISO_TIME_LEN+1];
179 
183 
187 
190 static time_t stability_last_downrated = 0;
191 
193 static time_t started_tracking_stability = 0;
194 
196 static digestmap_t *history_map = NULL;
197 
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 
221 static void
222 free_or_history(void *_hist)
223 {
224  or_history_t *hist = _hist;
227  tor_free(hist);
228 }
229 
231 void
233 {
234  history_map = digestmap_new();
235  bw_arrays_init();
236 }
237 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
744 static int n_bogus_times = 0;
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 
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 
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 
978 #define NUM_SECS_ROLLING_MEASURE 10
979 
980 #define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
981 
982 #define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
983 
984 #define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
985 
989 struct bw_array_t {
994  time_t cur_obs_time;
995  uint64_t total_obs;
997  uint64_t max_total;
999  uint64_t total_in_period;
1003  time_t next_period;
1012  uint64_t maxima[NUM_TOTALS];
1015  uint64_t totals[NUM_TOTALS];
1016 };
1017 
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 
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 
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 
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 
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 
1115 static bw_array_t *read_array = NULL;
1117 STATIC bw_array_t *write_array = NULL;
1124 
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 
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 
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 
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 
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 
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 
1214 rep_hist_bandwidth_assess,(void))
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 
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 
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 
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 
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 
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 
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 */
1534 #define EXIT_STATS_ROUND_UP_BYTES 1024
1535 
1536 #define EXIT_STATS_ROUND_UP_STREAMS 4
1537 
1538 #define EXIT_STATS_NUM_PORTS 65536
1539 
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. */
1547 static uint64_t *exit_bytes_read = NULL;
1549 static uint64_t *exit_bytes_written = NULL;
1551 static uint32_t *exit_streams = NULL;
1552 
1555 
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 
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 
1578 void
1580 {
1585 }
1586 
1590 static int
1591 compare_int_(const void *x, const void *y)
1592 {
1593  return (*(int*)x - *(int*)y);
1594 }
1595 
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 
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 
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 
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 
1812 
1814 void
1816 {
1818 }
1819 
1822 typedef struct circ_buffer_stats_t {
1830 
1833 
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;
1849  circuits_for_buffer_stats = smartlist_new();
1851 }
1852 
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 
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 
1906 void
1908 {
1910 }
1911 
1914 void
1916 {
1918  circuits_for_buffer_stats = smartlist_new();
1920  stats, tor_free(stats));
1923 }
1924 
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));
1954  circuits_for_buffer_stats = smartlist_new();
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 
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. */
2042  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
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 
2068 static digestmap_t *served_descs = NULL;
2069 
2072 static unsigned long total_descriptor_downloads;
2073 
2076 
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 
2092 static void
2094 {
2097 }
2098 
2101 void
2103 {
2104  digestmap_free(served_descs, NULL);
2105  served_descs = NULL;
2108 }
2109 
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 
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 
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 
2219 
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 
2241 static time_t bidi_next_interval = 0;
2242 
2245 static uint32_t below_threshold = 0;
2246 
2249 static uint32_t mostly_read = 0;
2250 
2253 static uint32_t mostly_written = 0;
2254 
2258 static uint32_t both_read_and_written = 0;
2259 
2262 typedef struct bidi_map_entry_t {
2263  HT_ENTRY(bidi_map_entry_t) node;
2264  uint64_t conn_id;
2265  size_t read;
2266  size_t written;
2268 
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 
2306 void
2308 {
2310  below_threshold = 0;
2311  mostly_read = 0;
2312  mostly_written = 0;
2314  bidi_map_free_all();
2315 }
2316 
2319 void
2321 {
2323 }
2324 
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 
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 
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 
2437 STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
2438 STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
2442 void
2444 {
2445  if (type <= MAX_ONION_HANDSHAKE_TYPE)
2447 }
2448 
2451 void
2453 {
2454  if (type <= MAX_ONION_HANDSHAKE_TYPE)
2455  onion_handshakes_assigned[type]++;
2456 }
2457 
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 
2478 
2481 typedef struct hs_stats_t {
2484 
2488 } hs_stats_t;
2489 
2491 static hs_stats_t *hs_stats = NULL;
2492 
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 
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 
2519 void
2521 {
2522  if (!hs_stats) {
2523  hs_stats = hs_stats_new();
2524  }
2525 
2527 }
2528 
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 
2548 void
2550 {
2552 }
2553 
2555 void
2557 {
2558  if (!hs_stats) {
2559  return; // We're not collecting stats
2560  }
2561 
2563 }
2564 
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 
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 
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 
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 
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 
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 
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 
2783 void
2785 {
2786  memset(&padding_current, 0, sizeof(padding_current));
2787 }
2788 
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 
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 
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 
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
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
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 rephist_total_alloc
Definition: rephist.c:104
uint64_t read_pad_cell_count
Definition: rephist.c:159
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:28
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
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
void rep_hist_reset_exit_stats(time_t now)
Definition: rephist.c:1568
void tor_addr_make_unspec(tor_addr_t *a)
Definition: address.c:225
struct padding_counts_t padding_counts_t
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:107
void rep_hist_exit_stats_term(void)
Definition: rephist.c:1579
Header for laplace.c.
time_t cur_obs_time
Definition: rephist.c:994
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
int cur_obs_idx
Definition: rephist.c:993
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:59
#define NUM_SECS_ROLLING_MEASURE
Definition: rephist.c:978
tor_addr_t last_reached_addr
Definition: rephist.c:130
#define CIRCUIT_IS_ORIGIN(c)
Definition: circuitlist.h:145
void rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here)
Definition: rephist.c:2701
uint64_t enabled_read_pad_cell_count
Definition: rephist.c:167
uint64_t enabled_write_cell_count
Definition: rephist.c:165
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, tor_addr_comparison_t how)
Definition: address.c:953
int authdir_mode(const or_options_t *options)
Definition: authmode.c:25
static HT_HEAD(bidimap, bidi_map_entry_t)
Definition: rephist.c:2271
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.
struct circ_buffer_stats_t circ_buffer_stats_t
HT_PROTOTYPE(HT_GENERATE2(strmap_impl, HT_GENERATE2(strmap_entry_t, HT_GENERATE2(node, HT_GENERATE2(strmap_entry_hash, HT_GENERATE2(strmap_entries_eq)
Definition: map.c:87
static void rep_hist_reset_hs_stats(time_t now)
Definition: rephist.c:2532
void tor_log(int severity, log_domain_mask_t domain, const char *format,...)
Definition: log.c:632
char * rep_hist_get_bandwidth_lines(void)
Definition: rephist.c:1281
void smartlist_add(smartlist_t *sl, void *element)
unsigned long weighted_run_length
Definition: rephist.c:138
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
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
uint64_t total_in_period
Definition: rephist.c:999
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
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
digestmap_t * onions_seen_this_period
Definition: rephist.c:2487
void rep_history_clean(time_t before)
Definition: rephist.c:593
#define EXIT_STATS_ROUND_UP_BYTES
Definition: rephist.c:1534
double mean_num_cells_in_queue
Definition: rephist.c:1824
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 enabled_write_pad_cell_count
Definition: rephist.c:169
int next_max_idx
Definition: rephist.c:1006
uint16_t last_reached_port
Definition: rephist.c:133
time_t rep_hist_hs_stats_write(time_t now)
Definition: rephist.c:2666
static time_t start_of_hs_stats_interval
Definition: rephist.c:2477
#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
uint64_t maximum_chanpad_timers
Definition: rephist.c:175
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:8112
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
uint64_t totals[NUM_TOTALS]
Definition: rephist.c:1015
Definition: rephist.c:2262
Header file for directory authority mode.
void rep_hist_padding_count_read(padding_type_t type)
Definition: rephist.c:2759
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
static bw_array_t * bw_array_new(void)
Definition: rephist.c:1087
uint64_t total_cell_waiting_time
Definition: or_circuit_st.h:71
static time_t bidi_next_interval
Definition: rephist.c:2241
time_t rep_hist_conn_stats_write(time_t now)
Definition: rephist.c:2408
static char * rep_hist_format_hs_stats(time_t now)
Definition: rephist.c:2620
uint64_t write_pad_cell_count
Definition: rephist.c:161
void rep_hist_update_state(or_state_t *state)
Definition: rephist.c:1398
void rep_hist_reset_padding_counts(void)
Definition: rephist.c:2784
tor_assert(buffer)
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:1290
struct hs_stats_t hs_stats_t
static padding_counts_t padding_current
Definition: rephist.c:182
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
uint64_t read_drop_cell_count
Definition: rephist.c:171
static smartlist_t * circuits_for_buffer_stats
Definition: rephist.c:1832
struct or_history_t or_history_t
#define DIGEST_LEN
Definition: digest_sizes.h:20
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
uint64_t read_cell_count
Definition: rephist.c:155
uint32_t processed_cells
Definition: rephist.c:1828
Master header file for Tor-specific functionality.
void rep_hist_dump_stats(time_t now, int severity)
Definition: rephist.c:554
uint64_t rp_relay_cells_seen
Definition: rephist.c:2483
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
void rep_hist_note_circuit_handshake_assigned(uint16_t type)
Definition: rephist.c:2452
uint64_t max_total
Definition: rephist.c:997
uint32_t processed_cells
Definition: or_circuit_st.h:66
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
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.
int tor_addr_is_null(const tor_addr_t *addr)
Definition: address.c:769
double total_run_weights
Definition: rephist.c:143
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
double mean_time_cells_in_queue
Definition: rephist.c:1826
void rep_hist_init(void)
Definition: rephist.c:232
#define RFTS_IGNORE_MISSING
Definition: files.h:97
Header file for circuitlist.c.
MOCK_IMPL(int, rep_hist_bandwidth_assess,(void))
Definition: rephist.c:1213
static void free_or_history(void *_hist)
Definition: rephist.c:222
int tor_digest_is_zero(const char *digest)
Definition: util_string.c:96
uint64_t write_cell_count
Definition: rephist.c:157
time_t since
Definition: rephist.c:124
static int find_next_with(smartlist_t *sl, int i, const char *prefix)
Definition: rephist.c:731
#define STABILITY_ALPHA
Definition: rephist.c:113
uint64_t obs[NUM_SECS_ROLLING_MEASURE]
Definition: rephist.c:992
Header for order.c.
static uint64_t * exit_bytes_read
Definition: rephist.c:1547
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
char first_published_at[ISO_TIME_LEN+1]
Definition: rephist.c:177
struct bidi_map_entry_t bidi_map_entry_t
uint64_t write_drop_cell_count
Definition: rephist.c:173
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
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)
char * rep_hist_format_exit_stats(time_t now)
Definition: rephist.c:1600
const char * escaped(const char *s)
Definition: escape.c:126
time_t next_period
Definition: rephist.c:1003
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:96
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
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:151
void rep_hist_make_router_pessimal(const char *id, time_t when)
Definition: rephist.c:368
time_t changed
Definition: rephist.c:126
void rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
Definition: rephist.c:2569
uint64_t total_obs
Definition: rephist.c:995
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:715
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:56
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
struct timeval timestamp_created
Definition: circuit_st.h:146
static uint64_t * exit_bytes_written
Definition: rephist.c:1549
int check_or_create_data_subdir(const char *subdir)
Definition: config.c:8093
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
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
time_t start_of_run
Definition: rephist.c:141
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
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
Definition: address.c:903
uint64_t RelayBandwidthRate
void rep_hist_reset_conn_stats(time_t now)
Definition: rephist.c:2307
void predicted_ports_free_all(void)
uint64_t enabled_read_cell_count
Definition: rephist.c:163
int num_maxes_set
Definition: rephist.c:1008
static padding_counts_t padding_published
Definition: rephist.c:186
uint64_t maxima[NUM_TOTALS]
Definition: rephist.c:1012
void rep_hist_log_circuit_handshake_stats(time_t now)
Definition: rephist.c:2460
void smartlist_clear(smartlist_t *sl)
time_t rep_hist_exit_stats_write(time_t now)
Definition: rephist.c:1755
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:100
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:83
static void bw_array_free_(bw_array_t *b)
Definition: rephist.c:1104
static int compare_int_(const void *x, const void *y)
Definition: rephist.c:1591
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)