1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
7 * \brief Functions to close listeners, stop allowing new circuits,
8 * etc in preparation for closing down or going dormant; and to track
9 * bandwidth and time intervals to know when to hibernate and when to
15 - send destroy in response to create cells
16 - send end (policy failed) in response to begin cells
17 - close an OR conn when it has no circuits
20 (entered when bandwidth hard limit reached)
21 - close all OR/AP/exit conns)
26 #define HIBERNATE_STATE_LIVE 1
27 #define HIBERNATE_STATE_EXITING 2
28 #define HIBERNATE_STATE_LOWBANDWIDTH 3
29 #define HIBERNATE_STATE_DORMANT 4
31 #define SHUTDOWN_WAIT_LENGTH 30 /* seconds */
33 static int hibernate_state
= HIBERNATE_STATE_LIVE
;
34 static time_t hibernate_timeout
= 0;
36 /** How many bytes have we read/written in this accounting interval? */
37 static uint64_t n_bytes_read_in_interval
= 0;
38 static uint64_t n_bytes_written_in_interval
= 0;
39 /** How many seconds have we been running this interval? */
40 static uint32_t n_seconds_active_in_interval
= 0;
41 /** When did this accounting interval start? */
42 static time_t interval_start_time
= 0;
43 /** When will this accounting interval end? */
44 static time_t interval_end_time
= 0;
45 /** How far into the accounting interval should we hibernate? */
46 static time_t interval_wakeup_time
= 0;
47 /** How much bandwidth do we 'expect' to use per minute? */
48 static uint32_t expected_bandwidth_usage
= 0;
50 static void reset_accounting(time_t now
);
51 static int read_bandwidth_usage(void);
52 static int record_bandwidth_usage(time_t now
);
53 static time_t start_of_accounting_period_after(time_t now
);
54 static time_t start_of_accounting_period_containing(time_t now
);
55 static void accounting_set_wakeup_time(void);
58 * Functions for bandwidth accounting.
62 accounting_add_bytes(size_t n_read
, size_t n_written
, int seconds
)
64 n_bytes_read_in_interval
+= n_read
;
65 n_bytes_written_in_interval
+= n_written
;
66 /* If we haven't been called in 10 seconds, we're probably jumping
68 n_seconds_active_in_interval
+= (seconds
< 10) ? seconds
: 0;
72 incr_month(struct tm
*tm
, unsigned int delta
)
75 while (tm
->tm_mon
> 11) {
82 decr_month(struct tm
*tm
, unsigned int delta
)
85 while (tm
->tm_mon
< 0) {
92 start_of_accounting_period_containing(time_t now
)
95 /* Only months are supported. */
97 /* If this is before the Nth, we want the Nth of last month. */
98 if (tm
->tm_mday
< get_options()->AccountingStart
) {
101 /* Otherwise, the month and year are correct.*/
103 tm
->tm_mday
= get_options()->AccountingStart
;
107 return tor_timegm(tm
);
110 start_of_accounting_period_after(time_t now
)
114 start
= start_of_accounting_period_containing(now
);
118 return tor_timegm(tm
);
122 configure_accounting(time_t now
)
124 if (!interval_start_time
)
125 read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and
127 if (!interval_start_time
||
128 start_of_accounting_period_after(interval_start_time
) <= now
) {
129 /* We start a new interval. */
130 log_fn(LOG_INFO
, "Starting new accounting interval.");
131 reset_accounting(now
);
132 } if (interval_start_time
==
133 start_of_accounting_period_containing(interval_start_time
)) {
134 log_fn(LOG_INFO
, "Continuing accounting interval.");
135 /* We are in the interval we thought we were in. Do nothing.*/
137 log_fn(LOG_WARN
, "Mismatched accounting interval; starting a fresh one.");
138 reset_accounting(now
);
140 accounting_set_wakeup_time();
144 update_expected_bandwidth(void)
147 uint32_t max_configured
= (get_options()->BandwidthRateBytes
* 60);
149 if (n_seconds_active_in_interval
< 1800) {
150 expected_bandwidth_usage
= max_configured
;
152 used
= n_bytes_written_in_interval
< n_bytes_read_in_interval
?
153 n_bytes_read_in_interval
: n_bytes_written_in_interval
;
154 expected_bandwidth_usage
= (uint32_t)
155 (used
/ (n_seconds_active_in_interval
/ 60));
156 if (expected_bandwidth_usage
> max_configured
)
157 expected_bandwidth_usage
= max_configured
;
162 reset_accounting(time_t now
) {
163 log_fn(LOG_INFO
, "Starting new accounting interval.");
164 update_expected_bandwidth();
165 interval_start_time
= start_of_accounting_period_containing(now
);
166 interval_end_time
= start_of_accounting_period_after(interval_start_time
);
167 n_bytes_read_in_interval
= 0;
168 n_bytes_written_in_interval
= 0;
169 n_seconds_active_in_interval
= 0;
172 static INLINE
int time_to_record_bandwidth_usage(time_t now
)
174 /* Note every 5 minutes */
175 #define NOTE_INTERVAL (5*60)
176 /* Or every 20 megabytes */
177 #define NOTE_BYTES 20*(1024*1024)
178 static uint64_t last_read_bytes_noted
= 0;
179 static uint64_t last_written_bytes_noted
= 0;
180 static time_t last_time_noted
= 0;
182 if (last_time_noted
+ NOTE_INTERVAL
<= now
||
183 last_read_bytes_noted
+ NOTE_BYTES
<= n_bytes_read_in_interval
||
184 last_written_bytes_noted
+ NOTE_BYTES
<= n_bytes_written_in_interval
||
185 (interval_end_time
&& interval_end_time
<= now
)) {
186 last_time_noted
= now
;
187 last_read_bytes_noted
= n_bytes_read_in_interval
;
188 last_written_bytes_noted
= n_bytes_written_in_interval
;
195 accounting_run_housekeeping(time_t now
)
197 if (now
>= interval_end_time
) {
198 configure_accounting(now
);
200 if (time_to_record_bandwidth_usage(now
)) {
201 if (record_bandwidth_usage(now
)) {
202 log_fn(LOG_ERR
, "Couldn't record bandwidth usage; exiting.");
209 accounting_set_wakeup_time(void)
212 char buf
[ISO_TIME_LEN
+1];
213 char digest
[DIGEST_LEN
];
214 crypto_digest_env_t
*d
;
215 int n_days_in_interval
;
216 int n_days_to_exhaust_bw
;
217 int n_days_to_consider
;
219 format_iso_time(buf
, interval_start_time
);
220 crypto_pk_get_digest(get_identity_key(), digest
);
222 d
= crypto_new_digest_env();
223 crypto_digest_add_bytes(d
, buf
, ISO_TIME_LEN
);
224 crypto_digest_add_bytes(d
, digest
, DIGEST_LEN
);
225 crypto_digest_get_digest(d
, digest
, DIGEST_LEN
);
226 crypto_free_digest_env(d
);
228 n_days_to_exhaust_bw
= (get_options()->AccountingMaxKB
/expected_bandwidth_usage
)
231 tm
= gmtime(&interval_start_time
);
232 if (++tm
->tm_mon
> 11) { tm
->tm_mon
= 0; ++tm
->tm_year
; }
233 n_days_in_interval
= (tor_timegm(tm
)-interval_start_time
+1)/(24*60*60);
235 n_days_to_consider
= n_days_in_interval
- n_days_to_exhaust_bw
;
237 /* XXX can we simplify this just by picking a random (non-deterministic)
238 * time to be up? If we go down and come up, then we pick a new one. Is
239 * that good enough? -RD */
240 while (((unsigned char)digest
[0]) > n_days_to_consider
)
241 crypto_digest(digest
, digest
, DIGEST_LEN
);
243 interval_wakeup_time
= interval_start_time
+
244 24*60*60 * (unsigned char)digest
[0];
247 #define BW_ACCOUNTING_VERSION 1
248 static int record_bandwidth_usage(time_t now
)
252 char time1
[ISO_TIME_LEN
+1];
253 char time2
[ISO_TIME_LEN
+1];
256 Version\nTime\nTime\nRead\nWrite\nSeconds\nExpected-Rate\n */
258 format_iso_time(time1
, interval_start_time
);
259 format_iso_time(time2
, now
);
260 tor_snprintf(cp
, sizeof(buf
),
261 "%d\n%s\n%s\n"U64_FORMAT
"\n"U64_FORMAT
"\n%lu\n%lu\n",
262 BW_ACCOUNTING_VERSION
,
265 U64_PRINTF_ARG(n_bytes_read_in_interval
),
266 U64_PRINTF_ARG(n_bytes_written_in_interval
),
267 (unsigned long)n_seconds_active_in_interval
,
268 (unsigned long)expected_bandwidth_usage
);
269 tor_snprintf(fname
, sizeof(fname
), "%s/bw_accounting",
270 get_data_directory());
272 return write_str_to_file(fname
, buf
, 0);
275 static int read_bandwidth_usage(void)
280 uint64_t n_read
, n_written
;
281 uint32_t expected_bw
, n_seconds
;
285 tor_snprintf(fname
, sizeof(fname
), "%s/bw_accounting",
286 get_data_directory());
287 if (!(s
= read_file_to_str(fname
, 0))) {
290 elts
= smartlist_create();
291 smartlist_split_string(elts
, s
, "\n", SPLIT_SKIP_SPACE
, SPLIT_IGNORE_BLANK
);
294 if (smartlist_len(elts
)<1 ||
295 atoi(smartlist_get(elts
,0)) != BW_ACCOUNTING_VERSION
) {
296 log_fn(LOG_WARN
, "Unrecognized bw_accounting file version: %s",
297 (const char*)smartlist_get(elts
,0));
300 if (smartlist_len(elts
) < 7) {
301 log_fn(LOG_WARN
, "Corrupted bw_accounting file: %d lines",
302 smartlist_len(elts
));
305 if (parse_iso_time(smartlist_get(elts
,1), &t1
)) {
306 log_fn(LOG_WARN
, "Error parsing bandwidth usage start time.");
309 if (parse_iso_time(smartlist_get(elts
,2), &t2
)) {
310 log_fn(LOG_WARN
, "Error parsing bandwidth usage last-written time");
313 n_read
= tor_parse_uint64(smartlist_get(elts
,3), 10, 0, UINT64_MAX
,
316 log_fn(LOG_WARN
, "Error parsing number of bytes read");
319 n_written
= tor_parse_uint64(smartlist_get(elts
,4), 10, 0, UINT64_MAX
,
322 log_fn(LOG_WARN
, "Error parsing number of bytes read");
325 n_seconds
= (uint32_t)tor_parse_ulong(smartlist_get(elts
,5), 10,0,ULONG_MAX
,
328 log_fn(LOG_WARN
, "Error parsing number of seconds live");
331 expected_bw
=(uint32_t)tor_parse_ulong(smartlist_get(elts
,6), 10,0,ULONG_MAX
,
334 log_fn(LOG_WARN
, "Error parsing expected bandwidth");
338 n_bytes_read_in_interval
= n_read
;
339 n_bytes_written_in_interval
= n_written
;
340 n_seconds_active_in_interval
= n_seconds
;
341 interval_start_time
= t1
;
342 expected_bandwidth_usage
= expected_bw
;
344 accounting_set_wakeup_time();
347 SMARTLIST_FOREACH(elts
, char *, cp
, tor_free(cp
));
348 smartlist_free(elts
);
352 static int hibernate_hard_limit_reached(void)
354 uint64_t hard_limit
= get_options()->AccountingMaxKB
<<10;
357 return n_bytes_read_in_interval
>= hard_limit
358 || n_bytes_written_in_interval
>= hard_limit
;
361 static int hibernate_soft_limit_reached(void)
363 uint64_t soft_limit
= (uint64_t) ((get_options()->AccountingMaxKB
<<10) * .99);
366 return n_bytes_read_in_interval
>= soft_limit
367 || n_bytes_written_in_interval
>= soft_limit
;
370 /** Called when we get a SIGINT, or when bandwidth soft limit
372 static void hibernate_begin(int new_state
, time_t now
) {
375 if(hibernate_state
== HIBERNATE_STATE_EXITING
) {
376 /* we've been called twice now. close immediately. */
377 log(LOG_NOTICE
,"Second sigint received; exiting now.");
382 tor_assert(hibernate_state
== HIBERNATE_STATE_LIVE
);
384 /* close listeners */
385 while((conn
= connection_get_by_type(CONN_TYPE_OR_LISTENER
)) ||
386 (conn
= connection_get_by_type(CONN_TYPE_AP_LISTENER
)) ||
387 (conn
= connection_get_by_type(CONN_TYPE_DIR_LISTENER
))) {
388 log_fn(LOG_INFO
,"Closing listener type %d", conn
->type
);
389 connection_mark_for_close(conn
);
392 /* XXX kill intro point circs */
393 /* XXX upload rendezvous service descriptors with no intro points */
395 if(new_state
== HIBERNATE_STATE_EXITING
) {
396 log(LOG_NOTICE
,"Interrupt: will shut down in %d seconds. Interrupt again to exit now.", SHUTDOWN_WAIT_LENGTH
);
397 hibernate_timeout
= time(NULL
) + SHUTDOWN_WAIT_LENGTH
;
398 } else { /* soft limit reached */
399 log_fn(LOG_NOTICE
,"Bandwidth limit reached; beginning hibernation.");
400 hibernate_timeout
= interval_end_time
;
403 hibernate_state
= new_state
;
406 /** Called when we've been hibernating and our timeout is reached. */
407 static void hibernate_end(int new_state
) {
409 tor_assert(hibernate_state
== HIBERNATE_STATE_LOWBANDWIDTH
||
410 hibernate_state
== HIBERNATE_STATE_DORMANT
);
412 /* listeners will be relaunched in run_scheduled_events() in main.c */
413 log_fn(LOG_NOTICE
,"Hibernation period ended. Resuming normal activity.");
415 hibernate_state
= new_state
;
416 hibernate_timeout
= 0; /* no longer hibernating */
419 /** A wrapper around hibernate_begin, for when we get SIGINT. */
420 void hibernate_begin_shutdown(void) {
421 hibernate_begin(HIBERNATE_STATE_EXITING
, time(NULL
));
424 /** A wrapper to expose whether we're hibernating. */
425 int we_are_hibernating(void) {
426 return hibernate_state
!= HIBERNATE_STATE_LIVE
;
429 /** The big function. Consider our environment and decide if it's
430 * time to start/stop hibernating.
432 void consider_hibernation(time_t now
) {
435 if (hibernate_state
== HIBERNATE_STATE_EXITING
) {
436 tor_assert(hibernate_timeout
);
437 if(hibernate_timeout
<= now
) {
438 log(LOG_NOTICE
,"Clean shutdown finished. Exiting.");
442 return; /* if exiting soon, don't worry about bandwidth limits */
445 if(hibernate_state
!= HIBERNATE_STATE_LIVE
) {
446 /* We've been hibernating because of bandwidth accounting. */
447 tor_assert(hibernate_timeout
);
448 if (hibernate_timeout
> now
) {
449 /* If we're hibernating, don't wake up until it's time, regardless of
450 * whether we're in a new interval */
453 /* The interval has ended, or it is wakeup time. Find out which */
454 accounting_run_housekeeping(now
);
455 if (interval_wakeup_time
<= now
) {
456 /* The interval hasn't changed, but interval_wakeup_time has passed.
457 * It's time to wake up. */
458 hibernate_end(HIBERNATE_STATE_LIVE
);
461 /* The interval has changed, and it isn't time to wake up yet. */
462 hibernate_timeout
= interval_wakeup_time
;
467 /* Else, see if it's time to start hibernating, or to go dormant. */
468 if (hibernate_state
== HIBERNATE_STATE_LIVE
&&
469 hibernate_soft_limit_reached()) {
470 log_fn(LOG_NOTICE
,"Bandwidth soft limit reached; commencing hibernation.");
471 hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH
, now
);
474 if (hibernate_state
== HIBERNATE_STATE_LOWBANDWIDTH
&&
475 hibernate_hard_limit_reached()) {
476 hibernate_state
= HIBERNATE_STATE_DORMANT
;
477 log_fn(LOG_NOTICE
,"Going dormant. Blowing away remaining connections.");
479 /* Close all OR/AP/exit conns. Leave dir conns. */
480 while((conn
= connection_get_by_type(CONN_TYPE_OR
)) ||
481 (conn
= connection_get_by_type(CONN_TYPE_AP
)) ||
482 (conn
= connection_get_by_type(CONN_TYPE_EXIT
))) {
483 log_fn(LOG_INFO
,"Closing conn type %d", conn
->type
);
484 connection_mark_for_close(conn
);