diff options
Diffstat (limited to 'src/app/config/statefile.c')
-rw-r--r-- | src/app/config/statefile.c | 154 |
1 files changed, 91 insertions, 63 deletions
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c index 89039a05b5..dcc55f1898 100644 --- a/src/app/config/statefile.c +++ b/src/app/config/statefile.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ * * This 'state' file is a typed key-value store that allows multiple * entries for the same key. It follows the same metaformat as described - * in confparse.c, and uses the same code to read and write itself. + * in confmgt.c, and uses the same code to read and write itself. * * The state file is most suitable for small values that don't change too * frequently. For values that become very large, we typically use a separate @@ -32,10 +32,12 @@ #include "core/or/or.h" #include "core/or/circuitstats.h" #include "app/config/config.h" -#include "app/config/confparse.h" +#include "feature/relay/transport_config.h" +#include "lib/confmgt/confmgt.h" #include "core/mainloop/mainloop.h" +#include "core/mainloop/netstatus.h" #include "core/mainloop/connection.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/client/entrynodes.h" #include "feature/hibernate/hibernate.h" #include "feature/stats/rephist.h" @@ -43,8 +45,10 @@ #include "feature/relay/routermode.h" #include "lib/sandbox/sandbox.h" #include "app/config/statefile.h" +#include "app/main/subsysmgr.h" #include "lib/encoding/confline.h" #include "lib/net/resolve.h" +#include "lib/version/torversion.h" #include "app/config/or_state_st.h" @@ -68,16 +72,14 @@ static config_abbrev_t state_abbrevs_[] = { * members with CONF_CHECK_VAR_TYPE. */ DUMMY_TYPECHECK_INSTANCE(or_state_t); -/*XXXX these next two are duplicates or near-duplicates from config.c */ -#define VAR(name,conftype,member,initvalue) \ - { name, CONFIG_TYPE_ ## conftype, offsetof(or_state_t, member), \ - initvalue CONF_TEST_MEMBERS(or_state_t, conftype, member) } -/** As VAR, but the option name and member name are the same. */ -#define V(member,conftype,initvalue) \ +#define VAR(varname,conftype,member,initvalue) \ + CONFIG_VAR_ETYPE(or_state_t, varname, conftype, member, 0, initvalue) +#define V(member,conftype,initvalue) \ VAR(#member, conftype, member, initvalue) /** Array of "state" variables saved to the ~/.tor/state file. */ -static config_var_t state_vars_[] = { +// clang-format off +static const config_var_t state_vars_[] = { /* Remember to document these in state-contents.txt ! */ V(AccountingBytesReadInInterval, MEMUNIT, NULL), @@ -103,19 +105,19 @@ static config_var_t state_vars_[] = { V(HidServRevCounter, LINELIST, NULL), V(BWHistoryReadEnds, ISOTIME, NULL), - V(BWHistoryReadInterval, UINT, "900"), + V(BWHistoryReadInterval, POSINT, "900"), V(BWHistoryReadValues, CSV, ""), V(BWHistoryReadMaxima, CSV, ""), V(BWHistoryWriteEnds, ISOTIME, NULL), - V(BWHistoryWriteInterval, UINT, "900"), + V(BWHistoryWriteInterval, POSINT, "900"), V(BWHistoryWriteValues, CSV, ""), V(BWHistoryWriteMaxima, CSV, ""), V(BWHistoryDirReadEnds, ISOTIME, NULL), - V(BWHistoryDirReadInterval, UINT, "900"), + V(BWHistoryDirReadInterval, POSINT, "900"), V(BWHistoryDirReadValues, CSV, ""), V(BWHistoryDirReadMaxima, CSV, ""), V(BWHistoryDirWriteEnds, ISOTIME, NULL), - V(BWHistoryDirWriteInterval, UINT, "900"), + V(BWHistoryDirWriteInterval, POSINT, "900"), V(BWHistoryDirWriteValues, CSV, ""), V(BWHistoryDirWriteMaxima, CSV, ""), @@ -126,48 +128,70 @@ static config_var_t state_vars_[] = { V(LastRotatedOnionKey, ISOTIME, NULL), V(LastWritten, ISOTIME, NULL), - V(TotalBuildTimes, UINT, NULL), - V(CircuitBuildAbandonedCount, UINT, "0"), + V(TotalBuildTimes, POSINT, NULL), + V(CircuitBuildAbandonedCount, POSINT, "0"), VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL), VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL), END_OF_CONFIG_VARS }; +// clang-format on #undef VAR #undef V static int or_state_validate(or_state_t *state, char **msg); -static int or_state_validate_cb(void *old_options, void *options, - void *default_options, - int from_setconf, char **msg); - -static void or_state_free_cb(void *state); +static int or_state_validate_cb(const void *old_options, + void *options, char **msg); /** Magic value for or_state_t. */ #define OR_STATE_MAGIC 0x57A73f57 /** "Extra" variable in the state that receives lines we can't parse. This * lets us preserve options from versions of Tor newer than us. */ -static config_var_t state_extra_var = { - "__extra", CONFIG_TYPE_LINELIST, offsetof(or_state_t, ExtraLines), NULL - CONF_TEST_MEMBERS(or_state_t, LINELIST, ExtraLines) +static struct_member_t state_extra_var = { + .name = "__extra", + .type = CONFIG_TYPE_LINELIST, + .offset = offsetof(or_state_t, ExtraLines), }; /** Configuration format for or_state_t. */ static const config_format_t state_format = { - sizeof(or_state_t), - OR_STATE_MAGIC, - offsetof(or_state_t, magic_), - state_abbrevs_, - NULL, - state_vars_, - or_state_validate_cb, - or_state_free_cb, - &state_extra_var, + .size = sizeof(or_state_t), + .magic = { + "or_state_t", + OR_STATE_MAGIC, + offsetof(or_state_t, magic_), + }, + .abbrevs = state_abbrevs_, + .vars = state_vars_, + .legacy_validate_fn = or_state_validate_cb, + .extra = &state_extra_var, + .has_config_suite = true, + .config_suite_offset = offsetof(or_state_t, substates_), }; +/* A global configuration manager for state-file objects */ +static config_mgr_t *state_mgr = NULL; + +/** Return the configuration manager for state-file objects. */ +STATIC const config_mgr_t * +get_state_mgr(void) +{ + if (PREDICT_UNLIKELY(state_mgr == NULL)) { + state_mgr = config_mgr_new(&state_format); + int rv = subsystems_register_state_formats(state_mgr); + tor_assert(rv == 0); + config_mgr_freeze(state_mgr); + } + return state_mgr; +} + +#define CHECK_STATE_MAGIC(s) STMT_BEGIN \ + config_check_toplevel_magic(get_state_mgr(), (s)); \ + STMT_END + /** Persistent serialized state. */ static or_state_t *global_state = NULL; @@ -249,25 +273,6 @@ validate_transports_in_state(or_state_t *state) return 0; } -static int -or_state_validate_cb(void *old_state, void *state, void *default_state, - int from_setconf, char **msg) -{ - /* We don't use these; only options do. Still, we need to match that - * signature. */ - (void) from_setconf; - (void) default_state; - (void) old_state; - - return or_state_validate(state, msg); -} - -static void -or_state_free_cb(void *state) -{ - or_state_free_(state); -} - /** Return 0 if every setting in <b>state</b> is reasonable, and a * permissible transition from <b>old_state</b>. Else warn and return -1. * Should have no side effects, except for normalizing the contents of @@ -276,6 +281,23 @@ or_state_free_cb(void *state) static int or_state_validate(or_state_t *state, char **msg) { + return config_validate(get_state_mgr(), NULL, state, msg); +} + +/** + * Legacy validation/normalization callback for or_state_t. See + * legacy_validate_fn_t for more information. + */ +static int +or_state_validate_cb(const void *old_state, void *state_, char **msg) +{ + /* There is not a meaningful concept of a state-to-state transition, + * since we do not reload the state after we start. */ + (void) old_state; + CHECK_STATE_MAGIC(state_); + + or_state_t *state = state_; + if (entry_guards_parse_state(state, 0, msg)<0) return -1; @@ -292,8 +314,11 @@ or_state_set(or_state_t *new_state) char *err = NULL; int ret = 0; tor_assert(new_state); - config_free(&state_format, global_state); + config_free(get_state_mgr(), global_state); global_state = new_state; + if (subsystems_set_state(get_state_mgr(), global_state) < 0) { + ret = -1; + } if (entry_guards_parse_state(global_state, 1, &err)<0) { log_warn(LD_GENERAL,"%s",err); tor_free(err); @@ -308,6 +333,7 @@ or_state_set(or_state_t *new_state) get_circuit_build_times_mutable(),global_state) < 0) { ret = -1; } + return ret; } @@ -353,9 +379,8 @@ or_state_save_broken(char *fname) STATIC or_state_t * or_state_new(void) { - or_state_t *new_state = tor_malloc_zero(sizeof(or_state_t)); - new_state->magic_ = OR_STATE_MAGIC; - config_init(&state_format, new_state); + or_state_t *new_state = config_new(get_state_mgr()); + config_init(get_state_mgr(), new_state); return new_state; } @@ -396,7 +421,7 @@ or_state_load(void) int assign_retval; if (config_get_lines(contents, &lines, 0)<0) goto done; - assign_retval = config_assign(&state_format, new_state, + assign_retval = config_assign(get_state_mgr(), new_state, lines, 0, &errmsg); config_free_lines(lines); if (assign_retval<0) @@ -423,7 +448,7 @@ or_state_load(void) or_state_save_broken(fname); tor_free(contents); - config_free(&state_format, new_state); + config_free(get_state_mgr(), new_state); new_state = or_state_new(); } else if (contents) { @@ -456,7 +481,7 @@ or_state_load(void) tor_free(fname); tor_free(contents); if (new_state) - config_free(&state_format, new_state); + config_free(get_state_mgr(), new_state); return r; } @@ -496,9 +521,11 @@ or_state_save(time_t now) /* Call everything else that might dirty the state even more, in order * to avoid redundant writes. */ + (void) subsystems_flush_state(get_state_mgr(), global_state); entry_guards_update_state(global_state); rep_hist_update_state(global_state); circuit_build_times_update_state(get_circuit_build_times(), global_state); + if (accounting_is_enabled(get_options())) accounting_run_housekeeping(now); @@ -507,7 +534,7 @@ or_state_save(time_t 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); + state = config_dump(get_state_mgr(), NULL, global_state, 1, 0); format_local_iso_time(tbuf, now); tor_asprintf(&contents, "# Tor state file last generated on %s local time\n" @@ -617,7 +644,7 @@ get_stored_bindaddr_for_server_transport(const char *transport) { /* See if the user explicitly asked for a specific listening address for this transport. */ - char *conf_bindaddr = get_transport_bindaddr_from_config(transport); + char *conf_bindaddr = pt_get_bindaddr_from_config(transport); if (conf_bindaddr) return conf_bindaddr; } @@ -717,7 +744,7 @@ or_state_free_(or_state_t *state) if (!state) return; - config_free(&state_format, state); + config_free(get_state_mgr(), state); } void @@ -725,4 +752,5 @@ or_state_free_all(void) { or_state_free(global_state); global_state = NULL; + config_mgr_free(state_mgr); } |