Back to index

tor  0.2.3.19-rc
hibernate.c
Go to the documentation of this file.
00001 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
00002  * Copyright (c) 2007-2012, The Tor Project, Inc. */
00003 /* See LICENSE for licensing information */
00004 
00013 /*
00014 hibernating, phase 1:
00015   - send destroy in response to create cells
00016   - send end (policy failed) in response to begin cells
00017   - close an OR conn when it has no circuits
00018 
00019 hibernating, phase 2:
00020   (entered when bandwidth hard limit reached)
00021   - close all OR/AP/exit conns)
00022 */
00023 
00024 #define HIBERNATE_PRIVATE
00025 #include "or.h"
00026 #include "config.h"
00027 #include "connection.h"
00028 #include "connection_edge.h"
00029 #include "hibernate.h"
00030 #include "main.h"
00031 #include "router.h"
00032 
00033 extern long stats_n_seconds_working; /* published uptime */
00034 
00037 static hibernate_state_t hibernate_state = HIBERNATE_STATE_INITIAL;
00040 static time_t hibernate_end_time = 0;
00043 static time_t shutdown_time = 0;
00044 
00046 typedef enum {
00047   UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3,
00048 } time_unit_t;
00049 
00050 /* Fields for accounting logic.  Accounting overview:
00051  *
00052  * Accounting is designed to ensure that no more than N bytes are sent in
00053  * either direction over a given interval (currently, one month, one week, or
00054  * one day) We could
00055  * try to do this by choking our bandwidth to a trickle, but that
00056  * would make our streams useless.  Instead, we estimate what our
00057  * bandwidth usage will be, and guess how long we'll be able to
00058  * provide that much bandwidth before hitting our limit.  We then
00059  * choose a random time within the accounting interval to come up (so
00060  * that we don't get 50 Tors running on the 1st of the month and none
00061  * on the 30th).
00062  *
00063  * Each interval runs as follows:
00064  *
00065  * 1. We guess our bandwidth usage, based on how much we used
00066  *     last time.  We choose a "wakeup time" within the interval to come up.
00067  * 2. Until the chosen wakeup time, we hibernate.
00068  * 3. We come up at the wakeup time, and provide bandwidth until we are
00069  *    "very close" to running out.
00070  * 4. Then we go into low-bandwidth mode, and stop accepting new
00071  *    connections, but provide bandwidth until we run out.
00072  * 5. Then we hibernate until the end of the interval.
00073  *
00074  * If the interval ends before we run out of bandwidth, we go back to
00075  * step one.
00076  */
00077 
00079 static uint64_t n_bytes_read_in_interval = 0;
00081 static uint64_t n_bytes_written_in_interval = 0;
00083 static uint32_t n_seconds_active_in_interval = 0;
00086 static int n_seconds_to_hit_soft_limit = 0;
00088 static time_t soft_limit_hit_at = 0;
00090 static uint64_t n_bytes_at_soft_limit = 0;
00092 static time_t interval_start_time = 0;
00094 static time_t interval_end_time = 0;
00096 static time_t interval_wakeup_time = 0;
00099 static uint64_t expected_bandwidth_usage = 0;
00101 static time_unit_t cfg_unit = UNIT_MONTH;
00102 
00106 static int cfg_start_day = 0,
00107            cfg_start_hour = 0,
00108            cfg_start_min = 0;
00111 static void reset_accounting(time_t now);
00112 static int read_bandwidth_usage(void);
00113 static time_t start_of_accounting_period_after(time_t now);
00114 static time_t start_of_accounting_period_containing(time_t now);
00115 static void accounting_set_wakeup_time(void);
00116 
00117 /* ************
00118  * Functions for bandwidth accounting.
00119  * ************/
00120 
00124 int
00125 accounting_parse_options(const or_options_t *options, int validate_only)
00126 {
00127   time_unit_t unit;
00128   int ok, idx;
00129   long d,h,m;
00130   smartlist_t *items;
00131   const char *v = options->AccountingStart;
00132   const char *s;
00133   char *cp;
00134 
00135   if (!v) {
00136     if (!validate_only) {
00137       cfg_unit = UNIT_MONTH;
00138       cfg_start_day = 1;
00139       cfg_start_hour = 0;
00140       cfg_start_min = 0;
00141     }
00142     return 0;
00143   }
00144 
00145   items = smartlist_new();
00146   smartlist_split_string(items, v, NULL,
00147                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0);
00148   if (smartlist_len(items)<2) {
00149     log_warn(LD_CONFIG, "Too few arguments to AccountingStart");
00150     goto err;
00151   }
00152   s = smartlist_get(items,0);
00153   if (0==strcasecmp(s, "month")) {
00154     unit = UNIT_MONTH;
00155   } else if (0==strcasecmp(s, "week")) {
00156     unit = UNIT_WEEK;
00157   } else if (0==strcasecmp(s, "day")) {
00158     unit = UNIT_DAY;
00159   } else {
00160     log_warn(LD_CONFIG,
00161              "Unrecognized accounting unit '%s': only 'month', 'week',"
00162              " and 'day' are supported.", s);
00163     goto err;
00164   }
00165 
00166   switch (unit) {
00167   case UNIT_WEEK:
00168     d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL);
00169     if (!ok) {
00170       log_warn(LD_CONFIG, "Weekly accounting must begin on a day between "
00171                "1 (Monday) and 7 (Sunday)");
00172       goto err;
00173     }
00174     break;
00175   case UNIT_MONTH:
00176     d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL);
00177     if (!ok) {
00178       log_warn(LD_CONFIG, "Monthly accounting must begin on a day between "
00179                "1 and 28");
00180       goto err;
00181     }
00182     break;
00183   case UNIT_DAY:
00184     d = 0;
00185     break;
00186     /* Coverity dislikes unreachable default cases; some compilers warn on
00187      * switch statements missing a case.  Tell Coverity not to worry. */
00188     /* coverity[dead_error_begin] */
00189   default:
00190     tor_assert(0);
00191   }
00192 
00193   idx = unit==UNIT_DAY?1:2;
00194   if (smartlist_len(items) != (idx+1)) {
00195     log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.",
00196              s, idx, (idx>1)?"s":"");
00197     goto err;
00198   }
00199   s = smartlist_get(items, idx);
00200   h = tor_parse_long(s, 10, 0, 23, &ok, &cp);
00201   if (!ok) {
00202     log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour.");
00203     goto err;
00204   }
00205   if (!cp || *cp!=':') {
00206     log_warn(LD_CONFIG,
00207              "Accounting start time not parseable: not in HH:MM format");
00208     goto err;
00209   }
00210   m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp);
00211   if (!ok) {
00212     log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute");
00213     goto err;
00214   }
00215   if (!cp || *cp!='\0') {
00216     log_warn(LD_CONFIG,
00217              "Accounting start time not parseable: not in HH:MM format");
00218     goto err;
00219   }
00220 
00221   if (!validate_only) {
00222     cfg_unit = unit;
00223     cfg_start_day = (int)d;
00224     cfg_start_hour = (int)h;
00225     cfg_start_min = (int)m;
00226   }
00227   SMARTLIST_FOREACH(items, char *, item, tor_free(item));
00228   smartlist_free(items);
00229   return 0;
00230  err:
00231   SMARTLIST_FOREACH(items, char *, item, tor_free(item));
00232   smartlist_free(items);
00233   return -1;
00234 }
00235 
00239 int
00240 accounting_is_enabled(const or_options_t *options)
00241 {
00242   if (options->AccountingMax)
00243     return 1;
00244   return 0;
00245 }
00246 
00249 int
00250 accounting_get_interval_length(void)
00251 {
00252   return (int)(interval_end_time - interval_start_time);
00253 }
00254 
00258 void
00259 accounting_add_bytes(size_t n_read, size_t n_written, int seconds)
00260 {
00261   n_bytes_read_in_interval += n_read;
00262   n_bytes_written_in_interval += n_written;
00263   /* If we haven't been called in 10 seconds, we're probably jumping
00264    * around in time. */
00265   n_seconds_active_in_interval += (seconds < 10) ? seconds : 0;
00266 }
00267 
00271 static time_t
00272 edge_of_accounting_period_containing(time_t now, int get_end)
00273 {
00274   int before;
00275   struct tm tm;
00276   tor_localtime_r(&now, &tm);
00277 
00278   /* Set 'before' to true iff the current time is before the hh:mm
00279    * changeover time for today. */
00280   before = tm.tm_hour < cfg_start_hour ||
00281     (tm.tm_hour == cfg_start_hour && tm.tm_min < cfg_start_min);
00282 
00283   /* Dispatch by unit.  First, find the start day of the given period;
00284    * then, if get_end is true, increment to the end day. */
00285   switch (cfg_unit)
00286     {
00287     case UNIT_MONTH: {
00288       /* If this is before the Nth, we want the Nth of last month. */
00289       if (tm.tm_mday < cfg_start_day ||
00290           (tm.tm_mday < cfg_start_day && before)) {
00291         --tm.tm_mon;
00292       }
00293       /* Otherwise, the month is correct. */
00294       tm.tm_mday = cfg_start_day;
00295       if (get_end)
00296         ++tm.tm_mon;
00297       break;
00298     }
00299     case UNIT_WEEK: {
00300       /* What is the 'target' day of the week in struct tm format? (We
00301          say Sunday==7; struct tm says Sunday==0.) */
00302       int wday = cfg_start_day % 7;
00303       /* How many days do we subtract from today to get to the right day? */
00304       int delta = (7+tm.tm_wday-wday)%7;
00305       /* If we are on the right day, but the changeover hasn't happened yet,
00306        * then subtract a whole week. */
00307       if (delta == 0 && before)
00308         delta = 7;
00309       tm.tm_mday -= delta;
00310       if (get_end)
00311         tm.tm_mday += 7;
00312       break;
00313     }
00314     case UNIT_DAY:
00315       if (before)
00316         --tm.tm_mday;
00317       if (get_end)
00318         ++tm.tm_mday;
00319       break;
00320     default:
00321       tor_assert(0);
00322   }
00323 
00324   tm.tm_hour = cfg_start_hour;
00325   tm.tm_min = cfg_start_min;
00326   tm.tm_sec = 0;
00327   tm.tm_isdst = -1; /* Autodetect DST */
00328   return mktime(&tm);
00329 }
00330 
00333 static time_t
00334 start_of_accounting_period_containing(time_t now)
00335 {
00336   return edge_of_accounting_period_containing(now, 0);
00337 }
00338 
00341 static time_t
00342 start_of_accounting_period_after(time_t now)
00343 {
00344   return edge_of_accounting_period_containing(now, 1);
00345 }
00346 
00349 static long
00350 length_of_accounting_period_containing(time_t now)
00351 {
00352   return edge_of_accounting_period_containing(now, 1) -
00353     edge_of_accounting_period_containing(now, 0);
00354 }
00355 
00357 void
00358 configure_accounting(time_t now)
00359 {
00360   time_t s_now;
00361   /* Try to remember our recorded usage. */
00362   if (!interval_start_time)
00363     read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and
00364                              * reset below.*/
00365 
00366   s_now = start_of_accounting_period_containing(now);
00367 
00368   if (!interval_start_time) {
00369     /* We didn't have recorded usage; Start a new interval. */
00370     log_info(LD_ACCT, "Starting new accounting interval.");
00371     reset_accounting(now);
00372   } else if (s_now == interval_start_time) {
00373     log_info(LD_ACCT, "Continuing accounting interval.");
00374     /* We are in the interval we thought we were in. Do nothing.*/
00375     interval_end_time = start_of_accounting_period_after(interval_start_time);
00376   } else {
00377     long duration =
00378       length_of_accounting_period_containing(interval_start_time);
00379     double delta = ((double)(s_now - interval_start_time)) / duration;
00380     if (-0.50 <= delta && delta <= 0.50) {
00381       /* The start of the period is now a little later or earlier than we
00382        * remembered.  That's fine; we might lose some bytes we could otherwise
00383        * have written, but better to err on the side of obeying people's
00384        * accounting settings. */
00385       log_info(LD_ACCT, "Accounting interval moved by %.02f%%; "
00386                "that's fine.", delta*100);
00387       interval_end_time = start_of_accounting_period_after(now);
00388     } else if (delta >= 0.99) {
00389       /* This is the regular time-moved-forward case; don't be too noisy
00390        * about it or people will complain */
00391       log_info(LD_ACCT, "Accounting interval elapsed; starting a new one");
00392       reset_accounting(now);
00393     } else {
00394       log_warn(LD_ACCT,
00395                "Mismatched accounting interval: moved by %.02f%%. "
00396                "Starting a fresh one.", delta*100);
00397       reset_accounting(now);
00398     }
00399   }
00400   accounting_set_wakeup_time();
00401 }
00402 
00406 static void
00407 update_expected_bandwidth(void)
00408 {
00409   uint64_t expected;
00410   const or_options_t *options= get_options();
00411   uint64_t max_configured = (options->RelayBandwidthRate > 0 ?
00412                              options->RelayBandwidthRate :
00413                              options->BandwidthRate) * 60;
00414 
00415 #define MIN_TIME_FOR_MEASUREMENT (1800)
00416 
00417   if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit &&
00418       (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) {
00419     /* If we hit our soft limit last time, only count the bytes up to that
00420      * time. This is a better predictor of our actual bandwidth than
00421      * considering the entirety of the last interval, since we likely started
00422      * using bytes very slowly once we hit our soft limit. */
00423     expected = n_bytes_at_soft_limit /
00424       (soft_limit_hit_at - interval_start_time);
00425     expected /= 60;
00426   } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) {
00427     /* Otherwise, we either measured enough time in the last interval but
00428      * never hit our soft limit, or we're using a state file from a Tor that
00429      * doesn't know to store soft-limit info.  Just take rate at which
00430      * we were reading/writing in the last interval as our expected rate.
00431      */
00432     uint64_t used = MAX(n_bytes_written_in_interval,
00433                         n_bytes_read_in_interval);
00434     expected = used / (n_seconds_active_in_interval / 60);
00435   } else {
00436     /* If we haven't gotten enough data last interval, set 'expected'
00437      * to 0.  This will set our wakeup to the start of the interval.
00438      * Next interval, we'll choose our starting time based on how much
00439      * we sent this interval.
00440      */
00441     expected = 0;
00442   }
00443   if (expected > max_configured)
00444     expected = max_configured;
00445   expected_bandwidth_usage = expected;
00446 }
00447 
00452 static void
00453 reset_accounting(time_t now)
00454 {
00455   log_info(LD_ACCT, "Starting new accounting interval.");
00456   update_expected_bandwidth();
00457   interval_start_time = start_of_accounting_period_containing(now);
00458   interval_end_time = start_of_accounting_period_after(interval_start_time);
00459   n_bytes_read_in_interval = 0;
00460   n_bytes_written_in_interval = 0;
00461   n_seconds_active_in_interval = 0;
00462   n_bytes_at_soft_limit = 0;
00463   soft_limit_hit_at = 0;
00464   n_seconds_to_hit_soft_limit = 0;
00465 }
00466 
00468 static INLINE int
00469 time_to_record_bandwidth_usage(time_t now)
00470 {
00471   /* Note every 600 sec */
00472 #define NOTE_INTERVAL (600)
00473   /* Or every 20 megabytes */
00474 #define NOTE_BYTES 20*(1024*1024)
00475   static uint64_t last_read_bytes_noted = 0;
00476   static uint64_t last_written_bytes_noted = 0;
00477   static time_t last_time_noted = 0;
00478 
00479   if (last_time_noted + NOTE_INTERVAL <= now ||
00480       last_read_bytes_noted + NOTE_BYTES <= n_bytes_read_in_interval ||
00481       last_written_bytes_noted + NOTE_BYTES <= n_bytes_written_in_interval ||
00482       (interval_end_time && interval_end_time <= now)) {
00483     last_time_noted = now;
00484     last_read_bytes_noted = n_bytes_read_in_interval;
00485     last_written_bytes_noted = n_bytes_written_in_interval;
00486     return 1;
00487   }
00488   return 0;
00489 }
00490 
00493 void
00494 accounting_run_housekeeping(time_t now)
00495 {
00496   if (now >= interval_end_time) {
00497     configure_accounting(now);
00498   }
00499   if (time_to_record_bandwidth_usage(now)) {
00500     if (accounting_record_bandwidth_usage(now, get_or_state())) {
00501       log_warn(LD_FS, "Couldn't record bandwidth usage to disk.");
00502     }
00503   }
00504 }
00505 
00508 #define GUESS_TIME_TO_USE_BANDWIDTH (24*60*60)
00509 
00512 static void
00513 accounting_set_wakeup_time(void)
00514 {
00515   char digest[DIGEST_LEN];
00516   crypto_digest_t *d_env;
00517   uint64_t time_to_exhaust_bw;
00518   int time_to_consider;
00519 
00520   if (! server_identity_key_is_set()) {
00521     if (init_keys() < 0) {
00522       log_err(LD_BUG, "Error initializing keys");
00523       tor_assert(0);
00524     }
00525   }
00526 
00527   if (server_identity_key_is_set()) {
00528     char buf[ISO_TIME_LEN+1];
00529     format_iso_time(buf, interval_start_time);
00530 
00531     crypto_pk_get_digest(get_server_identity_key(), digest);
00532 
00533     d_env = crypto_digest_new();
00534     crypto_digest_add_bytes(d_env, buf, ISO_TIME_LEN);
00535     crypto_digest_add_bytes(d_env, digest, DIGEST_LEN);
00536     crypto_digest_get_digest(d_env, digest, DIGEST_LEN);
00537     crypto_digest_free(d_env);
00538   } else {
00539     crypto_rand(digest, DIGEST_LEN);
00540   }
00541 
00542   if (!expected_bandwidth_usage) {
00543     char buf1[ISO_TIME_LEN+1];
00544     char buf2[ISO_TIME_LEN+1];
00545     format_local_iso_time(buf1, interval_start_time);
00546     format_local_iso_time(buf2, interval_end_time);
00547     interval_wakeup_time = interval_start_time;
00548 
00549     log_notice(LD_ACCT,
00550            "Configured hibernation. This interval begins at %s "
00551            "and ends at %s. We have no prior estimate for bandwidth, so "
00552            "we will start out awake and hibernate when we exhaust our quota.",
00553            buf1, buf2);
00554     return;
00555   }
00556 
00557   time_to_exhaust_bw =
00558     (get_options()->AccountingMax/expected_bandwidth_usage)*60;
00559   if (time_to_exhaust_bw > INT_MAX) {
00560     time_to_exhaust_bw = INT_MAX;
00561     time_to_consider = 0;
00562   } else {
00563     time_to_consider = accounting_get_interval_length() -
00564                        (int)time_to_exhaust_bw;
00565   }
00566 
00567   if (time_to_consider<=0) {
00568     interval_wakeup_time = interval_start_time;
00569   } else {
00570     /* XXX can we simplify this just by picking a random (non-deterministic)
00571      * time to be up? If we go down and come up, then we pick a new one. Is
00572      * that good enough? -RD */
00573 
00574     /* This is not a perfectly unbiased conversion, but it is good enough:
00575      * in the worst case, the first half of the day is 0.06 percent likelier
00576      * to be chosen than the last half. */
00577     interval_wakeup_time = interval_start_time +
00578       (get_uint32(digest) % time_to_consider);
00579   }
00580 
00581   {
00582     char buf1[ISO_TIME_LEN+1];
00583     char buf2[ISO_TIME_LEN+1];
00584     char buf3[ISO_TIME_LEN+1];
00585     char buf4[ISO_TIME_LEN+1];
00586     time_t down_time;
00587     if (interval_wakeup_time+time_to_exhaust_bw > TIME_MAX)
00588       down_time = TIME_MAX;
00589     else
00590       down_time = (time_t)(interval_wakeup_time+time_to_exhaust_bw);
00591     if (down_time>interval_end_time)
00592       down_time = interval_end_time;
00593     format_local_iso_time(buf1, interval_start_time);
00594     format_local_iso_time(buf2, interval_wakeup_time);
00595     format_local_iso_time(buf3, down_time);
00596     format_local_iso_time(buf4, interval_end_time);
00597 
00598     log_notice(LD_ACCT,
00599            "Configured hibernation.  This interval began at %s; "
00600            "the scheduled wake-up time %s %s; "
00601            "we expect%s to exhaust our quota for this interval around %s; "
00602            "the next interval begins at %s (all times local)",
00603            buf1,
00604            time(NULL)<interval_wakeup_time?"is":"was", buf2,
00605            time(NULL)<down_time?"":"ed", buf3,
00606            buf4);
00607   }
00608 }
00609 
00610 /* This rounds 0 up to 1000, but that's actually a feature. */
00611 #define ROUND_UP(x) (((x) + 0x3ff) & ~0x3ff)
00612 
00614 int
00615 accounting_record_bandwidth_usage(time_t now, or_state_t *state)
00616 {
00617   /* Just update the state */
00618   state->AccountingIntervalStart = interval_start_time;
00619   state->AccountingBytesReadInInterval = ROUND_UP(n_bytes_read_in_interval);
00620   state->AccountingBytesWrittenInInterval =
00621     ROUND_UP(n_bytes_written_in_interval);
00622   state->AccountingSecondsActive = n_seconds_active_in_interval;
00623   state->AccountingExpectedUsage = expected_bandwidth_usage;
00624 
00625   state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit;
00626   state->AccountingSoftLimitHitAt = soft_limit_hit_at;
00627   state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit;
00628 
00629   or_state_mark_dirty(state,
00630                       now+(get_options()->AvoidDiskWrites ? 7200 : 60));
00631 
00632   return 0;
00633 }
00634 #undef ROUND_UP
00635 
00638 static int
00639 read_bandwidth_usage(void)
00640 {
00641   or_state_t *state = get_or_state();
00642 
00643   {
00644     char *fname = get_datadir_fname("bw_accounting");
00645     unlink(fname);
00646     tor_free(fname);
00647   }
00648 
00649   if (!state)
00650     return -1;
00651 
00652   log_info(LD_ACCT, "Reading bandwidth accounting data from state file");
00653   n_bytes_read_in_interval = state->AccountingBytesReadInInterval;
00654   n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval;
00655   n_seconds_active_in_interval = state->AccountingSecondsActive;
00656   interval_start_time = state->AccountingIntervalStart;
00657   expected_bandwidth_usage = state->AccountingExpectedUsage;
00658 
00659   /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these
00660    * fields. If you switch back and forth, you might get an
00661    * AccountingSoftLimitHitAt value from long before the most recent
00662    * interval_start_time.  If that's so, then ignore the softlimit-related
00663    * values. */
00664   if (state->AccountingSoftLimitHitAt > interval_start_time) {
00665     soft_limit_hit_at =  state->AccountingSoftLimitHitAt;
00666     n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit;
00667     n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit;
00668   } else {
00669     soft_limit_hit_at = 0;
00670     n_bytes_at_soft_limit = 0;
00671     n_seconds_to_hit_soft_limit = 0;
00672   }
00673 
00674   {
00675     char tbuf1[ISO_TIME_LEN+1];
00676     char tbuf2[ISO_TIME_LEN+1];
00677     format_iso_time(tbuf1, state->LastWritten);
00678     format_iso_time(tbuf2, state->AccountingIntervalStart);
00679 
00680     log_info(LD_ACCT,
00681        "Successfully read bandwidth accounting info from state written at %s "
00682        "for interval starting at %s.  We have been active for %lu seconds in "
00683        "this interval.  At the start of the interval, we expected to use "
00684        "about %lu KB per second. ("U64_FORMAT" bytes read so far, "
00685        U64_FORMAT" bytes written so far)",
00686        tbuf1, tbuf2,
00687        (unsigned long)n_seconds_active_in_interval,
00688        (unsigned long)(expected_bandwidth_usage*1024/60),
00689        U64_PRINTF_ARG(n_bytes_read_in_interval),
00690        U64_PRINTF_ARG(n_bytes_written_in_interval));
00691   }
00692 
00693   return 0;
00694 }
00695 
00698 static int
00699 hibernate_hard_limit_reached(void)
00700 {
00701   uint64_t hard_limit = get_options()->AccountingMax;
00702   if (!hard_limit)
00703     return 0;
00704   return n_bytes_read_in_interval >= hard_limit
00705     || n_bytes_written_in_interval >= hard_limit;
00706 }
00707 
00710 static int
00711 hibernate_soft_limit_reached(void)
00712 {
00713   const uint64_t acct_max = get_options()->AccountingMax;
00714 #define SOFT_LIM_PCT (.95)
00715 #define SOFT_LIM_BYTES (500*1024*1024)
00716 #define SOFT_LIM_MINUTES (3*60)
00717   /* The 'soft limit' is a fair bit more complicated now than once it was.
00718    * We want to stop accepting connections when ALL of the following are true:
00719    *   - We expect to use up the remaining bytes in under 3 hours
00720    *   - We have used up 95% of our bytes.
00721    *   - We have less than 500MB of bytes left.
00722    */
00723   uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT);
00724   if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) {
00725     soft_limit = acct_max - SOFT_LIM_BYTES;
00726   }
00727   if (expected_bandwidth_usage) {
00728     const uint64_t expected_usage =
00729       expected_bandwidth_usage * SOFT_LIM_MINUTES;
00730     if (acct_max > expected_usage && acct_max - expected_usage > soft_limit)
00731       soft_limit = acct_max - expected_usage;
00732   }
00733 
00734   if (!soft_limit)
00735     return 0;
00736   return n_bytes_read_in_interval >= soft_limit
00737     || n_bytes_written_in_interval >= soft_limit;
00738 }
00739 
00743 static void
00744 hibernate_begin(hibernate_state_t new_state, time_t now)
00745 {
00746   const or_options_t *options = get_options();
00747 
00748   if (new_state == HIBERNATE_STATE_EXITING &&
00749       hibernate_state != HIBERNATE_STATE_LIVE) {
00750     log_notice(LD_GENERAL,"SIGINT received %s; exiting now.",
00751                hibernate_state == HIBERNATE_STATE_EXITING ?
00752                "a second time" : "while hibernating");
00753     tor_cleanup();
00754     exit(0);
00755   }
00756 
00757   if (new_state == HIBERNATE_STATE_LOWBANDWIDTH &&
00758       hibernate_state == HIBERNATE_STATE_LIVE) {
00759     soft_limit_hit_at = now;
00760     n_seconds_to_hit_soft_limit = n_seconds_active_in_interval;
00761     n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval,
00762                                 n_bytes_written_in_interval);
00763   }
00764 
00765   /* close listeners. leave control listener(s). */
00766   connection_mark_all_noncontrol_listeners();
00767 
00768   /* XXX kill intro point circs */
00769   /* XXX upload rendezvous service descriptors with no intro points */
00770 
00771   if (new_state == HIBERNATE_STATE_EXITING) {
00772     log_notice(LD_GENERAL,"Interrupt: we have stopped accepting new "
00773                "connections, and will shut down in %d seconds. Interrupt "
00774                "again to exit now.", options->ShutdownWaitLength);
00775     shutdown_time = time(NULL) + options->ShutdownWaitLength;
00776   } else { /* soft limit reached */
00777     hibernate_end_time = interval_end_time;
00778   }
00779 
00780   hibernate_state = new_state;
00781   accounting_record_bandwidth_usage(now, get_or_state());
00782 
00783   or_state_mark_dirty(get_or_state(),
00784                       get_options()->AvoidDiskWrites ? now+600 : 0);
00785 }
00786 
00788 static void
00789 hibernate_end(hibernate_state_t new_state)
00790 {
00791   tor_assert(hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH ||
00792              hibernate_state == HIBERNATE_STATE_DORMANT ||
00793              hibernate_state == HIBERNATE_STATE_INITIAL);
00794 
00795   /* listeners will be relaunched in run_scheduled_events() in main.c */
00796   if (hibernate_state != HIBERNATE_STATE_INITIAL)
00797     log_notice(LD_ACCT,"Hibernation period ended. Resuming normal activity.");
00798 
00799   hibernate_state = new_state;
00800   hibernate_end_time = 0; /* no longer hibernating */
00801   stats_n_seconds_working = 0; /* reset published uptime */
00802 }
00803 
00805 void
00806 hibernate_begin_shutdown(void)
00807 {
00808   hibernate_begin(HIBERNATE_STATE_EXITING, time(NULL));
00809 }
00810 
00812 int
00813 we_are_hibernating(void)
00814 {
00815   return hibernate_state != HIBERNATE_STATE_LIVE;
00816 }
00817 
00820 static void
00821 hibernate_go_dormant(time_t now)
00822 {
00823   connection_t *conn;
00824 
00825   if (hibernate_state == HIBERNATE_STATE_DORMANT)
00826     return;
00827   else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH)
00828     hibernate_state = HIBERNATE_STATE_DORMANT;
00829   else
00830     hibernate_begin(HIBERNATE_STATE_DORMANT, now);
00831 
00832   log_notice(LD_ACCT,"Going dormant. Blowing away remaining connections.");
00833 
00834   /* Close all OR/AP/exit conns. Leave dir conns because we still want
00835    * to be able to upload server descriptors so people know we're still
00836    * running, and download directories so we can detect if we're obsolete.
00837    * Leave control conns because we still want to be controllable.
00838    */
00839   while ((conn = connection_get_by_type(CONN_TYPE_OR)) ||
00840          (conn = connection_get_by_type(CONN_TYPE_AP)) ||
00841          (conn = connection_get_by_type(CONN_TYPE_EXIT))) {
00842     if (CONN_IS_EDGE(conn))
00843       connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING);
00844     log_info(LD_NET,"Closing conn type %d", conn->type);
00845     if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
00846       connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
00847                                     END_STREAM_REASON_HIBERNATING);
00848     else
00849       connection_mark_for_close(conn);
00850   }
00851 
00852   if (now < interval_wakeup_time)
00853     hibernate_end_time = interval_wakeup_time;
00854   else
00855     hibernate_end_time = interval_end_time;
00856 
00857   accounting_record_bandwidth_usage(now, get_or_state());
00858 
00859   or_state_mark_dirty(get_or_state(),
00860                       get_options()->AvoidDiskWrites ? now+600 : 0);
00861 }
00862 
00864 static void
00865 hibernate_end_time_elapsed(time_t now)
00866 {
00867   char buf[ISO_TIME_LEN+1];
00868 
00869   /* The interval has ended, or it is wakeup time.  Find out which. */
00870   accounting_run_housekeeping(now);
00871   if (interval_wakeup_time <= now) {
00872     /* The interval hasn't changed, but interval_wakeup_time has passed.
00873      * It's time to wake up and start being a server. */
00874     hibernate_end(HIBERNATE_STATE_LIVE);
00875     return;
00876   } else {
00877     /* The interval has changed, and it isn't time to wake up yet. */
00878     hibernate_end_time = interval_wakeup_time;
00879     format_iso_time(buf,interval_wakeup_time);
00880     if (hibernate_state != HIBERNATE_STATE_DORMANT) {
00881       /* We weren't sleeping before; we should sleep now. */
00882       log_notice(LD_ACCT,
00883                  "Accounting period ended. Commencing hibernation until "
00884                  "%s GMT", buf);
00885       hibernate_go_dormant(now);
00886     } else {
00887       log_notice(LD_ACCT,
00888              "Accounting period ended. This period, we will hibernate"
00889              " until %s GMT",buf);
00890     }
00891   }
00892 }
00893 
00897 void
00898 consider_hibernation(time_t now)
00899 {
00900   int accounting_enabled = get_options()->AccountingMax != 0;
00901   char buf[ISO_TIME_LEN+1];
00902 
00903   /* If we're in 'exiting' mode, then we just shut down after the interval
00904    * elapses. */
00905   if (hibernate_state == HIBERNATE_STATE_EXITING) {
00906     tor_assert(shutdown_time);
00907     if (shutdown_time <= now) {
00908       log_notice(LD_GENERAL, "Clean shutdown finished. Exiting.");
00909       tor_cleanup();
00910       exit(0);
00911     }
00912     return; /* if exiting soon, don't worry about bandwidth limits */
00913   }
00914 
00915   if (hibernate_state == HIBERNATE_STATE_DORMANT) {
00916     /* We've been hibernating because of bandwidth accounting. */
00917     tor_assert(hibernate_end_time);
00918     if (hibernate_end_time > now && accounting_enabled) {
00919       /* If we're hibernating, don't wake up until it's time, regardless of
00920        * whether we're in a new interval. */
00921       return ;
00922     } else {
00923       hibernate_end_time_elapsed(now);
00924     }
00925   }
00926 
00927   /* Else, we aren't hibernating. See if it's time to start hibernating, or to
00928    * go dormant. */
00929   if (hibernate_state == HIBERNATE_STATE_LIVE ||
00930       hibernate_state == HIBERNATE_STATE_INITIAL) {
00931     if (hibernate_soft_limit_reached()) {
00932       log_notice(LD_ACCT,
00933                  "Bandwidth soft limit reached; commencing hibernation. "
00934                  "No new connections will be accepted");
00935       hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH, now);
00936     } else if (accounting_enabled && now < interval_wakeup_time) {
00937       format_local_iso_time(buf,interval_wakeup_time);
00938       log_notice(LD_ACCT,
00939                  "Commencing hibernation. We will wake up at %s local time.",
00940                  buf);
00941       hibernate_go_dormant(now);
00942     } else if (hibernate_state == HIBERNATE_STATE_INITIAL) {
00943       hibernate_end(HIBERNATE_STATE_LIVE);
00944     }
00945   }
00946 
00947   if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) {
00948     if (!accounting_enabled) {
00949       hibernate_end_time_elapsed(now);
00950     } else if (hibernate_hard_limit_reached()) {
00951       hibernate_go_dormant(now);
00952     } else if (hibernate_end_time <= now) {
00953       /* The hibernation period ended while we were still in lowbandwidth.*/
00954       hibernate_end_time_elapsed(now);
00955     }
00956   }
00957 }
00958 
00964 int
00965 getinfo_helper_accounting(control_connection_t *conn,
00966                           const char *question, char **answer,
00967                           const char **errmsg)
00968 {
00969   (void) conn;
00970   (void) errmsg;
00971   if (!strcmp(question, "accounting/enabled")) {
00972     *answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0");
00973   } else if (!strcmp(question, "accounting/hibernating")) {
00974     if (hibernate_state == HIBERNATE_STATE_DORMANT)
00975       *answer = tor_strdup("hard");
00976     else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH)
00977       *answer = tor_strdup("soft");
00978     else
00979       *answer = tor_strdup("awake");
00980   } else if (!strcmp(question, "accounting/bytes")) {
00981     tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
00982                  U64_PRINTF_ARG(n_bytes_read_in_interval),
00983                  U64_PRINTF_ARG(n_bytes_written_in_interval));
00984   } else if (!strcmp(question, "accounting/bytes-left")) {
00985     uint64_t limit = get_options()->AccountingMax;
00986     uint64_t read_left = 0, write_left = 0;
00987     if (n_bytes_read_in_interval < limit)
00988       read_left = limit - n_bytes_read_in_interval;
00989     if (n_bytes_written_in_interval < limit)
00990       write_left = limit - n_bytes_written_in_interval;
00991     tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
00992                  U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left));
00993   } else if (!strcmp(question, "accounting/interval-start")) {
00994     *answer = tor_malloc(ISO_TIME_LEN+1);
00995     format_iso_time(*answer, interval_start_time);
00996   } else if (!strcmp(question, "accounting/interval-wake")) {
00997     *answer = tor_malloc(ISO_TIME_LEN+1);
00998     format_iso_time(*answer, interval_wakeup_time);
00999   } else if (!strcmp(question, "accounting/interval-end")) {
01000     *answer = tor_malloc(ISO_TIME_LEN+1);
01001     format_iso_time(*answer, interval_end_time);
01002   } else {
01003     *answer = NULL;
01004   }
01005   return 0;
01006 }
01007 
01012 void
01013 hibernate_set_state_for_testing_(hibernate_state_t newstate)
01014 {
01015   hibernate_state = newstate;
01016 }
01017