/** Write the persistent state to disk. Return 0 for success, <0 on failure. */ int or_state_save(time_t now) { char *state, *contents; char tbuf[ISO_TIME_LEN+1]; char *fname; tor_assert(global_state); if (global_state->next_write > now) return 0; /* Call everything else that might dirty the state even more, in order * to avoid redundant writes. */ entry_guards_update_state(global_state); rep_hist_update_state(global_state); circuit_build_times_update_state(&circ_times, global_state); if (accounting_is_enabled(get_options())) accounting_run_housekeeping(now); global_state->LastWritten = now; tor_free(global_state->TorVersion); tor_asprintf(&global_state->TorVersion, "Tor %s", get_version()); state = config_dump(&state_format, NULL, global_state, 1, 0); format_local_iso_time(tbuf, now); tor_asprintf(&contents, "# Tor state file last generated on %s local time\n" "# Other times below are in GMT\n" "# You *do not* need to edit this file.\n\n%s", tbuf, state); tor_free(state); fname = get_datadir_fname("state"); if (write_str_to_file(fname, contents, 0)<0) { log_warn(LD_FS, "Unable to write state to file \"%s\"; " "will try again later", fname); last_state_file_write_failed = 1; tor_free(fname); tor_free(contents); /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state * changes sooner). */ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL; return -1; } last_state_file_write_failed = 0; log_info(LD_GENERAL, "Saved state to \"%s\"", fname); tor_free(fname); tor_free(contents); if (server_mode(get_options())) global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL; else global_state->next_write = TIME_MAX; return 0; }
/** Helper function: called when we get a GETINFO request for an * accounting-related key on the control connection <b>conn</b>. If we can * answer the request for <b>question</b>, then set *<b>answer</b> to a newly * allocated string holding the result. Otherwise, set *<b>answer</b> to * NULL. */ int getinfo_helper_accounting(control_connection_t *conn, const char *question, char **answer, const char **errmsg) { (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")) { *answer = tor_malloc(32); tor_snprintf(*answer, 32, 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; *answer = tor_malloc(64); tor_snprintf(*answer, 64, 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; }
static void test_accounting_limits(void *arg) { or_options_t *options = get_options_mutable(); time_t fake_time = time(NULL); (void) arg; NS_MOCK(get_or_state); or_state = or_state_new(); options->AccountingMax = 100; options->AccountingRule = ACCT_MAX; tor_assert(accounting_is_enabled(options)); configure_accounting(fake_time); accounting_add_bytes(10, 0, 1); fake_time += 1; consider_hibernation(fake_time); tor_assert(we_are_hibernating() == 0); accounting_add_bytes(90, 0, 1); fake_time += 1; consider_hibernation(fake_time); tor_assert(we_are_hibernating() == 1); options->AccountingMax = 200; options->AccountingRule = ACCT_SUM; accounting_add_bytes(0, 10, 1); fake_time += 1; consider_hibernation(fake_time); tor_assert(we_are_hibernating() == 0); accounting_add_bytes(0, 90, 1); fake_time += 1; consider_hibernation(fake_time); tor_assert(we_are_hibernating() == 1); goto done; done: NS_UNMOCK(get_or_state); or_state_free(or_state); }