Back to index

tor  0.2.3.19-rc
Functions
rephist.h File Reference

Header file for rephist.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void rep_hist_init (void)
 Initialize the static data structures for tracking history.
void rep_hist_note_connect_failed (const char *nickname, time_t when)
 Remember that an attempt to connect to the OR with identity digest id failed at when.
void rep_hist_note_connect_succeeded (const char *nickname, time_t when)
 Remember that an attempt to connect to the OR with identity digest id succeeded at when.
void rep_hist_note_disconnect (const char *nickname, time_t when)
 Remember that we intentionally closed our connection to the OR with identity digest id at when.
void rep_hist_note_connection_died (const char *nickname, time_t when)
 Remember that our connection to the OR with identity digest id had an error and stopped working at when.
void rep_hist_note_extend_succeeded (const char *from_name, const char *to_name)
 Remember that we successfully extended from the OR with identity digest from_id to the OR with identity digest to_name.
void rep_hist_note_extend_failed (const char *from_name, const char *to_name)
 Remember that we tried to extend from the OR with identity digest from_id to the OR with identity digest to_name, but failed.
void rep_hist_dump_stats (time_t now, int severity)
 Log all the reliability data we have remembered, with the chosen severity.
void rep_hist_note_bytes_read (size_t num_bytes, time_t when)
 Remember that we wrote num_bytes bytes in second when.
void rep_hist_note_bytes_written (size_t num_bytes, time_t when)
 Remember that we read num_bytes bytes in second when.
void rep_hist_note_dir_bytes_read (size_t num_bytes, time_t when)
 Remember that we read num_bytes directory bytes in second when.
void rep_hist_note_dir_bytes_written (size_t num_bytes, time_t when)
 Remember that we wrote num_bytes directory bytes in second when.
int rep_hist_bandwidth_assess (void)
 Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly) seconds.
char * rep_hist_get_bandwidth_lines (void)
 Allocate and return lines for representing this server's bandwidth history in its descriptor.
void rep_hist_update_state (or_state_t *state)
 Update state with the newest bandwidth history.
int rep_hist_load_state (or_state_t *state, char **err)
 Set bandwidth history from the state file we just loaded.
void rep_history_clean (time_t before)
 Remove history info for routers/links that haven't changed since before.
void rep_hist_note_router_reachable (const char *id, const tor_addr_t *at_addr, const uint16_t at_port, time_t when)
 We have just decided that this router with identity digest id is reachable, meaning we will give it a "Running" flag for the next while.
void rep_hist_note_router_unreachable (const char *id, time_t when)
 We have just decided that this router is unreachable, meaning we are taking away its "Running" flag.
int rep_hist_record_mtbf_data (time_t now, int missing_means_down)
 Write MTBF data to disk.
int rep_hist_load_mtbf_data (time_t now)
 Load MTBF data from disk.
time_t rep_hist_downrate_old_runs (time_t now)
 Helper: Discount all old MTBF data, if it is time to do so.
long rep_hist_get_uptime (const char *id, time_t when)
 Return how long the router whose identity digest is id has been reachable.
double rep_hist_get_stability (const char *id, time_t when)
 Return an estimated MTBF for the router whose identity digest is id.
double rep_hist_get_weighted_fractional_uptime (const char *id, time_t when)
 Return an estimated percent-of-time-online for the router whose identity digest is id.
long rep_hist_get_weighted_time_known (const char *id, time_t when)
 Return a number representing how long we've known about the router whose digest is id.
int rep_hist_have_measured_enough_stability (void)
 Return true if we've been measuring MTBFs for long enough to pronounce on Stability.
const char * rep_hist_get_router_stability_doc (time_t now)
 Return a pointer to a NUL-terminated document describing our view of the stability of the routers we've been tracking.
void rep_hist_note_used_port (time_t now, uint16_t port)
 Remember that port has been asked for as of time now.
smartlist_trep_hist_get_predicted_ports (time_t now)
 Return a newly allocated pointer to a list of uint16_t * for ports that are likely to be asked for in the near future.
void rep_hist_remove_predicted_ports (const smartlist_t *rmv_ports)
 Take a list of uint16_t *, and remove every port in the list from the current list of predicted ports.
void rep_hist_note_used_resolve (time_t now)
 The user asked us to do a resolve.
void rep_hist_note_used_internal (time_t now, int need_uptime, int need_capacity)
 Remember that we used an internal circ at time now.
int rep_hist_get_predicted_internal (time_t now, int *need_uptime, int *need_capacity)
 Return 1 if we've used an internal circ recently; else return 0.
int any_predicted_circuits (time_t now)
 Any ports used lately? These are pre-seeded if we just started up or if we're running a hidden service.
int rep_hist_circbuilding_dormant (time_t now)
 Return 1 if we have no need for circuits currently, else return 0.
void note_crypto_pk_op (pk_op_t operation)
 Increment the count of the number of times we've done operation.
void dump_pk_ops (int severity)
 Log the number of times we've done each public/private-key operation.
void rep_hist_free_all (void)
 Free all storage held by the OR/link history caches, by the bandwidth history arrays, by the port history, or by statistics .
void rep_hist_exit_stats_init (time_t now)
 Initialize exit port stats.
void rep_hist_reset_exit_stats (time_t now)
 Reset counters for exit port statistics.
void rep_hist_exit_stats_term (void)
 Stop collecting exit port stats in a way that we can re-start doing so in rep_hist_exit_stats_init().
char * rep_hist_format_exit_stats (time_t now)
 Return a newly allocated string containing the exit port statistics until now, or NULL if we're not collecting exit stats.
time_t rep_hist_exit_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current exit port stats period, write exit stats to $DATADIR/stats/exit-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_note_exit_bytes (uint16_t port, size_t num_written, size_t num_read)
 Note that we wrote num_written bytes and read num_read bytes to/from an exit connection to port.
void rep_hist_note_exit_stream_opened (uint16_t port)
 Note that we opened an exit stream to port.
void rep_hist_buffer_stats_init (time_t now)
 Initialize buffer stats.
void rep_hist_buffer_stats_add_circ (circuit_t *circ, time_t end_of_interval)
 Remember cell statistics for circuit circ at time end_of_interval and reset cell counters in case the circuit remains open in the next measurement interval.
time_t rep_hist_buffer_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current buffer stats period, write buffer stats to $DATADIR/stats/buffer-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_buffer_stats_term (void)
 Stop collecting cell stats in a way that we can re-start doing so in rep_hist_buffer_stats_init().
void rep_hist_add_buffer_stats (double mean_num_cells_in_queue, double mean_time_cells_in_queue, uint32_t processed_cells)
 Remember cell statistics mean_num_cells_in_queue, mean_time_cells_in_queue, and processed_cells of a circuit.
char * rep_hist_format_buffer_stats (time_t now)
 Return a newly allocated string containing the buffer statistics until now, or NULL if we're not collecting buffer stats.
void rep_hist_reset_buffer_stats (time_t now)
 Clear history of circuit statistics and set the measurement interval start to now.
void rep_hist_desc_stats_init (time_t now)
 Initialize descriptor stats.
void rep_hist_note_desc_served (const char *desc)
void rep_hist_desc_stats_term (void)
 Stop collecting served descs stats, so that rep_hist_desc_stats_init() is safe to be called again.
time_t rep_hist_desc_stats_write (time_t now)
 If WRITE_STATS_INTERVAL seconds have passed since the beginning of the current served desc stats interval, write the stats to $DATADIR/stats/served-desc-stats (possibly appending to an existing file) and reset the state for the next interval.
void rep_hist_conn_stats_init (time_t now)
 Initialize connection stats.
void rep_hist_note_or_conn_bytes (uint64_t conn_id, size_t num_read, size_t num_written, time_t when)
 We read num_read bytes and wrote num_written from/to OR connection conn_id in second when.
void rep_hist_reset_conn_stats (time_t now)
 Reset counters for conn statistics.
char * rep_hist_format_conn_stats (time_t now)
 Return a newly allocated string containing the connection statistics until now, or NULL if we're not collecting conn stats.
time_t rep_hist_conn_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current conn stats period, write conn stats to $DATADIR/stats/conn-stats (possibly overwriting an existing file) and reset counters.
void rep_hist_conn_stats_term (void)
 Stop collecting connection stats in a way that we can re-start doing so in rep_hist_conn_stats_init().

Detailed Description

Header file for rephist.c.

Definition in file rephist.h.


Function Documentation

int any_predicted_circuits ( time_t  now)

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

Definition at line 1947 of file rephist.c.

Here is the caller graph for this function:

void dump_pk_ops ( int  severity)

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

Definition at line 2042 of file rephist.c.

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

Here is the caller graph for this function:

void note_crypto_pk_op ( pk_op_t  operation)

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

Definition at line 1998 of file rephist.c.

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

Here is the caller graph for this function:

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

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

Definition at line 2387 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_bandwidth_assess ( void  )

Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly) seconds.

Find one sum for reading and one for writing. They don't have to be at the same time.

Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.

Definition at line 1458 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_buffer_stats_add_circ ( circuit_t circ,
time_t  end_of_interval 
)

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

Definition at line 2406 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_buffer_stats_init ( time_t  now)

Initialize buffer stats.

Definition at line 2364 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_buffer_stats_term ( void  )

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

Definition at line 2456 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_buffer_stats_write ( time_t  now)

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

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

Definition at line 2581 of file rephist.c.

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

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

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_circbuilding_dormant ( time_t  now)

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

Definition at line 1955 of file rephist.c.

{
  if (any_predicted_circuits(now))
    return 0;

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

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_conn_stats_init ( time_t  now)

Initialize connection stats.

Definition at line 2779 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_conn_stats_term ( void  )

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

Definition at line 2877 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_conn_stats_write ( time_t  now)

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

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

Definition at line 2965 of file rephist.c.

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

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_desc_stats_init ( time_t  now)

Initialize descriptor stats.

Definition at line 2635 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_desc_stats_term ( void  )

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

Definition at line 2658 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_desc_stats_write ( time_t  now)

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

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

Definition at line 2725 of file rephist.c.

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

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

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

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

  rep_hist_reset_desc_stats(now);

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

Here is the call graph for this function:

Here is the caller graph for this function:

time_t rep_hist_downrate_old_runs ( time_t  now)

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

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

Definition at line 428 of file rephist.c.

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

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

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

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

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

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

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

  return stability_last_downrated + STABILITY_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_dump_stats ( time_t  now,
int  severity 
)

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

Definition at line 632 of file rephist.c.

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

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

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

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

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

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

        link_history = (link_history_t*) link_history_p;

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_exit_stats_init ( time_t  now)

Initialize exit port stats.

Definition at line 2097 of file rephist.c.

Here is the caller graph for this function:

void rep_hist_exit_stats_term ( void  )

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

Definition at line 2121 of file rephist.c.

Here is the caller graph for this function:

time_t rep_hist_exit_stats_write ( time_t  now)

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

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

Definition at line 2297 of file rephist.c.

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

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

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_buffer_stats ( time_t  now)

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

Caller must ensure start_of_buffer_stats_interval is in the past.

Definition at line 2478 of file rephist.c.

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

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

  tor_assert(now >= start_of_buffer_stats_interval);

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_conn_stats ( time_t  now)

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

Caller must ensure start_of_conn_stats_interval is in the past.

Definition at line 2940 of file rephist.c.

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

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

  tor_assert(now >= start_of_conn_stats_interval);

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

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_format_exit_stats ( time_t  now)

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

Caller must ensure start_of_exit_stats_interval is in the past.

Definition at line 2142 of file rephist.c.

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

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

  tor_assert(now >= start_of_exit_stats_interval);

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_free_all ( void  )

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

Definition at line 3000 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

char* rep_hist_get_bandwidth_lines ( void  )

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

We publish these lines in our extra-info descriptor.

Definition at line 1525 of file rephist.c.

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

Definition at line 1927 of file rephist.c.

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

Here is the caller graph for this function:

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

Definition at line 1856 of file rephist.c.

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

const char* rep_hist_get_router_stability_doc ( time_t  now)

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

Return NULL on failure.

Definition at line 922 of file rephist.c.

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

  if (!history_map)
    return NULL;

  tor_free(last_stability_doc);
  chunks = smartlist_new();

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

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

  } DIGESTMAP_FOREACH_END;

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

double rep_hist_get_stability ( const char *  id,
time_t  when 
)

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

Return 0 if the router is unknown.

Definition at line 549 of file rephist.c.

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

  return get_stability(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

long rep_hist_get_uptime ( const char *  id,
time_t  when 
)

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

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

Definition at line 536 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

double rep_hist_get_weighted_fractional_uptime ( const char *  id,
time_t  when 
)

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

Return 0 if the router is unknown.

Definition at line 561 of file rephist.c.

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

  return get_weighted_fractional_uptime(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

long rep_hist_get_weighted_time_known ( const char *  id,
time_t  when 
)

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

Return 0 if the router is unknown.

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

Definition at line 577 of file rephist.c.

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

  return get_total_weighted_time(hist, when);
}

Here is the call graph for this function:

Here is the caller graph for this function:

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

Definition at line 589 of file rephist.c.

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

Here is the caller graph for this function:

void rep_hist_init ( void  )

Initialize the static data structures for tracking history.

Definition at line 199 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_load_mtbf_data ( time_t  now)

Load MTBF data from disk.

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

Definition at line 1048 of file rephist.c.

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

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

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

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

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

  n_bogus_times = 0;

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

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

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

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

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

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

  stability_last_downrated = last_downrated;
  started_tracking_stability = tracked_since;

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

Here is the call graph for this function:

Here is the caller graph for this function:

int rep_hist_load_state ( or_state_t state,
char **  err 
)

Set bandwidth history from the state file we just loaded.

Definition at line 1741 of file rephist.c.

{
  int all_ok = 1;

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_bytes_read ( size_t  num_bytes,
time_t  when 
)

Remember that we wrote num_bytes bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1410 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_bytes_written ( size_t  num_bytes,
time_t  when 
)

Remember that we read num_bytes bytes in second when.

Add num_bytes to the current running total for when.

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

Definition at line 1393 of file rephist.c.

{
/* Maybe a circular array for recent seconds, and step to a new point
 * every time a new second shows up. Or simpler is to just to have
 * a normal array and push down each item every second; it's short.
 */
/* When a new second has rolled over, compute the sum of the bytes we've
 * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
 * somewhere. See rep_hist_bandwidth_assess() below.
 */
  add_obs(write_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connect_failed ( const char *  nickname,
time_t  when 
)

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

Definition at line 239 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connect_succeeded ( const char *  nickname,
time_t  when 
)

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

Definition at line 254 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_connection_died ( const char *  nickname,
time_t  when 
)

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

Definition at line 283 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_desc_served ( const char *  desc)

Definition at line 2757 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_dir_bytes_read ( size_t  num_bytes,
time_t  when 
)

Remember that we read num_bytes directory bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1429 of file rephist.c.

{
  add_obs(dir_read_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_dir_bytes_written ( size_t  num_bytes,
time_t  when 
)

Remember that we wrote num_bytes directory bytes in second when.

(like rep_hist_note_bytes_written() above)

Definition at line 1420 of file rephist.c.

{
  add_obs(dir_write_array, when, num_bytes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_disconnect ( const char *  nickname,
time_t  when 
)

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

Definition at line 269 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

Definition at line 2334 of file rephist.c.

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

Here is the caller graph for this function:

void rep_hist_note_exit_stream_opened ( uint16_t  port)

Note that we opened an exit stream to port.

Definition at line 2348 of file rephist.c.

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

Here is the caller graph for this function:

void rep_hist_note_extend_failed ( const char *  from_name,
const char *  to_name 
)

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

Definition at line 617 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_extend_succeeded ( const char *  from_name,
const char *  to_name 
)

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

Definition at line 601 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

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

Definition at line 2887 of file rephist.c.

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

Here is the caller graph for this function:

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

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

Definition at line 302 of file rephist.c.

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

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

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_router_unreachable ( const char *  id,
time_t  when 
)

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

Definition at line 374 of file rephist.c.

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

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

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

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

Remember that we used an internal circ at time now.

Definition at line 1916 of file rephist.c.

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

Here is the caller graph for this function:

void rep_hist_note_used_port ( time_t  now,
uint16_t  port 
)

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

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

Definition at line 1831 of file rephist.c.

{
  tor_assert(predicted_ports_list);

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_note_used_resolve ( time_t  now)

The user asked us to do a resolve.

Rather than keeping track of timings and such of resolves, we fake it for now by treating it the same way as a connection to port 80. This way we will continue to have circuits lying around if the user only uses Tor for resolves.

Definition at line 1902 of file rephist.c.

Here is the call graph for this function:

int rep_hist_record_mtbf_data ( time_t  now,
int  missing_means_down 
)

Write MTBF data to disk.

Return 0 on success, negative on failure.

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

Definition at line 765 of file rephist.c.

{
  char time_buf[ISO_TIME_LEN+1];

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

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

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

  PUT("format 2\n");

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

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

  PUT("data\n");

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

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

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

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

  PUT(".\n");

#undef PUT
#undef PRINTF

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_remove_predicted_ports ( const smartlist_t rmv_ports)

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

Definition at line 1881 of file rephist.c.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_buffer_stats ( time_t  now)

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

Definition at line 2464 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_conn_stats ( time_t  now)

Reset counters for conn statistics.

Definition at line 2864 of file rephist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_hist_reset_exit_stats ( time_t  now)

Reset counters for exit port statistics.

Definition at line 2110 of file rephist.c.

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

Here is the caller graph for this function:

void rep_hist_update_state ( or_state_t state)

Update state with the newest bandwidth history.

Done before writing out a new state file.

Definition at line 1642 of file rephist.c.

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

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

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

Here is the call graph for this function:

Here is the caller graph for this function:

void rep_history_clean ( time_t  before)

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

Definition at line 719 of file rephist.c.

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

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

    remove = authority ? (or_history->total_run_weights < STABILITY_EPSILON &&
                          !or_history->start_of_run)
                       : (or_history->changed < before);
    if (remove) {
      orhist_it = digestmap_iter_next_rmv(history_map, orhist_it);
      free_or_history(or_history);
      continue;
    }
    for (lhist_it = digestmap_iter_init(or_history->link_history_map);
         !digestmap_iter_done(lhist_it); ) {
      digestmap_iter_get(lhist_it, &d2, &link_history_p);
      link_history = link_history_p;
      if (link_history->changed < before) {
        lhist_it = digestmap_iter_next_rmv(or_history->link_history_map,
                                           lhist_it);
        rephist_total_alloc -= sizeof(link_history_t);
        tor_free(link_history);
        continue;
      }
      lhist_it = digestmap_iter_next(or_history->link_history_map,lhist_it);
    }
    orhist_it = digestmap_iter_next(history_map, orhist_it);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function: