Back to index

tor  0.2.3.19-rc
Functions
hibernate.h File Reference

Header file for hibernate.c. More...

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

Go to the source code of this file.

Functions

int accounting_parse_options (const or_options_t *options, int validate_only)
 Configure accounting start/end time settings based on options->AccountingStart.
int accounting_is_enabled (const or_options_t *options)
 If we want to manage the accounting system and potentially hibernate, return 1, else return 0.
int accounting_get_interval_length (void)
 If accounting is enabled, return how long (in seconds) this interval lasts.
void configure_accounting (time_t now)
 Initialize the accounting subsystem.
void accounting_run_housekeeping (time_t now)
 Invoked once per second.
void accounting_add_bytes (size_t n_read, size_t n_written, int seconds)
 Called from main.c to tell us that seconds seconds have passed, n_read bytes have been read, and n_written bytes have been written.
int accounting_record_bandwidth_usage (time_t now, or_state_t *state)
 Save all our bandwidth tracking information to disk.
void hibernate_begin_shutdown (void)
 A wrapper around hibernate_begin, for when we get SIGINT.
int we_are_hibernating (void)
 Return true iff we are currently hibernating.
void consider_hibernation (time_t now)
 Consider our environment and decide if it's time to start/stop hibernating.
int getinfo_helper_accounting (control_connection_t *conn, const char *question, char **answer, const char **errmsg)
 Helper function: called when we get a GETINFO request for an accounting-related key on the control connection conn.

Detailed Description

Header file for hibernate.c.

Definition in file hibernate.h.


Function Documentation

void accounting_add_bytes ( size_t  n_read,
size_t  n_written,
int  seconds 
)

Called from main.c to tell us that seconds seconds have passed, n_read bytes have been read, and n_written bytes have been written.

Definition at line 259 of file hibernate.c.

{
  n_bytes_read_in_interval += n_read;
  n_bytes_written_in_interval += n_written;
  /* If we haven't been called in 10 seconds, we're probably jumping
   * around in time. */
  n_seconds_active_in_interval += (seconds < 10) ? seconds : 0;
}

Here is the caller graph for this function:

If accounting is enabled, return how long (in seconds) this interval lasts.

Definition at line 250 of file hibernate.c.

Here is the caller graph for this function:

int accounting_is_enabled ( const or_options_t options)

If we want to manage the accounting system and potentially hibernate, return 1, else return 0.

Definition at line 240 of file hibernate.c.

{
  if (options->AccountingMax)
    return 1;
  return 0;
}

Here is the caller graph for this function:

int accounting_parse_options ( const or_options_t options,
int  validate_only 
)

Configure accounting start/end time settings based on options->AccountingStart.

Return 0 on success, -1 on failure. If validate_only is true, do not change the current settings.

Definition at line 125 of file hibernate.c.

{
  time_unit_t unit;
  int ok, idx;
  long d,h,m;
  smartlist_t *items;
  const char *v = options->AccountingStart;
  const char *s;
  char *cp;

  if (!v) {
    if (!validate_only) {
      cfg_unit = UNIT_MONTH;
      cfg_start_day = 1;
      cfg_start_hour = 0;
      cfg_start_min = 0;
    }
    return 0;
  }

  items = smartlist_new();
  smartlist_split_string(items, v, NULL,
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0);
  if (smartlist_len(items)<2) {
    log_warn(LD_CONFIG, "Too few arguments to AccountingStart");
    goto err;
  }
  s = smartlist_get(items,0);
  if (0==strcasecmp(s, "month")) {
    unit = UNIT_MONTH;
  } else if (0==strcasecmp(s, "week")) {
    unit = UNIT_WEEK;
  } else if (0==strcasecmp(s, "day")) {
    unit = UNIT_DAY;
  } else {
    log_warn(LD_CONFIG,
             "Unrecognized accounting unit '%s': only 'month', 'week',"
             " and 'day' are supported.", s);
    goto err;
  }

  switch (unit) {
  case UNIT_WEEK:
    d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL);
    if (!ok) {
      log_warn(LD_CONFIG, "Weekly accounting must begin on a day between "
               "1 (Monday) and 7 (Sunday)");
      goto err;
    }
    break;
  case UNIT_MONTH:
    d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL);
    if (!ok) {
      log_warn(LD_CONFIG, "Monthly accounting must begin on a day between "
               "1 and 28");
      goto err;
    }
    break;
  case UNIT_DAY:
    d = 0;
    break;
    /* Coverity dislikes unreachable default cases; some compilers warn on
     * switch statements missing a case.  Tell Coverity not to worry. */
    /* coverity[dead_error_begin] */
  default:
    tor_assert(0);
  }

  idx = unit==UNIT_DAY?1:2;
  if (smartlist_len(items) != (idx+1)) {
    log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.",
             s, idx, (idx>1)?"s":"");
    goto err;
  }
  s = smartlist_get(items, idx);
  h = tor_parse_long(s, 10, 0, 23, &ok, &cp);
  if (!ok) {
    log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour.");
    goto err;
  }
  if (!cp || *cp!=':') {
    log_warn(LD_CONFIG,
             "Accounting start time not parseable: not in HH:MM format");
    goto err;
  }
  m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp);
  if (!ok) {
    log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute");
    goto err;
  }
  if (!cp || *cp!='\0') {
    log_warn(LD_CONFIG,
             "Accounting start time not parseable: not in HH:MM format");
    goto err;
  }

  if (!validate_only) {
    cfg_unit = unit;
    cfg_start_day = (int)d;
    cfg_start_hour = (int)h;
    cfg_start_min = (int)m;
  }
  SMARTLIST_FOREACH(items, char *, item, tor_free(item));
  smartlist_free(items);
  return 0;
 err:
  SMARTLIST_FOREACH(items, char *, item, tor_free(item));
  smartlist_free(items);
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int accounting_record_bandwidth_usage ( time_t  now,
or_state_t state 
)

Save all our bandwidth tracking information to disk.

Return 0 on success, -1 on failure.

Definition at line 615 of file hibernate.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void accounting_run_housekeeping ( time_t  now)

Invoked once per second.

Checks whether it is time to hibernate, record bandwidth used, etc.

Definition at line 494 of file hibernate.c.

{
  if (now >= interval_end_time) {
    configure_accounting(now);
  }
  if (time_to_record_bandwidth_usage(now)) {
    if (accounting_record_bandwidth_usage(now, get_or_state())) {
      log_warn(LD_FS, "Couldn't record bandwidth usage to disk.");
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void configure_accounting ( time_t  now)

Initialize the accounting subsystem.

Definition at line 358 of file hibernate.c.

{
  time_t s_now;
  /* Try to remember our recorded usage. */
  if (!interval_start_time)
    read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and
                             * reset below.*/

  s_now = start_of_accounting_period_containing(now);

  if (!interval_start_time) {
    /* We didn't have recorded usage; Start a new interval. */
    log_info(LD_ACCT, "Starting new accounting interval.");
    reset_accounting(now);
  } else if (s_now == interval_start_time) {
    log_info(LD_ACCT, "Continuing accounting interval.");
    /* We are in the interval we thought we were in. Do nothing.*/
    interval_end_time = start_of_accounting_period_after(interval_start_time);
  } else {
    long duration =
      length_of_accounting_period_containing(interval_start_time);
    double delta = ((double)(s_now - interval_start_time)) / duration;
    if (-0.50 <= delta && delta <= 0.50) {
      /* The start of the period is now a little later or earlier than we
       * remembered.  That's fine; we might lose some bytes we could otherwise
       * have written, but better to err on the side of obeying people's
       * accounting settings. */
      log_info(LD_ACCT, "Accounting interval moved by %.02f%%; "
               "that's fine.", delta*100);
      interval_end_time = start_of_accounting_period_after(now);
    } else if (delta >= 0.99) {
      /* This is the regular time-moved-forward case; don't be too noisy
       * about it or people will complain */
      log_info(LD_ACCT, "Accounting interval elapsed; starting a new one");
      reset_accounting(now);
    } else {
      log_warn(LD_ACCT,
               "Mismatched accounting interval: moved by %.02f%%. "
               "Starting a fresh one.", delta*100);
      reset_accounting(now);
    }
  }
  accounting_set_wakeup_time();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void consider_hibernation ( time_t  now)

Consider our environment and decide if it's time to start/stop hibernating.

Definition at line 898 of file hibernate.c.

{
  int accounting_enabled = get_options()->AccountingMax != 0;
  char buf[ISO_TIME_LEN+1];

  /* If we're in 'exiting' mode, then we just shut down after the interval
   * elapses. */
  if (hibernate_state == HIBERNATE_STATE_EXITING) {
    tor_assert(shutdown_time);
    if (shutdown_time <= now) {
      log_notice(LD_GENERAL, "Clean shutdown finished. Exiting.");
      tor_cleanup();
      exit(0);
    }
    return; /* if exiting soon, don't worry about bandwidth limits */
  }

  if (hibernate_state == HIBERNATE_STATE_DORMANT) {
    /* We've been hibernating because of bandwidth accounting. */
    tor_assert(hibernate_end_time);
    if (hibernate_end_time > now && accounting_enabled) {
      /* If we're hibernating, don't wake up until it's time, regardless of
       * whether we're in a new interval. */
      return ;
    } else {
      hibernate_end_time_elapsed(now);
    }
  }

  /* Else, we aren't hibernating. See if it's time to start hibernating, or to
   * go dormant. */
  if (hibernate_state == HIBERNATE_STATE_LIVE ||
      hibernate_state == HIBERNATE_STATE_INITIAL) {
    if (hibernate_soft_limit_reached()) {
      log_notice(LD_ACCT,
                 "Bandwidth soft limit reached; commencing hibernation. "
                 "No new connections will be accepted");
      hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH, now);
    } else if (accounting_enabled && now < interval_wakeup_time) {
      format_local_iso_time(buf,interval_wakeup_time);
      log_notice(LD_ACCT,
                 "Commencing hibernation. We will wake up at %s local time.",
                 buf);
      hibernate_go_dormant(now);
    } else if (hibernate_state == HIBERNATE_STATE_INITIAL) {
      hibernate_end(HIBERNATE_STATE_LIVE);
    }
  }

  if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) {
    if (!accounting_enabled) {
      hibernate_end_time_elapsed(now);
    } else if (hibernate_hard_limit_reached()) {
      hibernate_go_dormant(now);
    } else if (hibernate_end_time <= now) {
      /* The hibernation period ended while we were still in lowbandwidth.*/
      hibernate_end_time_elapsed(now);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int getinfo_helper_accounting ( control_connection_t conn,
const char *  question,
char **  answer,
const char **  errmsg 
)

Helper function: called when we get a GETINFO request for an accounting-related key on the control connection conn.

If we can answer the request for question, then set *answer to a newly allocated string holding the result. Otherwise, set *answer to NULL.

Definition at line 965 of file hibernate.c.

{
  (void) conn;
  (void) errmsg;
  if (!strcmp(question, "accounting/enabled")) {
    *answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0");
  } else if (!strcmp(question, "accounting/hibernating")) {
    if (hibernate_state == HIBERNATE_STATE_DORMANT)
      *answer = tor_strdup("hard");
    else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH)
      *answer = tor_strdup("soft");
    else
      *answer = tor_strdup("awake");
  } else if (!strcmp(question, "accounting/bytes")) {
    tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
                 U64_PRINTF_ARG(n_bytes_read_in_interval),
                 U64_PRINTF_ARG(n_bytes_written_in_interval));
  } else if (!strcmp(question, "accounting/bytes-left")) {
    uint64_t limit = get_options()->AccountingMax;
    uint64_t read_left = 0, write_left = 0;
    if (n_bytes_read_in_interval < limit)
      read_left = limit - n_bytes_read_in_interval;
    if (n_bytes_written_in_interval < limit)
      write_left = limit - n_bytes_written_in_interval;
    tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
                 U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left));
  } else if (!strcmp(question, "accounting/interval-start")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_start_time);
  } else if (!strcmp(question, "accounting/interval-wake")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_wakeup_time);
  } else if (!strcmp(question, "accounting/interval-end")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_end_time);
  } else {
    *answer = NULL;
  }
  return 0;
}

Here is the call graph for this function:

void hibernate_begin_shutdown ( void  )

A wrapper around hibernate_begin, for when we get SIGINT.

Definition at line 806 of file hibernate.c.

{
  hibernate_begin(HIBERNATE_STATE_EXITING, time(NULL));
}

Here is the call graph for this function:

Here is the caller graph for this function:

int we_are_hibernating ( void  )

Return true iff we are currently hibernating.

Definition at line 813 of file hibernate.c.

{
  return hibernate_state != HIBERNATE_STATE_LIVE;
}

Here is the caller graph for this function: