summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--Makefile.am21
-rw-r--r--ReleaseNotes3
-rw-r--r--changes/bug272845
-rw-r--r--changes/ticket309676
-rw-r--r--changes/ticket312405
-rw-r--r--changes/ticket315295
-rw-r--r--changes/ticket315324
-rw-r--r--changes/ticket315455
-rw-r--r--changes/ticket315544
-rwxr-xr-xscripts/git/pre-commit.git-hook4
-rwxr-xr-xscripts/maint/checkShellScripts.sh64
-rw-r--r--scripts/maint/practracker/README21
-rwxr-xr-xscripts/maint/practracker/includes.py2
-rwxr-xr-xscripts/maint/practracker/practracker.py19
-rw-r--r--src/app/config/config.c157
-rw-r--r--src/app/config/config.h5
-rw-r--r--src/app/config/confparse.c764
-rw-r--r--src/app/config/confparse.h155
-rw-r--r--src/app/config/or_options_st.h9
-rw-r--r--src/app/config/or_state_st.h9
-rw-r--r--src/app/config/statefile.c43
-rw-r--r--src/feature/dirauth/shared_random_state.c43
-rw-r--r--src/feature/dirparse/microdesc_parse.c11
-rw-r--r--src/feature/nodelist/describe.c101
-rw-r--r--src/feature/nodelist/microdesc_st.h2
-rw-r--r--src/feature/nodelist/nodelist.c3
-rw-r--r--src/feature/rend/rendclient.c2
-rw-r--r--src/lib/buf/buffers.c21
-rw-r--r--src/lib/cc/compat_compiler.h2
-rw-r--r--src/lib/conf/conftypes.h42
-rw-r--r--src/lib/confmgt/structvar.c18
-rw-r--r--src/lib/confmgt/typedvar.c134
-rw-r--r--src/lib/confmgt/typedvar.h29
-rw-r--r--src/lib/container/smartlist.c10
-rw-r--r--src/lib/container/smartlist.h9
-rw-r--r--src/lib/err/torerr.c3
-rw-r--r--src/lib/string/compat_string.h3
-rw-r--r--src/test/fuzz/fuzzing_common.c5
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_config.c92
-rw-r--r--src/test/test_confmgr.c325
-rw-r--r--src/test/test_confparse.c383
-rw-r--r--src/test/test_dir_handle_get.c3
-rw-r--r--src/test/test_entrynodes.c30
-rw-r--r--src/test/test_helpers.c2
-rw-r--r--src/test/test_hs_service.c10
-rw-r--r--src/test/test_microdesc.c52
-rw-r--r--src/test/test_options.c14
-rw-r--r--src/test/test_pt.c2
52 files changed, 1941 insertions, 725 deletions
diff --git a/ChangeLog b/ChangeLog
index 439c435a73..637a1dfcd0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -95,7 +95,7 @@ Changes in version 0.4.1.4-rc - 2019-07-25
o Minor bugfixes (circuit padding):
- On relays, properly check that a padding machine is absent before
logging a warning about it being absent. Fixes bug 30649; bugfix
- on 0.4.1.1-alpha.
+ on 0.4.0.1-alpha.
- Add two NULL checks in unreachable places to silence Coverity (CID
144729 and 1447291) and better future-proof ourselves. Fixes bug
31024; bugfix on 0.4.1.1-alpha.
diff --git a/Makefile.am b/Makefile.am
index d3cce3934d..a7d1cbe8e6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -168,6 +168,8 @@ EXTRA_DIST+= \
ReleaseNotes \
scripts/maint/checkIncludes.py \
scripts/maint/checkSpace.pl \
+ scripts/maint/checkShellScripts.sh \
+ scripts/maint/practracker/README \
scripts/maint/practracker/exceptions.txt \
scripts/maint/practracker/includes.py \
scripts/maint/practracker/metrics.py \
@@ -238,22 +240,7 @@ test: all
$(top_builddir)/src/test/test
shellcheck:
- # Only use shellcheck if it is present
- if command -v shellcheck; then \
- find "$(top_srcdir)" -name "*.sh" -not -path "$(top_srcdir)/src/ext/*" -not -path "$(top_srcdir)/src/rust/registry/*" -exec shellcheck {} +; \
- if [ -d "$(top_srcdir)/scripts/test" ]; then \
- shellcheck $(top_srcdir)/scripts/test/cov-diff $(top_srcdir)/scripts/test/coverage; \
- fi; \
- if [ -e "$(top_srcdir)/contrib/dirauth-tools/nagios-check-tor-authority-cert" ]; then \
- shellcheck "$(top_srcdir)/contrib/dirauth-tools/nagios-check-tor-authority-cert"; \
- fi; \
- if [ -e "$(top_srcdir)/contrib/client-tools/torify" ]; then \
- shellcheck "$(top_srcdir)/contrib/client-tools/torify"; \
- fi; \
- if [ -d "$(top_srcdir)/scripts/git" ]; then \
- shellcheck $(top_srcdir)/scripts/git/*.git-hook; \
- fi; \
- fi
+ $(top_srcdir)/scripts/maint/checkShellScripts.sh
check-local: check-spaces check-changes check-includes check-best-practices shellcheck
@@ -320,7 +307,7 @@ need-stem-path:
fi
test-stem: need-stem-path $(TESTING_TOR_BINARY)
- @$(PYTHON) "$$STEM_SOURCE_DIR"/run_tests.py --tor "$(TESTING_TOR_BINARY)" --integ --log notice --target RUN_ALL;
+ @$(PYTHON) "$$STEM_SOURCE_DIR"/run_tests.py --tor "$(TESTING_TOR_BINARY)" --integ --test control.controller --test control.base_controller --test process --log notice;
test-stem-full: need-stem-path $(TESTING_TOR_BINARY)
@$(PYTHON) "$$STEM_SOURCE_DIR"/run_tests.py --tor "$(TESTING_TOR_BINARY)" --all --log notice --target RUN_ALL,ONLINE -v;
diff --git a/ReleaseNotes b/ReleaseNotes
index aa88c5321e..60fcdd4506 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -83,6 +83,9 @@ Changes in version 0.4.1.5 - 2019-08-20
of bug 29875; bugfix on 0.3.0.1-alpha.
o Major bugfixes (circuit build, guard):
+ - On relays, properly check that a padding machine is absent before
+ logging a warning about it being absent. Fixes bug 30649; bugfix
+ on 0.4.0.1-alpha.
- When considering upgrading circuits from "waiting for guard" to
"open", always ignore circuits that are marked for close. Otherwise,
we can end up in the situation where a subsystem is notified that
diff --git a/changes/bug27284 b/changes/bug27284
new file mode 100644
index 0000000000..14fc2082fe
--- /dev/null
+++ b/changes/bug27284
@@ -0,0 +1,5 @@
+ o Minor bugfixes (ipv6):
+ - When parsing microdescriptors, we should check the IPv6 exit policy
+ alongside IPv4. Previously, we checked both exit policies for only
+ router info structures, while microdescriptors were IPv4-only. Fixes
+ bug 27284; bugfix on 0.2.3.1-alpha. Patch by Neel Chauhan.
diff --git a/changes/ticket30967 b/changes/ticket30967
new file mode 100644
index 0000000000..5fe9c980b6
--- /dev/null
+++ b/changes/ticket30967
@@ -0,0 +1,6 @@
+ o Testing:
+ - When checking shell scripts, ignore any user-created directories.
+ Closes ticket 30967.
+ o Minor features (git scripts):
+ - Call the shellcheck script from the pre-commit hook.
+ Closes ticket 30967.
diff --git a/changes/ticket31240 b/changes/ticket31240
new file mode 100644
index 0000000000..0fe37ff44b
--- /dev/null
+++ b/changes/ticket31240
@@ -0,0 +1,5 @@
+ o Minor features (configuration):
+ - The configuration code has been extended to allow splitting
+ configuration data across multiple objects. Previously, all
+ configuration data needed to be kept in a single object, which
+ tended to become bloated. Closes ticket 31240.
diff --git a/changes/ticket31529 b/changes/ticket31529
new file mode 100644
index 0000000000..84f982214c
--- /dev/null
+++ b/changes/ticket31529
@@ -0,0 +1,5 @@
+ o Minor features (debugging):
+ - Log a nonfatal assertion failure if we encounter a configuration
+ line whose command is "CLEAR" but which has a nonempty value.
+ This should be impossible, according to the rules of our
+ configuration line parsing. Closes ticket 31529.
diff --git a/changes/ticket31532 b/changes/ticket31532
new file mode 100644
index 0000000000..95bcbc517c
--- /dev/null
+++ b/changes/ticket31532
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - Use the ptrdiff_t type consistently for expressing variable offsets and
+ pointer differences. Previously we incorrectly (but harmlessly) used
+ int and sometimes off_t for these cases. Closes ticket 31532.
diff --git a/changes/ticket31545 b/changes/ticket31545
new file mode 100644
index 0000000000..58921c2ad8
--- /dev/null
+++ b/changes/ticket31545
@@ -0,0 +1,5 @@
+ o Code simplification and refactoring:
+ - Rewrite format_node_description() and router_get_verbose_nickname() to
+ use strlcpy() and strlcat(). The previous implementation used memcpy()
+ and pointer arithmetic, which was error-prone.
+ Closes ticket 31545. This is CID 1452819.
diff --git a/changes/ticket31554 b/changes/ticket31554
new file mode 100644
index 0000000000..73f4159ff3
--- /dev/null
+++ b/changes/ticket31554
@@ -0,0 +1,4 @@
+ o Minor features (stem tests):
+ - Change "make test-stem" so it only runs the stem tests that use tor.
+ This change makes test-stem faster and more reliable.
+ Closes ticket 31554.
diff --git a/scripts/git/pre-commit.git-hook b/scripts/git/pre-commit.git-hook
index b2a1847a2b..1c381ec60a 100755
--- a/scripts/git/pre-commit.git-hook
+++ b/scripts/git/pre-commit.git-hook
@@ -53,3 +53,7 @@ if [ -e "${PT_DIR}/practracker.py" ]; then
fi
fi
fi
+
+if [ -e scripts/maint/checkShellScripts.sh ]; then
+ scripts/maint/checkShellScripts.sh
+fi
diff --git a/scripts/maint/checkShellScripts.sh b/scripts/maint/checkShellScripts.sh
new file mode 100755
index 0000000000..02d1275c48
--- /dev/null
+++ b/scripts/maint/checkShellScripts.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019 The Tor Project, Inc.
+# See LICENSE for license information
+#
+# checkShellScripts.sh
+# --------------------
+# If shellcheck is installed, check all the shell scripts that we can fix.
+
+set -e
+
+# Only run this script if shellcheck is installed
+# command echoes the path to shellcheck, which is a useful diagnostic log
+if ! command -v shellcheck; then
+ printf "%s: Install shellcheck to check shell scripts.\\n" "$0"
+ exit 0
+fi
+
+# Some platforms don't have realpath
+if command -v realpath ; then
+ HERE=$(dirname "$(realpath "$0")")
+else
+ HERE=$(dirname "$0")
+ if [ ! -d "$HERE" ]; then
+ HERE=$(dirname "$PWD/$0")
+ fi
+fi
+TOPLEVEL=$(dirname "$(dirname "$HERE")")
+
+# Check we actually have a tor/src directory
+if [ ! -d "$TOPLEVEL/src" ]; then
+ printf "Error: Couldn't find src directory in expected location: %s\\n" \
+ "$TOPLEVEL/src"
+fi
+
+# Check *.sh scripts, but ignore the ones that we can't fix
+find "$TOPLEVEL" \
+ -name "*.sh" \
+ -path "$TOPLEVEL/contrib/*" \
+ -path "$TOPLEVEL/doc/*" \
+ -path "$TOPLEVEL/scripts/*" \
+ -path "$TOPLEVEL/src/*" \
+ -not -path "$TOPLEVEL/src/ext/*" \
+ -not -path "$TOPLEVEL/src/rust/registry/*" \
+ -exec shellcheck {} +
+
+# Check scripts that aren't named *.sh
+if [ -d "$TOPLEVEL/scripts/test" ]; then
+ shellcheck \
+ "$TOPLEVEL/scripts/test/cov-diff" \
+ "$TOPLEVEL/scripts/test/coverage"
+fi
+if [ -e \
+ "$TOPLEVEL/contrib/dirauth-tools/nagios-check-tor-authority-cert" \
+ ]; then
+ shellcheck \
+ "$TOPLEVEL/contrib/dirauth-tools/nagios-check-tor-authority-cert"
+fi
+if [ -e "$TOPLEVEL/contrib/client-tools/torify" ]; then
+ shellcheck "$TOPLEVEL/contrib/client-tools/torify"
+fi
+if [ -d "$TOPLEVEL/scripts/git" ]; then
+ shellcheck "$TOPLEVEL/scripts/git/"*.git-hook
+fi
diff --git a/scripts/maint/practracker/README b/scripts/maint/practracker/README
new file mode 100644
index 0000000000..d978b39806
--- /dev/null
+++ b/scripts/maint/practracker/README
@@ -0,0 +1,21 @@
+Practracker is a simple python tool that keeps track of places where
+our code is ugly, and tries to warn us about new ones or ones that
+get worse.
+
+Right now, practracker looks for the following kinds of
+best-practices violations:
+
+ .c files greater than 3000 lines long
+ .h files greater than 500 lines long
+ .c files with more than 50 includes
+ .h files with more than 15 includes
+
+ All files that include a local header not listed in a .may_include
+ file in the same directory, when that .may_include file has an
+ "!advisory" marker.
+
+The list of current violations is tracked in exceptions.txt; slight
+deviations of the current exceptions cause warnings, whereas large
+ones cause practracker to fail.
+
+For usage information, run "practracker.py --help".
diff --git a/scripts/maint/practracker/includes.py b/scripts/maint/practracker/includes.py
index fcc527c983..397439b4ef 100755
--- a/scripts/maint/practracker/includes.py
+++ b/scripts/maint/practracker/includes.py
@@ -212,7 +212,7 @@ def consider_include_rules(fname, f):
log_sorted_levels = False
def walk_c_files(topdir="src"):
- """Run through all c and h files under topdir, looking for
+ """Run through all .c and .h files under topdir, looking for
include-rule violations. Yield those violations."""
for dirpath, dirnames, fnames in os.walk(topdir):
diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py
index 6483b88da1..b477cd60c0 100755
--- a/scripts/maint/practracker/practracker.py
+++ b/scripts/maint/practracker/practracker.py
@@ -7,7 +7,8 @@ Go through the various .c files and collect metrics about them. If the metrics
violate some of our best practices and they are not found in the optional
exceptions file, then log a problem about them.
-We currently do metrics about file size, function size and number of includes.
+We currently do metrics about file size, function size and number of includes,
+for C source files and headers.
practracker.py should be run with its second argument pointing to the Tor
top-level source directory like this:
@@ -143,8 +144,12 @@ HEADER="""\
#
# There are three kinds of problems that we recognize right now:
# function-size -- a function of more than {MAX_FUNCTION_SIZE} lines.
-# file-size -- a file of more than {MAX_FILE_SIZE} lines.
-# include-count -- a file with more than {MAX_INCLUDE_COUNT} #includes.
+# file-size -- a .c file of more than {MAX_FILE_SIZE} lines, or a .h
+# file with more than {MAX_H_FILE_SIZE} lines.
+# include-count -- a .c file with more than {MAX_INCLUDE_COUNT} #includes,
+ or a .h file with more than {MAX_H_INCLUDE_COUNT} #includes.
+# dependency-violation -- a file includes a header that it should
+# not, according to an advisory .may_include file.
#
# Each line below represents a single exception that practracker should
# _ignore_. Each line has four parts:
@@ -184,13 +189,13 @@ def main(argv):
parser.add_argument("--terse", action="store_true",
help="Do not emit helpful instructions.")
parser.add_argument("--max-h-file-size", default=MAX_H_FILE_SIZE,
- help="Maximum lines per .H file")
+ help="Maximum lines per .h file")
parser.add_argument("--max-h-include-count", default=MAX_H_INCLUDE_COUNT,
- help="Maximum includes per .H file")
+ help="Maximum includes per .h file")
parser.add_argument("--max-file-size", default=MAX_FILE_SIZE,
- help="Maximum lines per C file")
+ help="Maximum lines per .c file")
parser.add_argument("--max-include-count", default=MAX_INCLUDE_COUNT,
- help="Maximum includes per C file")
+ help="Maximum includes per .c file")
parser.add_argument("--max-function-size", default=MAX_FUNCTION_SIZE,
help="Maximum lines per function")
parser.add_argument("--max-dependency-violations", default=MAX_DEP_VIOLATIONS,
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 740315f3e4..0cbc223d02 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -843,15 +843,15 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
static int options_validate_cb(void *old_options, void *options,
void *default_options,
int from_setconf, char **msg);
-static void options_free_cb(void *options);
static void cleanup_protocol_warning_severity_level(void);
static void set_protocol_warning_severity_level(int warning_severity);
+static void options_clear_cb(const config_mgr_t *mgr, void *opts);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */
-STATIC const config_format_t options_format = {
+static const config_format_t options_format = {
sizeof(or_options_t),
{
"or_options_t",
@@ -862,8 +862,9 @@ STATIC const config_format_t options_format = {
option_deprecation_notes_,
option_vars_,
options_validate_cb,
- options_free_cb,
- NULL
+ options_clear_cb,
+ NULL,
+ offsetof(or_options_t, subconfigs_),
};
/*
@@ -895,6 +896,20 @@ static int in_option_validation = 0;
/* True iff we've initialized libevent */
static int libevent_initialized = 0;
+/* A global configuration manager to handle all configuration objects. */
+static config_mgr_t *options_mgr = NULL;
+
+/** Return the global configuration manager object for torrc options. */
+STATIC const config_mgr_t *
+get_options_mgr(void)
+{
+ if (PREDICT_UNLIKELY(options_mgr == NULL)) {
+ options_mgr = config_mgr_new(&options_format);
+ config_mgr_freeze(options_mgr);
+ }
+ return options_mgr;
+}
+
/** Return the contents of our frontpage string, or NULL if not configured. */
MOCK_IMPL(const char*,
get_dirportfrontpage, (void))
@@ -951,9 +966,6 @@ get_options_defaults(void)
int
set_options(or_options_t *new_val, char **msg)
{
- int i;
- smartlist_t *elements;
- config_line_t *line;
or_options_t *old_options = global_options;
global_options = new_val;
/* Note that we pass the *old* options below, for comparison. It
@@ -975,35 +987,16 @@ set_options(or_options_t *new_val, char **msg)
/* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
* just starting up then the old_options will be undefined. */
if (old_options && old_options != global_options) {
- elements = smartlist_new();
- for (i=0; options_format.vars[i].member.name; ++i) {
- const config_var_t *var = &options_format.vars[i];
- const char *var_name = var->member.name;
- if (config_var_is_contained(var)) {
- /* something else will check this var, or it doesn't need checking */
- continue;
- }
- if (!config_is_same(&options_format, new_val, old_options, var_name)) {
- line = config_get_assigned_option(&options_format, new_val,
- var_name, 1);
-
- if (line) {
- config_line_t *next;
- for (; line; line = next) {
- next = line->next;
- smartlist_add(elements, line->key);
- smartlist_add(elements, line->value);
- tor_free(line);
- }
- } else {
- smartlist_add_strdup(elements, options_format.vars[i].member.name);
- smartlist_add(elements, NULL);
- }
- }
+ smartlist_t *elements = smartlist_new();
+ config_line_t *changes =
+ config_get_changes(get_options_mgr(), old_options, new_val);
+ for (config_line_t *line = changes; line; line = line->next) {
+ smartlist_add(elements, line->key);
+ smartlist_add(elements, line->value);
}
control_event_conf_changed(elements);
- SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
+ config_free_lines(changes);
}
if (old_options != global_options) {
@@ -1019,11 +1012,11 @@ set_options(or_options_t *new_val, char **msg)
/** Release additional memory allocated in options
*/
-STATIC void
-or_options_free_(or_options_t *options)
+static void
+options_clear_cb(const config_mgr_t *mgr, void *opts)
{
- if (!options)
- return;
+ (void)mgr;
+ or_options_t *options = opts;
routerset_free(options->ExcludeExitNodesUnion_);
if (options->NodeFamilySets) {
@@ -1046,7 +1039,14 @@ or_options_free_(or_options_t *options)
tor_free(options->command_arg);
tor_free(options->master_key_fname);
config_free_lines(options->MyFamily);
- config_free(&options_format, options);
+}
+
+/** Release all memory allocated in options
+ */
+STATIC void
+or_options_free_(or_options_t *options)
+{
+ config_free(get_options_mgr(), options);
}
/** Release all memory and resources held by global configuration structures.
@@ -1080,6 +1080,8 @@ config_free_all(void)
have_parsed_cmdline = 0;
libevent_initialized = 0;
+
+ config_mgr_free(options_mgr);
}
/** Make <b>address</b> -- a piece of information related to our operation as
@@ -2547,7 +2549,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
param = tor_malloc_zero(sizeof(config_line_t));
param->key = is_cmdline ? tor_strdup(argv[i]) :
- tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
+ tor_strdup(config_expand_abbrev(get_options_mgr(), s, 1, 1));
param->value = arg;
param->command = command;
param->next = NULL;
@@ -2573,8 +2575,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
int
option_is_recognized(const char *key)
{
- const config_var_t *var = config_find_option(&options_format, key);
- return (var != NULL);
+ return config_find_option_name(get_options_mgr(), key) != NULL;
}
/** Return the canonical name of a configuration option, or NULL
@@ -2582,8 +2583,7 @@ option_is_recognized(const char *key)
const char *
option_get_canonical_name(const char *key)
{
- const config_var_t *var = config_find_option(&options_format, key);
- return var ? var->member.name : NULL;
+ return config_find_option_name(get_options_mgr(), key);
}
/** Return a canonical list of the options assigned for key.
@@ -2591,7 +2591,7 @@ option_get_canonical_name(const char *key)
config_line_t *
option_get_assignment(const or_options_t *options, const char *key)
{
- return config_get_assigned_option(&options_format, options, key, 1);
+ return config_get_assigned_option(get_options_mgr(), options, key, 1);
}
/** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2607,9 +2607,9 @@ setopt_err_t
options_trial_assign(config_line_t *list, unsigned flags, char **msg)
{
int r;
- or_options_t *trial_options = config_dup(&options_format, get_options());
+ or_options_t *trial_options = config_dup(get_options_mgr(), get_options());
- if ((r=config_assign(&options_format, trial_options,
+ if ((r=config_assign(get_options_mgr(), trial_options,
list, flags, msg)) < 0) {
or_options_free(trial_options);
return r;
@@ -2664,25 +2664,25 @@ print_usage(void)
static void
list_torrc_options(void)
{
- int i;
- for (i = 0; option_vars_[i].member.name; ++i) {
- const config_var_t *var = &option_vars_[i];
+ smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
+ SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
if (! config_var_is_settable(var)) {
/* This variable cannot be set, or cannot be set by this name. */
continue;
}
printf("%s\n", var->member.name);
- }
+ } SMARTLIST_FOREACH_END(var);
+ smartlist_free(vars);
}
/** Print all deprecated but non-obsolete torrc options. */
static void
list_deprecated_options(void)
{
- const config_deprecation_t *d;
- for (d = option_deprecation_notes_; d->name; ++d) {
- printf("%s\n", d->name);
- }
+ smartlist_t *deps = config_mgr_list_deprecated_vars(get_options_mgr());
+ SMARTLIST_FOREACH(deps, const char *, name,
+ printf("%s\n", name));
+ smartlist_free(deps);
}
/** Print all compile-time modules and their enabled/disabled status. */
@@ -2992,7 +2992,7 @@ is_local_addr, (const tor_addr_t *addr))
or_options_t *
options_new(void)
{
- return config_new(&options_format);
+ return config_new(get_options_mgr());
}
/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3000,10 +3000,10 @@ options_new(void)
void
options_init(or_options_t *options)
{
- config_init(&options_format, options);
+ config_init(get_options_mgr(), options);
config_line_t *dflts = get_options_defaults();
char *msg=NULL;
- if (config_assign(&options_format, options, dflts,
+ if (config_assign(get_options_mgr(), options, dflts,
CAL_WARN_DEPRECATIONS, &msg)<0) {
log_err(LD_BUG, "Unable to set default options: %s", msg);
tor_free(msg);
@@ -3040,7 +3040,7 @@ options_dump(const or_options_t *options, int how_to_dump)
return NULL;
}
- return config_dump(&options_format, use_defaults, options, minimal, 0);
+ return config_dump(get_options_mgr(), use_defaults, options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@@ -3172,13 +3172,6 @@ options_validate_cb(void *old_options, void *options, void *default_options,
return rv;
}
-/** Callback to free an or_options_t */
-static void
-options_free_cb(void *options)
-{
- or_options_free_(options);
-}
-
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
#if defined(__GNUC__) && __GNUC__ <= 3
@@ -4435,7 +4428,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
STMT_BEGIN \
if (!options->TestingTorNetwork && \
!options->UsingTestNetworkDefaults_ && \
- !config_is_same(&options_format,options, \
+ !config_is_same(get_options_mgr(),options, \
default_options,#arg)) { \
REJECT(#arg " may only be changed in testing Tor " \
"networks!"); \
@@ -5411,8 +5404,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
oldoptions = global_options; /* get_options unfortunately asserts if
this is the first time we run*/
- newoptions = tor_malloc_zero(sizeof(or_options_t));
- newoptions->magic_ = OR_OPTIONS_MAGIC;
+ newoptions = options_new();
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
@@ -5431,7 +5423,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err = SETOPT_ERR_PARSE;
goto err;
}
- retval = config_assign(&options_format, newoptions, cl,
+ retval = config_assign(get_options_mgr(), newoptions, cl,
CAL_WARN_DEPRECATIONS, msg);
config_free_lines(cl);
if (retval < 0) {
@@ -5439,15 +5431,15 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = config_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(get_options_mgr(), newoptions);
}
if (newdefaultoptions == NULL) {
- newdefaultoptions = config_dup(&options_format, global_default_options);
+ newdefaultoptions = config_dup(get_options_mgr(), global_default_options);
}
/* Go through command-line variables too */
- retval = config_assign(&options_format, newoptions,
+ retval = config_assign(get_options_mgr(), newoptions,
global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
@@ -8133,9 +8125,8 @@ getinfo_helper_config(control_connection_t *conn,
(void) errmsg;
if (!strcmp(question, "config/names")) {
smartlist_t *sl = smartlist_new();
- int i;
- for (i = 0; option_vars_[i].member.name; ++i) {
- const config_var_t *var = &option_vars_[i];
+ smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
+ SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
/* don't tell controller about invisible options */
if (config_var_is_invisible(var))
continue;
@@ -8143,26 +8134,27 @@ getinfo_helper_config(control_connection_t *conn,
if (!type)
continue;
smartlist_add_asprintf(sl, "%s %s\n",var->member.name,type);
- }
+ } SMARTLIST_FOREACH_END(var);
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
+ smartlist_free(vars);
} else if (!strcmp(question, "config/defaults")) {
smartlist_t *sl = smartlist_new();
int dirauth_lines_seen = 0, fallback_lines_seen = 0;
- for (int i = 0; option_vars_[i].member.name; ++i) {
- const config_var_t *var = &option_vars_[i];
+ smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
+ SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
if (var->initvalue != NULL) {
- if (strcmp(option_vars_[i].member.name, "DirAuthority") == 0) {
+ if (strcmp(var->member.name, "DirAuthority") == 0) {
/*
* Count dirauth lines we have a default for; we'll use the
* count later to decide whether to add the defaults manually
*/
++dirauth_lines_seen;
}
- if (strcmp(option_vars_[i].member.name, "FallbackDir") == 0) {
+ if (strcmp(var->member.name, "FallbackDir") == 0) {
/*
- * Similarly count fallback lines, so that we can decided later
+ * Similarly count fallback lines, so that we can decide later
* to add the defaults manually.
*/
++fallback_lines_seen;
@@ -8171,7 +8163,8 @@ getinfo_helper_config(control_connection_t *conn,
smartlist_add_asprintf(sl, "%s %s\n",var->member.name,val);
tor_free(val);
}
- }
+ } SMARTLIST_FOREACH_END(var);
+ smartlist_free(vars);
if (dirauth_lines_seen == 0) {
/*
diff --git a/src/app/config/config.h b/src/app/config/config.h
index c6feb89fe7..44f09e5ee9 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -247,9 +247,8 @@ int options_any_client_port_set(const or_options_t *options);
#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
STATIC int options_act(const or_options_t *old_options);
-#ifdef TOR_UNIT_TESTS
-extern const struct config_format_t options_format;
-#endif
+struct config_mgr_t;
+STATIC const struct config_mgr_t *get_options_mgr(void);
STATIC port_cfg_t *port_cfg_new(size_t namelen);
#define port_cfg_free(port) \
diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c
index 6e2624466a..0e941bab6c 100644
--- a/src/app/config/confparse.c
+++ b/src/app/config/confparse.c
@@ -37,16 +37,352 @@
#include "lib/string/printf.h"
#include "lib/string/util_string.h"
-static void config_reset(const config_format_t *fmt, void *options,
- const config_var_t *var, int use_defaults);
+#include "ext/siphash.h"
+
+/**
+ * A managed_var_t is an internal wrapper around a config_var_t in
+ * a config_format_t structure. It is used by config_mgr_t to
+ * keep track of which option goes with which structure. */
+typedef struct managed_var_t {
+ /**
+ * A pointer to the config_var_t for this option.
+ */
+ const config_var_t *cvar;
+ /**
+ * The index of the object in which this option is stored. It is
+ * IDX_TOPLEVEL to indicate that the object is the top-level object.
+ **/
+ int object_idx;
+} managed_var_t;
+
+static void config_reset(const config_mgr_t *fmt, void *options,
+ const managed_var_t *var, int use_defaults);
+static void config_mgr_register_fmt(config_mgr_t *mgr,
+ const config_format_t *fmt,
+ int object_idx);
+
+/** Release all storage held in a managed_var_t. */
+static void
+managed_var_free_(managed_var_t *mv)
+{
+ if (!mv)
+ return;
+ tor_free(mv);
+}
+#define managed_var_free(mv) \
+ FREE_AND_NULL(managed_var_t, managed_var_free_, (mv))
+
+struct config_suite_t {
+ /** A list of configuration objects managed by a given configuration
+ * manager. They are stored in the same order as the config_format_t
+ * objects in the manager's list of subformats. */
+ smartlist_t *configs;
+};
+
+/**
+ * Allocate a new empty config_suite_t.
+ **/
+static config_suite_t *
+config_suite_new(void)
+{
+ config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
+ suite->configs = smartlist_new();
+ return suite;
+}
+
+/** Release all storage held by a config_suite_t. (Does not free
+ * any configuration objects it holds; the caller must do that first.) */
+static void
+config_suite_free_(config_suite_t *suite)
+{
+ if (!suite)
+ return;
+ smartlist_free(suite->configs);
+ tor_free(suite);
+}
+
+#define config_suite_free(suite) \
+ FREE_AND_NULL(config_suite_t, config_suite_free_, (suite))
+
+struct config_mgr_t {
+ /** The 'top-level' configuration format. This one is used for legacy
+ * options that have not yet been assigned to different sub-modules.
+ *
+ * (NOTE: for now, this is the only config_format_t that a config_mgr_t
+ * contains. A subsequent commit will add more. XXXX)
+ */
+ const config_format_t *toplevel;
+ /**
+ * List of second-level configuration format objects that this manager
+ * also knows about.
+ */
+ smartlist_t *subconfigs;
+ /** A smartlist of managed_var_t objects for all configuration formats. */
+ smartlist_t *all_vars;
+ /** A smartlist of config_abbrev_t objects for all configuration
+ * formats. These objects are used to track synonyms and abbreviations for
+ * different configuration options. */
+ smartlist_t *all_abbrevs;
+ /** A smartlist of config_deprecation_t for all configuration formats. */
+ smartlist_t *all_deprecations;
+ /** True if this manager has been frozen and cannot have any more formats
+ * added to it. A manager must be frozen before it can be used to construct
+ * or manipulate objects. */
+ bool frozen;
+ /** A replacement for the magic number of the toplevel object. We override
+ * that number to make it unique for this particular config_mgr_t, so that
+ * an object constructed with one mgr can't be used with another, even if
+ * those managers' contents are equal.
+ */
+ struct_magic_decl_t toplevel_magic;
+};
+
+#define IDX_TOPLEVEL (-1)
+
+/** Create a new config_mgr_t to manage a set of configuration objects to be
+ * wrapped under <b>toplevel_fmt</b>. */
+config_mgr_t *
+config_mgr_new(const config_format_t *toplevel_fmt)
+{
+ config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
+ mgr->subconfigs = smartlist_new();
+ mgr->all_vars = smartlist_new();
+ mgr->all_abbrevs = smartlist_new();
+ mgr->all_deprecations = smartlist_new();
+
+ config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
+ mgr->toplevel = toplevel_fmt;
+
+ return mgr;
+}
+
+/** Add a config_format_t to a manager, with a specified (unique) index. */
+static void
+config_mgr_register_fmt(config_mgr_t *mgr,
+ const config_format_t *fmt,
+ int object_idx)
+{
+ int i;
+
+ tor_assertf(!mgr->frozen,
+ "Tried to add a format to a configuration manager after "
+ "it had been frozen.");
+
+ if (object_idx != IDX_TOPLEVEL) {
+ tor_assertf(fmt->config_suite_offset < 0,
+ "Tried to register a toplevel format in a non-toplevel position");
+ }
+ tor_assertf(fmt != mgr->toplevel &&
+ ! smartlist_contains(mgr->subconfigs, fmt),
+ "Tried to register an already-registered format.");
+
+ /* register variables */
+ for (i = 0; fmt->vars[i].member.name; ++i) {
+ managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
+ mv->cvar = &fmt->vars[i];
+ mv->object_idx = object_idx;
+ smartlist_add(mgr->all_vars, mv);
+ }
+
+ /* register abbrevs */
+ if (fmt->abbrevs) {
+ for (i = 0; fmt->abbrevs[i].abbreviated; ++i) {
+ smartlist_add(mgr->all_abbrevs, (void*)&fmt->abbrevs[i]);
+ }
+ }
+
+ /* register deprecations. */
+ if (fmt->deprecations) {
+ const config_deprecation_t *d;
+ for (d = fmt->deprecations; d->name; ++d) {
+ smartlist_add(mgr->all_deprecations, (void*)d);
+ }
+ }
+}
+
+/**
+ * Add a new format to this configuration object. Asserts on failure.
+ *
+ * Returns an internal "index" value used to identify this format within
+ * all of those formats contained in <b>mgr</b>. This index value
+ * should not generally be used outside of this module.
+ **/
+int
+config_mgr_add_format(config_mgr_t *mgr,
+ const config_format_t *fmt)
+{
+ tor_assert(mgr);
+ int idx = smartlist_len(mgr->subconfigs);
+ config_mgr_register_fmt(mgr, fmt, idx);
+ smartlist_add(mgr->subconfigs, (void *)fmt);
+ return idx;
+}
+
+/** Return a pointer to the config_suite_t * pointer inside a
+ * configuration object; returns NULL if there is no such member. */
+static inline config_suite_t **
+config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
+{
+ if (mgr->toplevel->config_suite_offset < 0)
+ return NULL;
+ return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
+}
+
+/**
+ * Return a pointer to the configuration object within <b>toplevel</b> whose
+ * index is <b>idx</b>.
+ *
+ * NOTE: XXXX Eventually, there will be multiple objects supported within the
+ * toplevel object. For example, the or_options_t will contain pointers
+ * to configuration objects for other modules. This function gets
+ * the sub-object for a particular module.
+ */
+STATIC void *
+config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
+{
+ tor_assert(mgr);
+ tor_assert(toplevel);
+ if (idx == IDX_TOPLEVEL)
+ return toplevel;
+
+ tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
+ "Index %d is out of range.", idx);
+ config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
+ tor_assert(suite);
+ tor_assert(smartlist_len(mgr->subconfigs) ==
+ smartlist_len((*suite)->configs));
+
+ return smartlist_get((*suite)->configs, idx);
+}
+
+/** As config_mgr_get_obj_mutable(), but return a const pointer. */
+STATIC const void *
+config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
+{
+ return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
+}
+
+/** Sorting helper for smartlist of managed_var_t */
+static int
+managed_var_cmp(const void **a, const void **b)
+{
+ const managed_var_t *mv1 = *(const managed_var_t**)a;
+ const managed_var_t *mv2 = *(const managed_var_t**)b;
+
+ return strcasecmp(mv1->cvar->member.name, mv2->cvar->member.name);
+}
+
+/**
+ * Mark a configuration manager as "frozen", so that no more formats can be
+ * added, and so that it can be used for manipulating configuration objects.
+ **/
+void
+config_mgr_freeze(config_mgr_t *mgr)
+{
+ static uint64_t mgr_count = 0;
+
+ smartlist_sort(mgr->all_vars, managed_var_cmp);
+ memcpy(&mgr->toplevel_magic, &mgr->toplevel->magic,
+ sizeof(struct_magic_decl_t));
+ uint64_t magic_input[3] = { mgr->toplevel_magic.magic_val,
+ (uint64_t) (uintptr_t) mgr,
+ ++mgr_count };
+ mgr->toplevel_magic.magic_val =
+ (uint32_t)siphash24g(magic_input, sizeof(magic_input));
+ mgr->frozen = true;
+}
+
+/** Release all storage held in <b>mgr</b> */
+void
+config_mgr_free_(config_mgr_t *mgr)
+{
+ if (!mgr)
+ return;
+ SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv, managed_var_free(mv));
+ smartlist_free(mgr->all_vars);
+ smartlist_free(mgr->all_abbrevs);
+ smartlist_free(mgr->all_deprecations);
+ smartlist_free(mgr->subconfigs);
+ memset(mgr, 0, sizeof(*mgr));
+ tor_free(mgr);
+}
+
+/** Return a new smartlist_t containing a config_var_t for every variable that
+ * <b>mgr</b> knows about. The elements of this smartlist do not need
+ * to be freed; they have the same lifespan as <b>mgr</b>. */
+smartlist_t *
+config_mgr_list_vars(const config_mgr_t *mgr)
+{
+ smartlist_t *result = smartlist_new();
+ tor_assert(mgr);
+ SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv,
+ smartlist_add(result, (void*) mv->cvar));
+ return result;
+}
+
+/** Return a new smartlist_t containing the names of all deprecated variables.
+ * The elements of this smartlist do not need to be freed; they have the same
+ * lifespan as <b>mgr</b>.
+ */
+smartlist_t *
+config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
+{
+ smartlist_t *result = smartlist_new();
+ tor_assert(mgr);
+ SMARTLIST_FOREACH(mgr->all_deprecations, config_deprecation_t *, d,
+ smartlist_add(result, (char*)d->name));
+ return result;
+}
+
+/** Assert that the magic fields in <b>options</b> and its subsidiary
+ * objects are all okay. */
+static void
+config_mgr_assert_magic_ok(const config_mgr_t *mgr,
+ const void *options)
+{
+ tor_assert(mgr);
+ tor_assert(options);
+ tor_assert(mgr->frozen);
+ struct_check_magic(options, &mgr->toplevel_magic);
+
+ config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
+ if (suitep == NULL) {
+ tor_assert(smartlist_len(mgr->subconfigs) == 0);
+ return;
+ }
+
+ tor_assert(smartlist_len((*suitep)->configs) ==
+ smartlist_len(mgr->subconfigs));
+ SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
+ void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
+ tor_assert(obj);
+ struct_check_magic(obj, &fmt->magic);
+ } SMARTLIST_FOREACH_END(fmt);
+}
+
+/** Macro: assert that <b>cfg</b> has the right magic field for
+ * <b>mgr</b>. */
+#define CONFIG_CHECK(mgr, cfg) STMT_BEGIN \
+ config_mgr_assert_magic_ok((mgr), (cfg)); \
+ STMT_END
/** Allocate an empty configuration object of a given format type. */
void *
-config_new(const config_format_t *fmt)
+config_new(const config_mgr_t *mgr)
{
- void *opts = tor_malloc_zero(fmt->size);
- struct_set_magic(opts, &fmt->magic);
- CONFIG_CHECK(fmt, opts);
+ tor_assert(mgr->frozen);
+ void *opts = tor_malloc_zero(mgr->toplevel->size);
+ struct_set_magic(opts, &mgr->toplevel_magic);
+ config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
+ if (suitep) {
+ *suitep = config_suite_new();
+ SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
+ void *obj = tor_malloc_zero(fmt->size);
+ struct_set_magic(obj, &fmt->magic);
+ smartlist_add((*suitep)->configs, obj);
+ } SMARTLIST_FOREACH_END(fmt);
+ }
+ CONFIG_CHECK(mgr, opts);
return opts;
}
@@ -60,29 +396,26 @@ config_new(const config_format_t *fmt)
* apply abbreviations that work for the config file and the command line.
* If <b>warn_obsolete</b> is set, warn about deprecated names. */
const char *
-config_expand_abbrev(const config_format_t *fmt, const char *option,
+config_expand_abbrev(const config_mgr_t *mgr, const char *option,
int command_line, int warn_obsolete)
{
- int i;
- if (! fmt->abbrevs)
- return option;
- for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
+ SMARTLIST_FOREACH_BEGIN(mgr->all_abbrevs, const config_abbrev_t *, abbrev) {
/* Abbreviations are case insensitive. */
- if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
- (command_line || !fmt->abbrevs[i].commandline_only)) {
- if (warn_obsolete && fmt->abbrevs[i].warn) {
+ if (!strcasecmp(option, abbrev->abbreviated) &&
+ (command_line || !abbrev->commandline_only)) {
+ if (warn_obsolete && abbrev->warn) {
log_warn(LD_CONFIG,
"The configuration option '%s' is deprecated; "
"use '%s' instead.",
- fmt->abbrevs[i].abbreviated,
- fmt->abbrevs[i].full);
+ abbrev->abbreviated,
+ abbrev->full);
}
/* Keep going through the list in case we want to rewrite it more.
* (We could imagine recursing here, but I don't want to get the
* user into an infinite loop if we craft our list wrong.) */
- option = fmt->abbrevs[i].full;
+ option = abbrev->full;
}
- }
+ } SMARTLIST_FOREACH_END(abbrev);
return option;
}
@@ -90,61 +423,92 @@ config_expand_abbrev(const config_format_t *fmt, const char *option,
* explaining why it is deprecated (which may be an empty string). Return NULL
* if it is not deprecated. The <b>key</b> field must be fully expanded. */
const char *
-config_find_deprecation(const config_format_t *fmt, const char *key)
+config_find_deprecation(const config_mgr_t *mgr, const char *key)
{
- if (BUG(fmt == NULL) || BUG(key == NULL))
+ if (BUG(mgr == NULL) || BUG(key == NULL))
return NULL; // LCOV_EXCL_LINE
- if (fmt->deprecations == NULL)
- return NULL;
- const config_deprecation_t *d;
- for (d = fmt->deprecations; d->name; ++d) {
+ SMARTLIST_FOREACH_BEGIN(mgr->all_deprecations, const config_deprecation_t *,
+ d) {
if (!strcasecmp(d->name, key)) {
return d->why_deprecated ? d->why_deprecated : "";
}
- }
+ } SMARTLIST_FOREACH_END(d);
return NULL;
}
-/** If <b>key</b> is a configuration option, return the corresponding const
- * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
- * warn, and return the corresponding const config_var_t. Otherwise return
- * NULL.
+/**
+ * Find the managed_var_t object for a variable whose name is <b>name</b>
+ * according to <b>mgr</b>. Return that object, or NULL if none exists.
+ *
+ * If <b>allow_truncated</b> is true, then accept any variable whose
+ * name begins with <b>name</b>.
+ *
+ * If <b>idx_out</b> is not NULL, set *<b>idx_out</b> to the position of
+ * that variable within mgr-&gt;all_vars, or to -1 if the variable is
+ * not found.
*/
-const config_var_t *
-config_find_option(const config_format_t *fmt, const char *key)
+static const managed_var_t *
+config_mgr_find_var(const config_mgr_t *mgr,
+ const char *key,
+ bool allow_truncated, int *idx_out)
{
- int i;
- size_t keylen = strlen(key);
+ const size_t keylen = strlen(key);
+ if (idx_out)
+ *idx_out = -1;
+
if (!keylen)
return NULL; /* if they say "--" on the command line, it's not an option */
+
/* First, check for an exact (case-insensitive) match */
- for (i=0; fmt->vars[i].member.name; ++i) {
- if (!strcasecmp(key, fmt->vars[i].member.name)) {
- return &fmt->vars[i];
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ if (!strcasecmp(mv->cvar->member.name, key)) {
+ if (idx_out)
+ *idx_out = mv_sl_idx;
+ return mv;
}
- }
+ } SMARTLIST_FOREACH_END(mv);
+
+ if (!allow_truncated)
+ return NULL;
+
/* If none, check for an abbreviated match */
- for (i=0; fmt->vars[i].member.name; ++i) {
- if (!strncasecmp(key, fmt->vars[i].member.name, keylen)) {
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ if (!strncasecmp(key, mv->cvar->member.name, keylen)) {
log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
"Please use '%s' instead",
- key, fmt->vars[i].member.name);
- return &fmt->vars[i];
+ key, mv->cvar->member.name);
+ if (idx_out)
+ *idx_out = mv_sl_idx;
+ return mv;
}
- }
+ } SMARTLIST_FOREACH_END(mv);
+
/* Okay, unrecognized option */
return NULL;
}
+/**
+ * If <b>key</b> is a name or an abbreviation configuration option, return
+ * the corresponding canonical name for it. Warn if the abbreviation is
+ * non-standard. Return NULL if the option does not exist.
+ */
+const char *
+config_find_option_name(const config_mgr_t *mgr, const char *key)
+{
+ key = config_expand_abbrev(mgr, key, 0, 0);
+ const managed_var_t *mv = config_mgr_find_var(mgr, key, true, NULL);
+ if (mv)
+ return mv->cvar->member.name;
+ else
+ return NULL;
+}
+
/** Return the number of option entries in <b>fmt</b>. */
static int
-config_count_options(const config_format_t *fmt)
+config_count_options(const config_mgr_t *mgr)
{
- int i;
- for (i=0; fmt->vars[i].member.name; ++i)
- ;
- return i;
+ return smartlist_len(mgr->all_vars);
}
bool
@@ -185,35 +549,41 @@ config_var_is_dumpable(const config_var_t *var)
* Called from config_assign_line() and option_reset().
*/
static int
-config_assign_value(const config_format_t *fmt, void *options,
+config_assign_value(const config_mgr_t *mgr, void *options,
config_line_t *c, char **msg)
{
- const config_var_t *var;
+ const managed_var_t *var;
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
- var = config_find_option(fmt, c->key);
+ var = config_mgr_find_var(mgr, c->key, true, NULL);
tor_assert(var);
- tor_assert(!strcmp(c->key, var->member.name));
+ tor_assert(!strcmp(c->key, var->cvar->member.name));
+ void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
- return struct_var_kvassign(options, c, msg, &var->member);
+ return struct_var_kvassign(object, c, msg, &var->cvar->member);
}
/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
* to it will replace old ones. */
static void
-config_mark_lists_fragile(const config_format_t *fmt, void *options)
+config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
{
- int i;
- tor_assert(fmt);
+ tor_assert(mgr);
tor_assert(options);
- for (i = 0; fmt->vars[i].member.name; ++i) {
- const config_var_t *var = &fmt->vars[i];
- struct_var_mark_fragile(options, &var->member);
- }
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ void *object = config_mgr_get_obj_mutable(mgr, options, mv->object_idx);
+ struct_var_mark_fragile(object, &mv->cvar->member);
+ } SMARTLIST_FOREACH_END(mv);
}
+/**
+ * Log a warning that declaring that the option called <b>what</b>
+ * is deprecated because of the reason in <b>why</b>.
+ *
+ * (Both arguments must be non-NULL.)
+ **/
void
warn_deprecated_option(const char *what, const char *why)
{
@@ -234,19 +604,21 @@ warn_deprecated_option(const char *what, const char *why)
* Called from config_assign().
*/
static int
-config_assign_line(const config_format_t *fmt, void *options,
+config_assign_line(const config_mgr_t *mgr, void *options,
config_line_t *c, unsigned flags,
bitarray_t *options_seen, char **msg)
{
const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
const unsigned clear_first = flags & CAL_CLEAR_FIRST;
const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
- const config_var_t *var;
+ const managed_var_t *mvar;
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
- var = config_find_option(fmt, c->key);
- if (!var) {
+ int var_index = -1;
+ mvar = config_mgr_find_var(mgr, c->key, true, &var_index);
+ if (!mvar) {
+ const config_format_t *fmt = mgr->toplevel;
if (fmt->extra) {
void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
log_info(LD_CONFIG,
@@ -260,49 +632,57 @@ config_assign_line(const config_format_t *fmt, void *options,
}
}
+ const config_var_t *cvar = mvar->cvar;
+ tor_assert(cvar);
+
/* Put keyword into canonical case. */
- if (strcmp(var->member.name, c->key)) {
+ if (strcmp(cvar->member.name, c->key)) {
tor_free(c->key);
- c->key = tor_strdup(var->member.name);
+ c->key = tor_strdup(cvar->member.name);
}
const char *deprecation_msg;
if (warn_deprecations &&
- (deprecation_msg = config_find_deprecation(fmt, var->member.name))) {
- warn_deprecated_option(var->member.name, deprecation_msg);
+ (deprecation_msg = config_find_deprecation(mgr, cvar->member.name))) {
+ warn_deprecated_option(cvar->member.name, deprecation_msg);
}
if (!strlen(c->value)) {
/* reset or clear it, then return */
if (!clear_first) {
- if (config_var_is_cumulative(var) && c->command != CONFIG_LINE_CLEAR) {
+ if (config_var_is_cumulative(cvar) && c->command != CONFIG_LINE_CLEAR) {
/* We got an empty linelist from the torrc or command line.
As a special case, call this an error. Warn and ignore. */
log_warn(LD_CONFIG,
"Linelist option '%s' has no value. Skipping.", c->key);
} else { /* not already cleared */
- config_reset(fmt, options, var, use_defaults);
+ config_reset(mgr, options, mvar, use_defaults);
}
}
return 0;
} else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
- // XXXX This is unreachable, since a CLEAR line always has an
- // XXXX empty value.
- config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
+ // This block is unreachable, since a CLEAR line always has an
+ // empty value, and so will trigger be handled by the previous
+ // "if (!strlen(c->value))" block.
+
+ // LCOV_EXCL_START
+ tor_assert_nonfatal_unreached();
+ config_reset(mgr, options, mvar, use_defaults);
+ // LCOV_EXCL_STOP
}
- if (options_seen && ! config_var_is_cumulative(var)) {
+ if (options_seen && ! config_var_is_cumulative(cvar)) {
/* We're tracking which options we've seen, and this option is not
* supposed to occur more than once. */
- int var_index = (int)(var - fmt->vars);
+ tor_assert(var_index >= 0);
if (bitarray_is_set(options_seen, var_index)) {
log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
- "value will be ignored.", var->member.name);
+ "value will be ignored.", cvar->member.name);
}
bitarray_set(options_seen, var_index);
}
- if (config_assign_value(fmt, options, c, msg) < 0)
+ if (config_assign_value(mgr, options, c, msg) < 0)
return -2;
return 0;
}
@@ -310,18 +690,18 @@ config_assign_line(const config_format_t *fmt, void *options,
/** Restore the option named <b>key</b> in options to its default value.
* Called from config_assign(). */
STATIC void
-config_reset_line(const config_format_t *fmt, void *options,
+config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults)
{
- const config_var_t *var;
+ const managed_var_t *var;
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
- var = config_find_option(fmt, key);
+ var = config_mgr_find_var(mgr, key, true, NULL);
if (!var)
return; /* give error on next pass. */
- config_reset(fmt, options, var, use_defaults);
+ config_reset(mgr, options, var, use_defaults);
}
/** Return true iff value needs to be quoted and escaped to be used in
@@ -355,22 +735,24 @@ config_value_needs_escape(const char *value)
* value needs to be quoted before it's put in a config file, quote and
* escape that value. Return NULL if no such key exists. */
config_line_t *
-config_get_assigned_option(const config_format_t *fmt, const void *options,
+config_get_assigned_option(const config_mgr_t *mgr, const void *options,
const char *key, int escape_val)
{
- const config_var_t *var;
+ const managed_var_t *var;
config_line_t *result;
+
tor_assert(options && key);
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
- var = config_find_option(fmt, key);
+ var = config_mgr_find_var(mgr, key, true, NULL);
if (!var) {
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
return NULL;
}
+ const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
- result = struct_var_kvencode(options, &var->member);
+ result = struct_var_kvencode(object, &var->cvar->member);
if (escape_val) {
config_line_t *line;
@@ -442,20 +824,20 @@ options_trial_assign() calls config_assign(1, 1)
returns.
*/
int
-config_assign(const config_format_t *fmt, void *options, config_line_t *list,
+config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
unsigned config_assign_flags, char **msg)
{
config_line_t *p;
bitarray_t *options_seen;
- const int n_options = config_count_options(fmt);
+ const int n_options = config_count_options(mgr);
const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
/* pass 1: normalize keys */
for (p = list; p; p = p->next) {
- const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
+ const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
if (strcmp(full,p->key)) {
tor_free(p->key);
p->key = tor_strdup(full);
@@ -466,14 +848,14 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
* mentioned config options, and maybe set to their defaults. */
if (clear_first) {
for (p = list; p; p = p->next)
- config_reset_line(fmt, options, p->key, use_defaults);
+ config_reset_line(mgr, options, p->key, use_defaults);
}
options_seen = bitarray_init_zero(n_options);
/* pass 3: assign. */
while (list) {
int r;
- if ((r=config_assign_line(fmt, options, list, config_assign_flags,
+ if ((r=config_assign_line(mgr, options, list, config_assign_flags,
options_seen, msg))) {
bitarray_free(options_seen);
return r;
@@ -485,7 +867,7 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
/** Now we're done assigning a group of options to the configuration.
* Subsequent group assignments should _replace_ linelists, not extend
* them. */
- config_mark_lists_fragile(fmt, options);
+ config_mark_lists_fragile(mgr, options);
return 0;
}
@@ -493,33 +875,32 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
* Called from config_reset() and config_free(). */
static void
-config_clear(const config_format_t *fmt, void *options,
- const config_var_t *var)
+config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
{
-
- (void)fmt; /* unused */
-
- struct_var_free(options, &var->member);
+ void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
+ struct_var_free(object, &var->cvar->member);
}
/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
* <b>use_defaults</b>, set it to its default value.
* Called by config_init() and option_reset_line() and option_assign_line(). */
static void
-config_reset(const config_format_t *fmt, void *options,
- const config_var_t *var, int use_defaults)
+config_reset(const config_mgr_t *mgr, void *options,
+ const managed_var_t *var, int use_defaults)
{
config_line_t *c;
char *msg = NULL;
- CONFIG_CHECK(fmt, options);
- config_clear(fmt, options, var); /* clear it first */
+ CONFIG_CHECK(mgr, options);
+ config_clear(mgr, options, var); /* clear it first */
+
if (!use_defaults)
return; /* all done */
- if (var->initvalue) {
+
+ if (var->cvar->initvalue) {
c = tor_malloc_zero(sizeof(config_line_t));
- c->key = tor_strdup(var->member.name);
- c->value = tor_strdup(var->initvalue);
- if (config_assign_value(fmt, options, c, &msg) < 0) {
+ c->key = tor_strdup(var->cvar->member.name);
+ c->value = tor_strdup(var->cvar->initvalue);
+ if (config_assign_value(mgr, options, c, &msg) < 0) {
// LCOV_EXCL_START
log_warn(LD_BUG, "Failed to assign default: %s", msg);
tor_free(msg); /* if this happens it's a bug */
@@ -531,23 +912,44 @@ config_reset(const config_format_t *fmt, void *options,
/** Release storage held by <b>options</b>. */
void
-config_free_(const config_format_t *fmt, void *options)
+config_free_(const config_mgr_t *mgr, void *options)
{
- int i;
-
if (!options)
return;
- tor_assert(fmt);
+ tor_assert(mgr);
- for (i=0; fmt->vars[i].member.name; ++i)
- config_clear(fmt, options, &(fmt->vars[i]));
+ if (mgr->toplevel->clear_fn) {
+ mgr->toplevel->clear_fn(mgr, options);
+ }
+ config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
+ if (suitep) {
+ tor_assert(smartlist_len((*suitep)->configs) ==
+ smartlist_len(mgr->subconfigs));
+ SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
+ void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
+ if (fmt->clear_fn) {
+ fmt->clear_fn(mgr, obj);
+ }
+ } SMARTLIST_FOREACH_END(fmt);
+ }
- if (fmt->extra) {
- config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->offset);
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ config_clear(mgr, options, mv);
+ } SMARTLIST_FOREACH_END(mv);
+
+ if (mgr->toplevel->extra) {
+ config_line_t **linep = STRUCT_VAR_P(options,
+ mgr->toplevel->extra->offset);
config_free_lines(*linep);
*linep = NULL;
}
+
+ if (suitep) {
+ SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
+ config_suite_free(*suitep);
+ }
+
tor_free(options);
}
@@ -555,59 +957,103 @@ config_free_(const config_format_t *fmt, void *options)
* and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
*/
int
-config_is_same(const config_format_t *fmt,
+config_is_same(const config_mgr_t *mgr,
const void *o1, const void *o2,
const char *name)
{
- CONFIG_CHECK(fmt, o1);
- CONFIG_CHECK(fmt, o2);
+ CONFIG_CHECK(mgr, o1);
+ CONFIG_CHECK(mgr, o2);
- const config_var_t *var = config_find_option(fmt, name);
+ const managed_var_t *var = config_mgr_find_var(mgr, name, true, NULL);
if (!var) {
return true;
}
+ const void *obj1 = config_mgr_get_obj(mgr, o1, var->object_idx);
+ const void *obj2 = config_mgr_get_obj(mgr, o2, var->object_idx);
- return struct_var_eq(o1, o2, &var->member);
+ return struct_var_eq(obj1, obj2, &var->cvar->member);
+}
+
+/**
+ * Return a list of the options which have changed between <b>options1</b> and
+ * <b>options2</b>. If an option has reverted to its default value, it has a
+ * value entry of NULL.
+ *
+ * <b>options1</b> and <b>options2</b> must be top-level configuration objects
+ * of the type managed by <b>mgr</b>.
+ **/
+config_line_t *
+config_get_changes(const config_mgr_t *mgr,
+ const void *options1, const void *options2)
+{
+ config_line_t *result = NULL;
+ config_line_t **next = &result;
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
+ if (config_var_is_contained(mv->cvar)) {
+ /* something else will check this var, or it doesn't need checking */
+ continue;
+ }
+ const void *obj1 = config_mgr_get_obj(mgr, options1, mv->object_idx);
+ const void *obj2 = config_mgr_get_obj(mgr, options2, mv->object_idx);
+
+ if (struct_var_eq(obj1, obj2, &mv->cvar->member)) {
+ continue;
+ }
+
+ const char *varname = mv->cvar->member.name;
+ config_line_t *line =
+ config_get_assigned_option(mgr, options2, varname, 1);
+
+ if (line) {
+ *next = line;
+ } else {
+ *next = tor_malloc_zero(sizeof(config_line_t));
+ (*next)->key = tor_strdup(varname);
+ }
+ while (*next)
+ next = &(*next)->next;
+ } SMARTLIST_FOREACH_END(mv);
+
+ return result;
}
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
void *
-config_dup(const config_format_t *fmt, const void *old)
+config_dup(const config_mgr_t *mgr, const void *old)
{
void *newopts;
- int i;
- newopts = config_new(fmt);
- for (i=0; fmt->vars[i].member.name; ++i) {
- if (config_var_is_contained(&fmt->vars[i])) {
+ newopts = config_new(mgr);
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
+ if (config_var_is_contained(mv->cvar)) {
// Something else will copy this option, or it doesn't need copying.
continue;
}
- if (struct_var_copy(newopts, old, &fmt->vars[i].member) < 0) {
+ const void *oldobj = config_mgr_get_obj(mgr, old, mv->object_idx);
+ void *newobj = config_mgr_get_obj_mutable(mgr, newopts, mv->object_idx);
+ if (struct_var_copy(newobj, oldobj, &mv->cvar->member) < 0) {
// LCOV_EXCL_START
log_err(LD_BUG, "Unable to copy value for %s.",
- fmt->vars[i].member.name);
+ mv->cvar->member.name);
tor_assert_unreached();
// LCOV_EXCL_STOP
}
- }
+ } SMARTLIST_FOREACH_END(mv);
+
return newopts;
}
/** Set all vars in the configuration object <b>options</b> to their default
* values. */
void
-config_init(const config_format_t *fmt, void *options)
+config_init(const config_mgr_t *mgr, void *options)
{
- int i;
- const config_var_t *var;
- CONFIG_CHECK(fmt, options);
+ CONFIG_CHECK(mgr, options);
- for (i=0; fmt->vars[i].member.name; ++i) {
- var = &fmt->vars[i];
- if (!var->initvalue)
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ if (!mv->cvar->initvalue)
continue; /* defaults to NULL or 0 */
- config_reset(fmt, options, var, 1);
- }
+ config_reset(mgr, options, mv, 1);
+ } SMARTLIST_FOREACH_END(mv);
}
/** Allocate and return a new string holding the written-out values of the vars
@@ -615,21 +1061,21 @@ config_init(const config_format_t *fmt, void *options)
* Else, if comment_defaults, write default values as comments.
*/
char *
-config_dump(const config_format_t *fmt, const void *default_options,
+config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults)
{
+ const config_format_t *fmt = mgr->toplevel;
smartlist_t *elements;
const void *defaults = default_options;
void *defaults_tmp = NULL;
config_line_t *line, *assigned;
char *result;
- int i;
char *msg = NULL;
if (defaults == NULL) {
- defaults = defaults_tmp = config_new(fmt);
- config_init(fmt, defaults_tmp);
+ defaults = defaults_tmp = config_new(mgr);
+ config_init(mgr, defaults_tmp);
}
/* XXX use a 1 here so we don't add a new log line while dumping */
@@ -644,24 +1090,24 @@ config_dump(const config_format_t *fmt, const void *default_options,
}
elements = smartlist_new();
- for (i=0; fmt->vars[i].member.name; ++i) {
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
int comment_option = 0;
- if (config_var_is_contained(&fmt->vars[i])) {
+ if (config_var_is_contained(mv->cvar)) {
// Something else will dump this option, or it doesn't need dumping.
continue;
}
/* Don't save 'hidden' control variables. */
- if (! config_var_is_dumpable(&fmt->vars[i]))
+ if (! config_var_is_dumpable(mv->cvar))
continue;
- if (minimal && config_is_same(fmt, options, defaults,
- fmt->vars[i].member.name))
+ const char *name = mv->cvar->member.name;
+ if (minimal && config_is_same(mgr, options, defaults, name))
continue;
else if (comment_defaults &&
- config_is_same(fmt, options, defaults, fmt->vars[i].member.name))
+ config_is_same(mgr, options, defaults, name))
comment_option = 1;
line = assigned =
- config_get_assigned_option(fmt, options, fmt->vars[i].member.name, 1);
+ config_get_assigned_option(mgr, options, name, 1);
for (; line; line = line->next) {
if (!strcmpstart(line->key, "__")) {
@@ -674,7 +1120,7 @@ config_dump(const config_format_t *fmt, const void *default_options,
line->key, line->value);
}
config_free_lines(assigned);
- }
+ } SMARTLIST_FOREACH_END(mv);
if (fmt->extra) {
line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
@@ -686,9 +1132,7 @@ config_dump(const config_format_t *fmt, const void *default_options,
result = smartlist_join_strings(elements, "", 0, NULL);
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
- if (defaults_tmp) {
- fmt->free_fn(defaults_tmp);
- }
+ config_free(mgr, defaults_tmp);
return result;
}
@@ -697,15 +1141,17 @@ config_dump(const config_format_t *fmt, const void *default_options,
* Return false otherwise. Log errors at level <b>severity</b>.
*/
bool
-config_check_ok(const config_format_t *fmt, const void *options, int severity)
+config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
{
bool all_ok = true;
- for (int i=0; fmt->vars[i].member.name; ++i) {
- if (!struct_var_ok(options, &fmt->vars[i].member)) {
+
+ SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
+ if (!struct_var_ok(options, &mv->cvar->member)) {
log_fn(severity, LD_BUG, "Invalid value for %s",
- fmt->vars[i].member.name);
+ mv->cvar->member.name);
all_ok = false;
}
- }
+ } SMARTLIST_FOREACH_END(mv);
+
return all_ok;
}
diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h
index d6571692f9..6a7a567273 100644
--- a/src/app/config/confparse.h
+++ b/src/app/config/confparse.h
@@ -17,30 +17,76 @@
#include "lib/conf/confmacros.h"
#include "lib/testsupport/testsupport.h"
-/** An abbreviation for a configuration option allowed on the command line. */
+/**
+ * An abbreviation or alias for a configuration option.
+ **/
typedef struct config_abbrev_t {
+ /** The option name as abbreviated. Not case-sensitive. */
const char *abbreviated;
+ /** The full name of the option. Not case-sensitive. */
const char *full;
+ /** True if this abbreviation should only be allowed on the command line. */
int commandline_only;
+ /** True if we should warn whenever this abbreviation is used. */
int warn;
} config_abbrev_t;
+/**
+ * A note that a configuration option is deprecated, with an explanation why.
+ */
typedef struct config_deprecation_t {
+ /** The option that is deprecated. */
const char *name;
+ /** A user-facing string explaining why the option is deprecated. */
const char *why_deprecated;
} config_deprecation_t;
-/* Handy macro for declaring "In the config file or on the command line,
- * you can abbreviate <b>tok</b>s as <b>tok</b>". */
+/**
+ * Handy macro for declaring "In the config file or on the command line, you
+ * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
+ * config_abbrev_t.
+ *
+ * For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
+ * you can say PLURAL(NumCpu).
+ **/
#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
-/** Type of a callback to validate whether a given configuration is
- * well-formed and consistent. See options_trial_assign() for documentation
- * of arguments. */
-typedef int (*validate_fn_t)(void*,void*,void*,int,char**);
+/**
+ * Type of a callback to validate whether a given configuration is
+ * well-formed and consistent.
+ *
+ * The configuration to validate is passed as <b>newval</b>. The previous
+ * configuration, if any, is provided in <b>oldval</b>. The
+ * <b>default_val</b> argument receives a configuration object initialized
+ * with default values for all its fields. The <b>from_setconf</b> argument
+ * is true iff the input comes from a SETCONF controller command.
+ *
+ * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated
+ * error message, and return -1.
+ *
+ * REFACTORING NOTE: Currently, this callback type is only used from inside
+ * config_dump(); later in our refactoring, it will be cleaned up and used
+ * more generally.
+ */
+typedef int (*validate_fn_t)(void *oldval,
+ void *newval,
+ void *default_val,
+ int from_setconf,
+ char **msg_out);
+
+struct config_mgr_t;
-/** Callback to free a configuration object. */
-typedef void (*free_cfg_fn_t)(void*);
+/**
+ * Callback to clear all non-managed fields of a configuration object.
+ *
+ * <b>obj</b> is the configuration object whose non-managed fields should be
+ * cleared.
+ *
+ * (Regular fields get cleared by config_reset(), but you might have fields
+ * in the object that do not correspond to configuration variables. If those
+ * fields need to be cleared or freed, this is where to do it.)
+ */
+typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj);
/** Information on the keys, value types, key-to-struct-member mappings,
* variable descriptions, validation functions, and abbreviations for a
@@ -55,51 +101,90 @@ typedef struct config_format_t {
* values, and where we stick them in the
* structure. */
validate_fn_t validate_fn; /**< Function to validate config. */
- free_cfg_fn_t free_fn; /**< Function to free the configuration. */
+ clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */
/** If present, extra denotes a LINELIST variable for unrecognized
* lines. Otherwise, unrecognized lines are an error. */
const struct_member_t *extra;
+ /** The position of a config_suite_t pointer within the toplevel object,
+ * or -1 if there is no such pointer. */
+ ptrdiff_t config_suite_offset;
} config_format_t;
-/** Macro: assert that <b>cfg</b> has the right magic field for format
- * <b>fmt</b>. */
-#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
- tor_assert(fmt); \
- struct_check_magic((cfg), &fmt->magic); \
- STMT_END
+/**
+ * A collection of config_format_t objects to describe several objects
+ * that are all configured with the same configuration file.
+ *
+ * (NOTE: for now, this only handles a single config_format_t.)
+ **/
+typedef struct config_mgr_t config_mgr_t;
+
+config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt);
+void config_mgr_free_(config_mgr_t *mgr);
+int config_mgr_add_format(config_mgr_t *mgr,
+ const config_format_t *fmt);
+void config_mgr_freeze(config_mgr_t *mgr);
+#define config_mgr_free(mgr) \
+ FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr))
+struct smartlist_t *config_mgr_list_vars(const config_mgr_t *mgr);
+struct smartlist_t *config_mgr_list_deprecated_vars(const config_mgr_t *mgr);
+
+/** A collection of managed configuration objects. */
+typedef struct config_suite_t config_suite_t;
+/**
+ * Flag for config_assign: if set, then "resetting" an option changes it to
+ * its default value, as specified in the config_var_t. Otherwise,
+ * "resetting" an option changes it to a type-dependent null value --
+ * typically 0 or NULL.
+ *
+ * (An option is "reset" when it is set to an empty value, or as described in
+ * CAL_CLEAR_FIRST).
+ **/
#define CAL_USE_DEFAULTS (1u<<0)
+/**
+ * Flag for config_assign: if set, then we reset every provided config
+ * option before we set it.
+ *
+ * For example, if this flag is not set, then passing a multi-line option to
+ * config_assign will cause any previous value to be extended. But if this
+ * flag is set, then a multi-line option will replace any previous value.
+ **/
#define CAL_CLEAR_FIRST (1u<<1)
+/**
+ * Flag for config_assign: if set, we warn about deprecated options.
+ **/
#define CAL_WARN_DEPRECATIONS (1u<<2)
-void *config_new(const config_format_t *fmt);
-void config_free_(const config_format_t *fmt, void *options);
-#define config_free(fmt, options) do { \
- config_free_((fmt), (options)); \
+void *config_new(const config_mgr_t *fmt);
+void config_free_(const config_mgr_t *fmt, void *options);
+#define config_free(mgr, options) do { \
+ config_free_((mgr), (options)); \
(options) = NULL; \
} while (0)
-struct config_line_t *config_get_assigned_option(const config_format_t *fmt,
+struct config_line_t *config_get_assigned_option(const config_mgr_t *mgr,
const void *options, const char *key,
int escape_val);
-int config_is_same(const config_format_t *fmt,
+int config_is_same(const config_mgr_t *fmt,
const void *o1, const void *o2,
const char *name);
-void config_init(const config_format_t *fmt, void *options);
-void *config_dup(const config_format_t *fmt, const void *old);
-char *config_dump(const config_format_t *fmt, const void *default_options,
+struct config_line_t *config_get_changes(const config_mgr_t *mgr,
+ const void *options1, const void *options2);
+void config_init(const config_mgr_t *mgr, void *options);
+void *config_dup(const config_mgr_t *mgr, const void *old);
+char *config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults);
-bool config_check_ok(const config_format_t *fmt, const void *options,
+bool config_check_ok(const config_mgr_t *mgr, const void *options,
int severity);
-int config_assign(const config_format_t *fmt, void *options,
+int config_assign(const config_mgr_t *mgr, void *options,
struct config_line_t *list,
unsigned flags, char **msg);
-const char *config_find_deprecation(const config_format_t *fmt,
- const char *key);
-const config_var_t *config_find_option(const config_format_t *fmt,
- const char *key);
-const char *config_expand_abbrev(const config_format_t *fmt,
+const char *config_find_deprecation(const config_mgr_t *mgr,
+ const char *key);
+const char *config_find_option_name(const config_mgr_t *mgr,
+ const char *key);
+const char *config_expand_abbrev(const config_mgr_t *mgr,
const char *option,
int command_line, int warn_obsolete);
void warn_deprecated_option(const char *what, const char *why);
@@ -119,8 +204,12 @@ bool config_var_is_dumpable(const config_var_t *var);
#define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)
#ifdef CONFPARSE_PRIVATE
-STATIC void config_reset_line(const config_format_t *fmt, void *options,
+STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults);
+STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr,
+ void *toplevel, int idx);
+STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr,
+ const void *toplevel, int idx);
#endif
#endif /* !defined(TOR_CONFPARSE_H) */
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 8156d2ca11..32dcd9fb18 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -18,6 +18,7 @@
struct smartlist_t;
struct config_line_t;
+struct config_suite_t;
/** Enumeration of outbound address configuration types:
* Exit-only, OR-only, or both */
@@ -1107,6 +1108,14 @@ struct or_options_t {
* a possible previous dormant state.
**/
int DormantCanceledByStartup;
+
+ /**
+ * Configuration objects for individual modules.
+ *
+ * Never access this field or its members directly: instead, use the module
+ * in question to get its relevant configuration object.
+ */
+ struct config_suite_t *subconfigs_;
};
#endif /* !defined(TOR_OR_OPTIONS_ST_H) */
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index f45c6196cc..225003bb7e 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -15,6 +15,7 @@
#include "lib/cc/torint.h"
struct smartlist_t;
+struct config_suite_t;
/** Persistent state for an onion router, as saved to disk. */
struct or_state_t {
@@ -94,6 +95,14 @@ struct or_state_t {
/** True if we were dormant when we last wrote the file; false if we
* weren't. "auto" on initial startup. */
int Dormant;
+
+ /**
+ * State objects for individual modules.
+ *
+ * Never access this field or its members directly: instead, use the module
+ * in question to get its relevant state object if you must.
+ */
+ struct config_suite_t *substates_;
};
#endif /* !defined(TOR_OR_STATE_ST_H) */
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index d997d3932e..bcc06809b3 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -145,8 +145,6 @@ 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);
-
/** Magic value for or_state_t. */
#define OR_STATE_MAGIC 0x57A73f57
@@ -170,10 +168,25 @@ static const config_format_t state_format = {
NULL,
state_vars_,
or_state_validate_cb,
- or_state_free_cb,
+ NULL,
&state_extra_var,
+ 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);
+ config_mgr_freeze(state_mgr);
+ }
+ return state_mgr;
+}
+
/** Persistent serialized state. */
static or_state_t *global_state = NULL;
@@ -268,12 +281,6 @@ or_state_validate_cb(void *old_state, void *state, void *default_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
@@ -298,7 +305,7 @@ 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 (entry_guards_parse_state(global_state, 1, &err)<0) {
log_warn(LD_GENERAL,"%s",err);
@@ -361,9 +368,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;
}
@@ -404,7 +410,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)
@@ -431,7 +437,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) {
@@ -464,7 +470,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;
}
@@ -517,7 +523,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"
@@ -727,7 +733,7 @@ or_state_free_(or_state_t *state)
if (!state)
return;
- config_free(&state_format, state);
+ config_free(get_state_mgr(), state);
}
void
@@ -735,4 +741,5 @@ or_state_free_all(void)
{
or_state_free(global_state);
global_state = NULL;
+ config_mgr_free(state_mgr);
}
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index c2ad3e7cca..f2a626c738 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -62,7 +62,6 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
static int
disk_state_validate_cb(void *old_state, void *state, void *default_state,
int from_setconf, char **msg);
-static void disk_state_free_cb(void *);
/* Array of variables that are saved to disk as a persistent state. */
static const config_var_t state_vars[] = {
@@ -99,10 +98,25 @@ static const config_format_t state_format = {
NULL,
state_vars,
disk_state_validate_cb,
- disk_state_free_cb,
+ NULL,
&state_extra_var,
+ -1,
};
+/* Global configuration manager for the shared-random state file */
+static config_mgr_t *shared_random_state_mgr = NULL;
+
+/** Return the configuration manager for the shared-random state file. */
+static const config_mgr_t *
+get_srs_mgr(void)
+{
+ if (PREDICT_UNLIKELY(shared_random_state_mgr == NULL)) {
+ shared_random_state_mgr = config_mgr_new(&state_format);
+ config_mgr_freeze(shared_random_state_mgr);
+ }
+ return shared_random_state_mgr;
+}
+
static void state_query_del_(sr_state_object_t obj_type, void *data);
/* Return a string representation of a protocol phase. */
@@ -264,23 +278,22 @@ disk_state_free_(sr_disk_state_t *state)
if (state == NULL) {
return;
}
- config_free(&state_format, state);
+ config_free(get_srs_mgr(), state);
}
/* Allocate a new disk state, initialize it and return it. */
static sr_disk_state_t *
disk_state_new(time_t now)
{
- sr_disk_state_t *new_state = tor_malloc_zero(sizeof(*new_state));
+ sr_disk_state_t *new_state = config_new(get_srs_mgr());
- new_state->magic_ = SR_DISK_STATE_MAGIC;
new_state->Version = SR_PROTO_VERSION;
new_state->TorVersion = tor_strdup(get_version());
new_state->ValidUntil = get_state_valid_until_time(now);
new_state->ValidAfter = now;
/* Init config format. */
- config_init(&state_format, new_state);
+ config_init(get_srs_mgr(), new_state);
return new_state;
}
@@ -348,12 +361,6 @@ disk_state_validate_cb(void *old_state, void *state, void *default_state,
return 0;
}
-static void
-disk_state_free_cb(void *state)
-{
- disk_state_free_(state);
-}
-
/* Parse the Commit line(s) in the disk state and translate them to the
* the memory state. Return 0 on success else -1 on error. */
static int
@@ -584,11 +591,12 @@ disk_state_reset(void)
config_free_lines(sr_disk_state->ExtraLines);
tor_free(sr_disk_state->TorVersion);
- /* Clean up the struct */
- memset(sr_disk_state, 0, sizeof(*sr_disk_state));
+ /* Clear other fields. */
+ sr_disk_state->ValidAfter = 0;
+ sr_disk_state->ValidUntil = 0;
+ sr_disk_state->Version = 0;
/* Reset it with useful data */
- sr_disk_state->magic_ = SR_DISK_STATE_MAGIC;
sr_disk_state->TorVersion = tor_strdup(get_version());
}
@@ -683,7 +691,7 @@ disk_state_load_from_disk_impl(const char *fname)
}
disk_state = disk_state_new(time(NULL));
- config_assign(&state_format, disk_state, lines, 0, &errmsg);
+ config_assign(get_srs_mgr(), disk_state, lines, 0, &errmsg);
config_free_lines(lines);
if (errmsg) {
log_warn(LD_DIR, "SR: Reading state error: %s", errmsg);
@@ -736,7 +744,7 @@ disk_state_save_to_disk(void)
/* Make sure that our disk state is up to date with our memory state
* before saving it to disk. */
disk_state_update();
- state = config_dump(&state_format, NULL, sr_disk_state, 0, 0);
+ state = config_dump(get_srs_mgr(), NULL, sr_disk_state, 0, 0);
format_local_iso_time(tbuf, now);
tor_asprintf(&content,
"# Tor shared random state file last generated on %s "
@@ -1278,6 +1286,7 @@ sr_state_free_all(void)
/* Nullify our global state. */
sr_state = NULL;
sr_disk_state = NULL;
+ config_mgr_free(shared_random_state_mgr);
}
/* Save our current state in memory to disk. */
diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c
index 22cc1e272e..e02dfcf11a 100644
--- a/src/feature/dirparse/microdesc_parse.c
+++ b/src/feature/dirparse/microdesc_parse.c
@@ -92,6 +92,12 @@ find_start_of_next_microdesc(const char *s, const char *eos)
#undef NEXT_LINE
}
+static inline int
+policy_is_reject_star_or_null(struct short_policy_t *policy)
+{
+ return !policy || short_policy_is_reject_star(policy);
+}
+
/** Parse as many microdescriptors as are found from the string starting at
* <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
* annotations we recognize and ignore ones we don't.
@@ -250,6 +256,11 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->ipv6_exit_policy = parse_short_policy(tok->args[0]);
}
+ if (policy_is_reject_star_or_null(md->exit_policy) &&
+ policy_is_reject_star_or_null(md->ipv6_exit_policy)) {
+ md->policy_is_reject_star = 1;
+ }
+
smartlist_add(result, md);
okay = 1;
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index 7ec18438c1..1e46837685 100644
--- a/src/feature/nodelist/describe.c
+++ b/src/feature/nodelist/describe.c
@@ -29,7 +29,8 @@
* NULL or the null address. The <b>addr32h</b> field is optional and may be
* set to 0.
*
- * Return a pointer to the front of <b>buf</b>, or a string constant on error.
+ * Return a pointer to the front of <b>buf</b>.
+ * If buf is NULL, return a string constant describing the error.
*/
STATIC const char *
format_node_description(char *buf,
@@ -38,7 +39,7 @@ format_node_description(char *buf,
const tor_addr_t *addr,
uint32_t addr32h)
{
- char *cp;
+ size_t rv = 0;
bool has_addr = addr && !tor_addr_is_null(addr);
if (!buf)
@@ -47,34 +48,67 @@ format_node_description(char *buf,
memset(buf, 0, NODE_DESC_BUF_LEN);
if (!id_digest) {
- memcpy(buf, "<NULL ID DIGEST>", 17);
+ /* strlcpy() returns the length of the source string it attempted to copy,
+ * ignoring any required truncation due to the buffer length. */
+ rv = strlcpy(buf, "<NULL ID DIGEST>", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
return buf;
}
- buf[0] = '$';
- base16_encode(buf+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN);
- cp = buf+1+HEX_DIGEST_LEN;
+ /* strlcat() returns the length of the concatenated string it attempted to
+ * create, ignoring any required truncation due to the buffer length. */
+ rv = strlcat(buf, "$", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+
+ {
+ char hex_digest[HEX_DIGEST_LEN+1];
+ memset(hex_digest, 0, sizeof(hex_digest));
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ id_digest, DIGEST_LEN);
+ rv = strlcat(buf, hex_digest, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
+
if (nickname) {
- buf[1+HEX_DIGEST_LEN] = '~';
- strlcpy(buf+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1);
- cp += strlen(cp);
+ rv = strlcat(buf, "~", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ rv = strlcat(buf, nickname, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
if (addr32h || has_addr) {
- memcpy(cp, " at ", 4);
- cp += 4;
+ rv = strlcat(buf, " at ", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
if (addr32h) {
+ int ntoa_rv = 0;
+ char ipv4_addr_str[INET_NTOA_BUF_LEN];
+ memset(ipv4_addr_str, 0, sizeof(ipv4_addr_str));
struct in_addr in;
+ memset(&in, 0, sizeof(in));
+
in.s_addr = htonl(addr32h);
- tor_inet_ntoa(&in, cp, INET_NTOA_BUF_LEN);
- cp += strlen(cp);
+ ntoa_rv = tor_inet_ntoa(&in, ipv4_addr_str, sizeof(ipv4_addr_str));
+ tor_assert_nonfatal(ntoa_rv >= 0);
+
+ rv = strlcat(buf, ipv4_addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
+ /* Both addresses are valid */
if (addr32h && has_addr) {
- memcpy(cp, " and ", 5);
- cp += 5;
+ rv = strlcat(buf, " and ", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
if (has_addr) {
- tor_addr_to_str(cp, addr, TOR_ADDR_BUF_LEN, 1);
+ const char *str_rv = NULL;
+ char addr_str[TOR_ADDR_BUF_LEN];
+ memset(addr_str, 0, sizeof(addr_str));
+
+ str_rv = tor_addr_to_str(addr_str, addr, sizeof(addr_str), 1);
+ tor_assert_nonfatal(str_rv == addr_str);
+
+ rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
return buf;
@@ -92,6 +126,7 @@ router_describe(const routerinfo_t *ri)
if (!ri)
return "<null>";
+
return format_node_description(buf,
ri->cache_info.identity_digest,
ri->nickname,
@@ -152,6 +187,7 @@ routerstatus_describe(const routerstatus_t *rs)
if (!rs)
return "<null>";
+
return format_node_description(buf,
rs->identity_digest,
rs->nickname,
@@ -171,6 +207,7 @@ extend_info_describe(const extend_info_t *ei)
if (!ei)
return "<null>";
+
return format_node_description(buf,
ei->identity_digest,
ei->nickname,
@@ -188,19 +225,39 @@ extend_info_describe(const extend_info_t *ei)
void
router_get_verbose_nickname(char *buf, const routerinfo_t *router)
{
+ size_t rv = 0;
+
if (!buf)
return;
memset(buf, 0, MAX_VERBOSE_NICKNAME_LEN+1);
if (!router) {
- memcpy(buf, "<null>", 7);
+ /* strlcpy() returns the length of the source string it attempted to copy,
+ * ignoring any required truncation due to the buffer length. */
+ rv = strlcpy(buf, "<null>", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
return;
}
- buf[0] = '$';
- base16_encode(buf+1, HEX_DIGEST_LEN+1, router->cache_info.identity_digest,
- DIGEST_LEN);
- buf[1+HEX_DIGEST_LEN] = '~';
- strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1);
+ /* strlcat() returns the length of the concatenated string it attempted to
+ * create, ignoring any required truncation due to the buffer length. */
+ rv = strlcat(buf, "$", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+
+ {
+ char hex_digest[HEX_DIGEST_LEN+1];
+ memset(hex_digest, 0, sizeof(hex_digest));
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ router->cache_info.identity_digest, DIGEST_LEN);
+ rv = strlcat(buf, hex_digest, MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+ }
+
+ rv = strlcat(buf, "~", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+
+ rv = strlcat(buf, router->nickname, MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
}
diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h
index c8265cb778..e017c46c79 100644
--- a/src/feature/nodelist/microdesc_st.h
+++ b/src/feature/nodelist/microdesc_st.h
@@ -33,6 +33,8 @@ struct microdesc_t {
unsigned int no_save : 1;
/** If true, this microdesc has an entry in the microdesc_map */
unsigned int held_in_map : 1;
+ /** True iff the exit policy for this router rejects everything. */
+ unsigned int policy_is_reject_star : 1;
/** Reference count: how many node_ts have a reference to this microdesc? */
unsigned int held_by_nodes;
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 21914c6c6d..6ae8d2bcb1 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -1424,8 +1424,7 @@ node_exit_policy_rejects_all(const node_t *node)
if (node->ri)
return node->ri->policy_is_reject_star;
else if (node->md)
- return node->md->exit_policy == NULL ||
- short_policy_is_reject_star(node->md->exit_policy);
+ return node->md->policy_is_reject_star;
else
return 1;
}
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index 5bdd4d453e..2540066dfc 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -119,7 +119,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
char tmp[RELAY_PAYLOAD_SIZE];
rend_cache_entry_t *entry = NULL;
crypt_path_t *cpath;
- off_t dh_offset;
+ ptrdiff_t dh_offset;
crypto_pk_t *intro_key = NULL;
int status = 0;
const char *onion_address;
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index 88a25b8470..4d026bd37d 100644
--- a/src/lib/buf/buffers.c
+++ b/src/lib/buf/buffers.c
@@ -158,7 +158,7 @@ chunk_new_with_alloc_size(size_t alloc)
static inline chunk_t *
chunk_grow(chunk_t *chunk, size_t sz)
{
- off_t offset;
+ ptrdiff_t offset;
const size_t memlen_orig = chunk->memlen;
const size_t orig_alloc = CHUNK_ALLOC_SIZE(memlen_orig);
const size_t new_alloc = CHUNK_ALLOC_SIZE(sz);
@@ -440,7 +440,7 @@ chunk_copy(const chunk_t *in_chunk)
#endif
newch->next = NULL;
if (in_chunk->data) {
- off_t offset = in_chunk->data - in_chunk->mem;
+ ptrdiff_t offset = in_chunk->data - in_chunk->mem;
newch->data = newch->mem + offset;
}
return newch;
@@ -710,7 +710,8 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in)
/** Internal structure: represents a position in a buffer. */
typedef struct buf_pos_t {
const chunk_t *chunk; /**< Which chunk are we pointing to? */
- int pos;/**< Which character inside the chunk's data are we pointing to? */
+ ptrdiff_t pos;/**< Which character inside the chunk's data are we pointing
+ * to? */
size_t chunk_pos; /**< Total length of all previous chunks. */
} buf_pos_t;
@@ -726,15 +727,15 @@ buf_pos_init(const buf_t *buf, buf_pos_t *out)
/** Advance <b>out</b> to the first appearance of <b>ch</b> at the current
* position of <b>out</b>, or later. Return -1 if no instances are found;
* otherwise returns the absolute position of the character. */
-static off_t
+static ptrdiff_t
buf_find_pos_of_char(char ch, buf_pos_t *out)
{
const chunk_t *chunk;
- int pos;
+ ptrdiff_t pos;
tor_assert(out);
if (out->chunk) {
if (out->chunk->datalen) {
- tor_assert(out->pos < (off_t)out->chunk->datalen);
+ tor_assert(out->pos < (ptrdiff_t)out->chunk->datalen);
} else {
tor_assert(out->pos == 0);
}
@@ -762,7 +763,7 @@ buf_pos_inc(buf_pos_t *pos)
{
tor_assert(pos->pos < INT_MAX - 1);
++pos->pos;
- if (pos->pos == (off_t)pos->chunk->datalen) {
+ if (pos->pos == (ptrdiff_t)pos->chunk->datalen) {
if (!pos->chunk->next)
return -1;
pos->chunk_pos += pos->chunk->datalen;
@@ -836,11 +837,11 @@ buf_peek_startswith(const buf_t *buf, const char *cmd)
/** Return the index within <b>buf</b> at which <b>ch</b> first appears,
* or -1 if <b>ch</b> does not appear on buf. */
-static off_t
+static ptrdiff_t
buf_find_offset_of_char(buf_t *buf, char ch)
{
chunk_t *chunk;
- off_t offset = 0;
+ ptrdiff_t offset = 0;
tor_assert(buf->datalen < INT_MAX);
for (chunk = buf->head; chunk; chunk = chunk->next) {
char *cp = memchr(chunk->data, ch, chunk->datalen);
@@ -863,7 +864,7 @@ int
buf_get_line(buf_t *buf, char *data_out, size_t *data_len)
{
size_t sz;
- off_t offset;
+ ptrdiff_t offset;
if (!buf->head)
return 0;
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index a8d1593214..92301449e8 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -195,7 +195,7 @@
* structure <b>st</b>. Example:
* <pre>
* struct a { int foo; int bar; } x;
- * off_t bar_offset = offsetof(struct a, bar);
+ * ptrdiff_t bar_offset = offsetof(struct a, bar);
* int *bar_p = STRUCT_VAR_P(&x, bar_offset);
* *bar_p = 3;
* </pre>
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index fabad97d0c..4609564b34 100644
--- a/src/lib/conf/conftypes.h
+++ b/src/lib/conf/conftypes.h
@@ -33,6 +33,8 @@
#include "lib/conf/conftesting.h"
#endif
+#include <stddef.h>
+
/** Enumeration of types which option values can take */
typedef enum config_type_t {
CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
@@ -63,8 +65,17 @@ typedef enum config_type_t {
* context-sensitive config lines when fetching.
*/
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
- CONFIG_TYPE_EXTENDED, /**< Extended type; definition will appear in
- * pointer. */
+ /**
+ * Extended type: definition appears in the <b>type_def</b> pointer
+ * of the corresponding struct_member_t.
+ *
+ * For some types, we cannot define them as particular values of this
+ * enumeration, since those types are abstractions defined at a higher level
+ * than this module. (For example, parsing a routerset_t is higher-level
+ * than this module.) To handle this, we use CONFIG_TYPE_EXTENDED for those
+ * types, and give a definition for them in the struct_member_t.type_def.
+ **/
+ CONFIG_TYPE_EXTENDED,
} config_type_t;
/* Forward delcaration for var_type_def_t, for extended types. */
@@ -74,22 +85,33 @@ struct var_type_def_t;
typedef struct struct_member_t {
/** Name of the field. */
const char *name;
- /** Type of the field, according to the config_type_t enumeration.
+ /**
+ * Type of the field, according to the config_type_t enumeration.
*
- * This value is CONFIG_TYPE_EXTENDED for any type not listed in
- * config_type_t.
+ * For any type not otherwise listed in config_type_t, this field's value
+ * should be CONFIG_TYPE_EXTENDED. When it is, the <b>type_def</b> pointer
+ * must be set.
**/
+ /*
+ * NOTE: In future refactoring, we might remove this field entirely, along
+ * with its corresponding enumeration. In that case, we will require that
+ * type_def be set in all cases. If we do, we will also need a new mechanism
+ * to enforce consistency between configuration variable types and their
+ * corresponding structures, since our current design in
+ * lib/conf/conftesting.h won't work any more.
+ */
config_type_t type;
/**
* Pointer to a type definition for the type of this field. Overrides
- * <b>type</b> if not NULL.
+ * <b>type</b> if it is not NULL. Must be set when <b>type</b> is
+ * CONFIG_TYPE_EXTENDED.
**/
const struct var_type_def_t *type_def;
/**
* Offset of this field within the structure. Compute this with
* offsetof(structure, fieldname).
**/
- int offset;
+ ptrdiff_t offset;
} struct_member_t;
/**
@@ -100,9 +122,13 @@ typedef struct struct_member_t {
* that they have the correct type.
*/
typedef struct struct_magic_decl_t {
+ /** The name of the structure */
const char *typename;
+ /** A value used to recognize instances of this structure. */
uint32_t magic_val;
- int magic_offset;
+ /** The location within the structure at which we expect to find
+ * <b>magic_val</b>. */
+ ptrdiff_t magic_offset;
} struct_magic_decl_t;
/**
diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c
index 97a8fb3633..32f616c214 100644
--- a/src/lib/confmgt/structvar.c
+++ b/src/lib/confmgt/structvar.c
@@ -103,7 +103,7 @@ struct_var_assign(void *object, const char *value, char **errmsg,
void *p = struct_get_mptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_assign_ex(p, value, errmsg, def);
+ return typed_var_assign(p, value, errmsg, def);
}
/**
@@ -116,7 +116,7 @@ struct_var_free(void *object, const struct_member_t *member)
void *p = struct_get_mptr(object, member);
const var_type_def_t *def = get_type_def(member);
- typed_var_free_ex(p, def);
+ typed_var_free(p, def);
}
/**
@@ -129,7 +129,7 @@ struct_var_encode(const void *object, const struct_member_t *member)
const void *p = struct_get_ptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_encode_ex(p, def);
+ return typed_var_encode(p, def);
}
/**
@@ -143,7 +143,7 @@ struct_var_copy(void *dest, const void *src, const struct_member_t *member)
const void *p_src = struct_get_ptr(src, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_copy_ex(p_dest, p_src, def);
+ return typed_var_copy(p_dest, p_src, def);
}
/**
@@ -157,7 +157,7 @@ struct_var_eq(const void *a, const void *b, const struct_member_t *member)
const void *p_b = struct_get_ptr(b, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_eq_ex(p_a, p_b, def);
+ return typed_var_eq(p_a, p_b, def);
}
/**
@@ -170,7 +170,7 @@ struct_var_ok(const void *object, const struct_member_t *member)
const void *p = struct_get_ptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_ok_ex(p, def);
+ return typed_var_ok(p, def);
}
/**
@@ -185,7 +185,7 @@ struct_var_kvassign(void *object, const struct config_line_t *line,
void *p = struct_get_mptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_kvassign_ex(p, line, errmsg, def);
+ return typed_var_kvassign(p, line, errmsg, def);
}
/**
@@ -198,7 +198,7 @@ struct_var_kvencode(const void *object, const struct_member_t *member)
const void *p = struct_get_ptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_kvencode_ex(member->name, p, def);
+ return typed_var_kvencode(member->name, p, def);
}
/**
@@ -211,7 +211,7 @@ struct_var_mark_fragile(void *object, const struct_member_t *member)
{
void *p = struct_get_mptr(object, member);
const var_type_def_t *def = get_type_def(member);
- return typed_var_mark_fragile_ex(p, def);
+ return typed_var_mark_fragile(p, def);
}
/**
diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c
index 3cba075390..43040e1e05 100644
--- a/src/lib/confmgt/typedvar.c
+++ b/src/lib/confmgt/typedvar.c
@@ -40,13 +40,13 @@
* string holding an error message, and return -1.
**/
int
-typed_var_assign_ex(void *target, const char *value, char **errmsg,
+typed_var_assign(void *target, const char *value, char **errmsg,
const var_type_def_t *def)
{
if (BUG(!def))
return -1; // LCOV_EXCL_LINE
// clear old value if needed.
- typed_var_free_ex(target, def);
+ typed_var_free(target, def);
tor_assert(def->fns->parse);
return def->fns->parse(target, value, errmsg, def->params);
@@ -55,7 +55,7 @@ typed_var_assign_ex(void *target, const char *value, char **errmsg,
/**
* Try to parse a single line from the head of<b>line</b> that encodes an
* object of the type defined in <b>def</b>. On success and failure, behave as
- * typed_var_assign_ex().
+ * typed_var_assign().
*
* All types for which keys are significant should use this function.
*
@@ -63,7 +63,7 @@ typed_var_assign_ex(void *target, const char *value, char **errmsg,
* only the first one is handled by this function.
**/
int
-typed_var_kvassign_ex(void *target, const config_line_t *line,
+typed_var_kvassign(void *target, const config_line_t *line,
char **errmsg, const var_type_def_t *def)
{
if (BUG(!def))
@@ -75,7 +75,7 @@ typed_var_kvassign_ex(void *target, const config_line_t *line,
return def->fns->kv_parse(target, line, errmsg, def->params);
}
- return typed_var_assign_ex(target, line->value, errmsg, def);
+ return typed_var_assign(target, line->value, errmsg, def);
}
/**
@@ -83,7 +83,7 @@ typed_var_kvassign_ex(void *target, const config_line_t *line,
* <b>def</b>, and set <b>target</b> to a reasonable default.
**/
void
-typed_var_free_ex(void *target, const var_type_def_t *def)
+typed_var_free(void *target, const var_type_def_t *def)
{
if (BUG(!def))
return; // LCOV_EXCL_LINE
@@ -99,7 +99,7 @@ typed_var_free_ex(void *target, const var_type_def_t *def)
* Returns NULL if this option has a NULL value, or on internal error.
**/
char *
-typed_var_encode_ex(const void *value, const var_type_def_t *def)
+typed_var_encode(const void *value, const var_type_def_t *def)
{
if (BUG(!def))
return NULL; // LCOV_EXCL_LINE
@@ -108,7 +108,7 @@ typed_var_encode_ex(const void *value, const var_type_def_t *def)
}
/**
- * As typed_var_encode_ex(), but returns a newly allocated config_line_t
+ * As typed_var_encode(), but returns a newly allocated config_line_t
* object. The provided <b>key</b> is used as the key of the lines, unless
* the type is one (line a linelist) that encodes its own keys.
*
@@ -117,7 +117,7 @@ typed_var_encode_ex(const void *value, const var_type_def_t *def)
* Returns NULL if there are no lines to encode, or on internal error.
*/
config_line_t *
-typed_var_kvencode_ex(const char *key, const void *value,
+typed_var_kvencode(const char *key, const void *value,
const var_type_def_t *def)
{
if (BUG(!def))
@@ -125,7 +125,7 @@ typed_var_kvencode_ex(const char *key, const void *value,
if (def->fns->kv_encode) {
return def->fns->kv_encode(key, value, def->params);
}
- char *encoded_value = typed_var_encode_ex(value, def);
+ char *encoded_value = typed_var_encode(value, def);
if (!encoded_value)
return NULL;
@@ -142,7 +142,7 @@ typed_var_kvencode_ex(const char *key, const void *value,
* Return 0 on success, and -1 on failure.
**/
int
-typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
+typed_var_copy(void *dest, const void *src, const var_type_def_t *def)
{
if (BUG(!def))
return -1; // LCOV_EXCL_LINE
@@ -152,13 +152,13 @@ typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
}
// Otherwise, encode 'src' and parse the result into 'def'.
- char *enc = typed_var_encode_ex(src, def);
+ char *enc = typed_var_encode(src, def);
if (!enc) {
- typed_var_free_ex(dest, def);
+ typed_var_free(dest, def);
return 0;
}
char *err = NULL;
- int rv = typed_var_assign_ex(dest, enc, &err, def);
+ int rv = typed_var_assign(dest, enc, &err, def);
if (BUG(rv < 0)) {
// LCOV_EXCL_START
log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s",
@@ -175,7 +175,7 @@ typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
* Both types must be as defined by <b>def</b>.
**/
bool
-typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def)
+typed_var_eq(const void *a, const void *b, const var_type_def_t *def)
{
if (BUG(!def))
return false; // LCOV_EXCL_LINE
@@ -186,8 +186,8 @@ typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def)
}
// Otherwise, encode the values and compare them.
- char *enc_a = typed_var_encode_ex(a, def);
- char *enc_b = typed_var_encode_ex(b, def);
+ char *enc_a = typed_var_encode(a, def);
+ char *enc_b = typed_var_encode(b, def);
bool eq = !strcmp_opt(enc_a,enc_b);
tor_free(enc_a);
tor_free(enc_b);
@@ -199,7 +199,7 @@ typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def)
* type definition in <b>def</b>.
*/
bool
-typed_var_ok_ex(const void *value, const var_type_def_t *def)
+typed_var_ok(const void *value, const var_type_def_t *def)
{
if (BUG(!def))
return false; // LCOV_EXCL_LINE
@@ -216,7 +216,7 @@ typed_var_ok_ex(const void *value, const var_type_def_t *def)
* assignment instead.
**/
void
-typed_var_mark_fragile_ex(void *value, const var_type_def_t *def)
+typed_var_mark_fragile(void *value, const var_type_def_t *def)
{
if (BUG(!def)) {
return; // LCOV_EXCL_LINE
@@ -254,99 +254,3 @@ var_type_is_settable(const var_type_def_t *def)
{
return ! def->is_unsettable;
}
-
-/* =====
- * The functions below take a config_type_t instead of a var_type_def_t.
- * I'd like to deprecate them eventually and use var_type_def_t everywhere,
- * but for now they make migration easier.
- * ===== */
-
-/**
- * As typed_var_assign_ex(), but look up the definition of the configuration
- * type from a provided config_type_t enum.
- */
-int
-typed_var_assign(void *target, const char *value, char **errmsg,
- config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_assign_ex(target, value, errmsg, def);
-}
-
-/**
- * As typed_var_kvassign_ex(), but look up the definition of the configuration
- * type from a provided config_type_t enum.
- */
-int
-typed_var_kvassign(void *target, const config_line_t *line, char **errmsg,
- config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_kvassign_ex(target, line, errmsg, def);
-}
-
-/**
- * As typed_var_free_ex(), but look up the definition of the configuration
- * type from a provided config_type_t enum.
- */
-void
-typed_var_free(void *target, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_free_ex(target, def);
-}
-
-/**
- * As typed_var_encode_ex(), but look up the definition of the configuration
- * type from a provided config_type_t enum.
- */
-char *
-typed_var_encode(const void *value, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_encode_ex(value, def);
-}
-
-/**
- * As typed_var_kvencode_ex(), but look up the definition of the configuration
- * type from a provided config_type_t enum.
- */
-config_line_t *
-typed_var_kvencode(const char *key, const void *value, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_kvencode_ex(key, value, def);
-}
-
-/**
- * As typed_var_copy_ex(), but look up the definition of the configuration type
- * from a provided config_type_t enum.
- */
-int
-typed_var_copy(void *dest, const void *src, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_copy_ex(dest, src, def);
-}
-
-/**
- * As typed_var_eq_ex(), but look up the definition of the configuration type
- * from a provided config_type_t enum.
- */
-bool
-typed_var_eq(const void *a, const void *b, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_eq_ex(a, b, def);
-}
-
-/**
- * As typed_var_ok_ex(), but look up the definition of the configuration type
- * from a provided config_type_t enum.
- */
-bool
-typed_var_ok(const void *value, config_type_t type)
-{
- const var_type_def_t *def = lookup_type_def(type);
- return typed_var_ok_ex(value, def);
-}
diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h
index 2e36f9d673..23fd8c13e4 100644
--- a/src/lib/confmgt/typedvar.h
+++ b/src/lib/confmgt/typedvar.h
@@ -21,32 +21,19 @@ typedef struct var_type_fns_t var_type_fns_t;
typedef struct var_type_def_t var_type_def_t;
int typed_var_assign(void *target, const char *value, char **errmsg,
- enum config_type_t type);
-void typed_var_free(void *target, enum config_type_t type);
-char *typed_var_encode(const void *value, enum config_type_t type);
-int typed_var_copy(void *dest, const void *src, enum config_type_t type);
-bool typed_var_eq(const void *a, const void *b, enum config_type_t type);
-bool typed_var_ok(const void *value, enum config_type_t type);
-
-int typed_var_kvassign(void *target, const struct config_line_t *line,
- char **errmsg, enum config_type_t type);
-struct config_line_t *typed_var_kvencode(const char *key, const void *value,
- enum config_type_t type);
-
-int typed_var_assign_ex(void *target, const char *value, char **errmsg,
const var_type_def_t *def);
-void typed_var_free_ex(void *target, const var_type_def_t *def);
-char *typed_var_encode_ex(const void *value, const var_type_def_t *def);
-int typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def);
-bool typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def);
-bool typed_var_ok_ex(const void *value, const var_type_def_t *def);
+void typed_var_free(void *target, const var_type_def_t *def);
+char *typed_var_encode(const void *value, const var_type_def_t *def);
+int typed_var_copy(void *dest, const void *src, const var_type_def_t *def);
+bool typed_var_eq(const void *a, const void *b, const var_type_def_t *def);
+bool typed_var_ok(const void *value, const var_type_def_t *def);
-int typed_var_kvassign_ex(void *target, const struct config_line_t *line,
+int typed_var_kvassign(void *target, const struct config_line_t *line,
char **errmsg, const var_type_def_t *def);
-struct config_line_t *typed_var_kvencode_ex(const char *key, const void *value,
+struct config_line_t *typed_var_kvencode(const char *key, const void *value,
const var_type_def_t *def);
-void typed_var_mark_fragile_ex(void *value, const var_type_def_t *def);
+void typed_var_mark_fragile(void *value, const var_type_def_t *def);
bool var_type_is_cumulative(const var_type_def_t *def);
bool var_type_is_contained(const var_type_def_t *def);
diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c
index 3ab2797d68..2b71c11287 100644
--- a/src/lib/container/smartlist.c
+++ b/src/lib/container/smartlist.c
@@ -678,7 +678,7 @@ smartlist_sort_pointers(smartlist_t *sl)
static inline void
smartlist_heapify(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset,
+ ptrdiff_t idx_field_offset,
int idx)
{
while (1) {
@@ -725,7 +725,7 @@ smartlist_heapify(smartlist_t *sl,
void
smartlist_pqueue_add(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset,
+ ptrdiff_t idx_field_offset,
void *item)
{
int idx;
@@ -754,7 +754,7 @@ smartlist_pqueue_add(smartlist_t *sl,
void *
smartlist_pqueue_pop(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset)
+ ptrdiff_t idx_field_offset)
{
void *top;
tor_assert(sl->num_used);
@@ -778,7 +778,7 @@ smartlist_pqueue_pop(smartlist_t *sl,
void
smartlist_pqueue_remove(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset,
+ ptrdiff_t idx_field_offset,
void *item)
{
int idx = IDX_OF_ITEM(item);
@@ -802,7 +802,7 @@ smartlist_pqueue_remove(smartlist_t *sl,
void
smartlist_pqueue_assert_ok(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset)
+ ptrdiff_t idx_field_offset)
{
int i;
for (i = sl->num_used - 1; i >= 0; --i) {
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index 81b0151433..25638e4b22 100644
--- a/src/lib/container/smartlist.h
+++ b/src/lib/container/smartlist.h
@@ -13,6 +13,7 @@
**/
#include <stdarg.h>
+#include <stddef.h>
#include "lib/smartlist_core/smartlist_core.h"
#include "lib/smartlist_core/smartlist_foreach.h"
@@ -72,18 +73,18 @@ int smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
void smartlist_pqueue_add(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset,
+ ptrdiff_t idx_field_offset,
void *item);
void *smartlist_pqueue_pop(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset);
+ ptrdiff_t idx_field_offset);
void smartlist_pqueue_remove(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset,
+ ptrdiff_t idx_field_offset,
void *item);
void smartlist_pqueue_assert_ok(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
- int idx_field_offset);
+ ptrdiff_t idx_field_offset);
char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate,
size_t *len_out) ATTR_MALLOC;
diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c
index 1a246e995c..48fcf35e06 100644
--- a/src/lib/err/torerr.c
+++ b/src/lib/err/torerr.c
@@ -234,8 +234,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len,
* does not guarantee that an int is wider than a char (an int must be at
* least 16 bits but it is permitted for a char to be that wide as well), we
* can't assume a signed int is sufficient to accommodate an unsigned char.
- * Thus, format_helper_exit_status() will still need to emit any require '-'
- * on its own.
+ * Thus, callers will still need to add any required '-' to the final string.
*
* For most purposes, you'd want to use tor_snprintf("%x") instead of this
* function; it's designed to be used in code paths where you can't call
diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h
index 4f30bf5392..ffc892c3e5 100644
--- a/src/lib/string/compat_string.h
+++ b/src/lib/string/compat_string.h
@@ -39,6 +39,9 @@ static inline int strcasecmp(const char *a, const char *b) {
* appear to have a severe bug that can sometimes cause aborts in Tor.
* Instead, use the non-checking variants. This is sad.
*
+ * (If --enable-fragile-hardening is passed to configure, we use the hardened
+ * variants, which do not suffer from this issue.)
+ *
* See https://trac.torproject.org/projects/tor/ticket/15205
*/
#undef strlcat
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
index 6d0f9d7d60..862acb2b35 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -1,6 +1,7 @@
/* Copyright (c) 2016-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
+#define CONFIG_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "app/main/subsysmgr.h"
@@ -111,7 +112,7 @@ global_init(void)
}
/* set up the options. */
- mock_options = tor_malloc_zero(sizeof(or_options_t));
+ mock_options = options_new();
MOCK(get_options, mock_get_options);
/* Make BUG() and nonfatal asserts crash */
@@ -189,7 +190,7 @@ main(int argc, char **argv)
if (fuzz_cleanup() < 0)
abort();
- tor_free(mock_options);
+ or_options_free(mock_options);
UNMOCK(get_options);
return 0;
}
diff --git a/src/test/include.am b/src/test/include.am
index 1e20f3f53f..1ec54a286f 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -124,6 +124,7 @@ src_test_test_SOURCES += \
src/test/test_circuitstats.c \
src/test/test_compat_libevent.c \
src/test/test_config.c \
+ src/test/test_confmgr.c \
src/test/test_confparse.c \
src/test/test_connection.c \
src/test/test_conscache.c \
diff --git a/src/test/test.c b/src/test/test.c
index b9a1da06f0..65e169b38e 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -840,6 +840,7 @@ struct testgroup_t testgroups[] = {
{ "circuituse/", circuituse_tests },
{ "compat/libevent/", compat_libevent_tests },
{ "config/", config_tests },
+ { "config/mgr/", confmgr_tests },
{ "config/parse/", confparse_tests },
{ "connection/", connection_tests },
{ "conscache/", conscache_tests },
diff --git a/src/test/test.h b/src/test/test.h
index f5c21bfe88..d6a1d19ea1 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -197,6 +197,7 @@ extern struct testcase_t circuitstats_tests[];
extern struct testcase_t circuituse_tests[];
extern struct testcase_t compat_libevent_tests[];
extern struct testcase_t config_tests[];
+extern struct testcase_t confmgr_tests[];
extern struct testcase_t confparse_tests[];
extern struct testcase_t connection_tests[];
extern struct testcase_t conscache_tests[];
diff --git a/src/test/test_config.c b/src/test/test_config.c
index a415ca4480..58e05e5094 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1755,6 +1755,18 @@ add_default_fallback_dir_servers_known_default(void)
n_add_default_fallback_dir_servers_known_default++;
}
+/* Helper for test_config_adding_dir_servers(), which should be
+ * refactored: clear the fields in the options which the options object
+ * does not really own. */
+static void
+ads_clear_helper(or_options_t *options)
+{
+ options->DirAuthorities = NULL;
+ options->AlternateBridgeAuthority = NULL;
+ options->AlternateDirAuthority = NULL;
+ options->FallbackDir = NULL;
+}
+
/* Test all the different combinations of adding dir servers */
static void
test_config_adding_dir_servers(void *arg)
@@ -1762,7 +1774,7 @@ test_config_adding_dir_servers(void *arg)
(void)arg;
/* allocate options */
- or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+ or_options_t *options = options_new();
/* Allocate and populate configuration lines:
*
@@ -1885,7 +1897,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -1967,7 +1981,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2108,7 +2124,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2249,7 +2267,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2391,7 +2411,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2543,7 +2565,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2697,7 +2721,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2860,7 +2886,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3017,7 +3045,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3183,7 +3213,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3346,7 +3378,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3515,10 +3549,7 @@ test_config_adding_dir_servers(void *arg)
tor_free(test_fallback_directory->value);
tor_free(test_fallback_directory);
- options->DirAuthorities = NULL;
- options->AlternateBridgeAuthority = NULL;
- options->AlternateDirAuthority = NULL;
- options->FallbackDir = NULL;
+ ads_clear_helper(options);
or_options_free(options);
UNMOCK(add_default_fallback_dir_servers);
@@ -3533,7 +3564,7 @@ test_config_default_dir_servers(void *arg)
int fallback_count = 0;
/* new set of options should stop fallback parsing */
- opts = tor_malloc_zero(sizeof(or_options_t));
+ opts = options_new();
opts->UseDefaultFallbackDirs = 0;
/* set old_options to NULL to force dir update */
consider_adding_dir_servers(opts, NULL);
@@ -3547,7 +3578,7 @@ test_config_default_dir_servers(void *arg)
/* if we disable the default fallbacks, there must not be any extra */
tt_assert(fallback_count == trusted_count);
- opts = tor_malloc_zero(sizeof(or_options_t));
+ opts = options_new();
opts->UseDefaultFallbackDirs = 1;
consider_adding_dir_servers(opts, opts);
trusted_count = smartlist_len(router_get_trusted_dir_servers());
@@ -3607,7 +3638,7 @@ test_config_directory_fetch(void *arg)
(void)arg;
/* Test Setup */
- or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+ or_options_t *options = options_new();
routerinfo_t routerinfo;
memset(&routerinfo, 0, sizeof(routerinfo));
mock_router_pick_published_address_result = -1;
@@ -3619,9 +3650,10 @@ test_config_directory_fetch(void *arg)
mock_router_my_exit_policy_is_reject_star);
MOCK(advertised_server_mode, mock_advertised_server_mode);
MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo);
+ or_options_free(options);
+ options = options_new();
/* Clients can use multiple directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
options->ClientOnly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
@@ -3630,7 +3662,8 @@ test_config_directory_fetch(void *arg)
OP_EQ, 1);
/* Bridge Clients can use multiple directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->UseBridges = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
@@ -3640,7 +3673,8 @@ test_config_directory_fetch(void *arg)
/* Bridge Relays (Bridges) must act like clients, and use multiple
* directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->BridgeRelay = 1;
options->ORPort_set = 1;
tt_assert(server_mode(options) == 1);
@@ -3651,7 +3685,8 @@ test_config_directory_fetch(void *arg)
/* Clients set to FetchDirInfoEarly must fetch it from the authorities,
* but can use multiple authorities for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->FetchDirInfoEarly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
@@ -3662,7 +3697,8 @@ test_config_directory_fetch(void *arg)
/* OR servers only fetch the consensus from the authorities when they don't
* know their own address, but never use multiple directories for bootstrap
*/
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->ORPort_set = 1;
mock_router_pick_published_address_result = -1;
@@ -3682,7 +3718,8 @@ test_config_directory_fetch(void *arg)
/* Exit OR servers only fetch the consensus from the authorities when they
* refuse unknown exits, but never use multiple directories for bootstrap
*/
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->ORPort_set = 1;
options->ExitRelay = 1;
mock_router_pick_published_address_result = 0;
@@ -3712,7 +3749,8 @@ test_config_directory_fetch(void *arg)
* advertising their dirport, and never use multiple directories for
* bootstrap. This only applies if they are also OR servers.
* (We don't care much about the behaviour of non-OR directory servers.) */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->DirPort_set = 1;
options->ORPort_set = 1;
options->DirCache = 1;
@@ -3766,7 +3804,7 @@ test_config_directory_fetch(void *arg)
OP_EQ, 0);
done:
- tor_free(options);
+ or_options_free(options);
UNMOCK(router_pick_published_address);
UNMOCK(router_get_my_routerinfo);
UNMOCK(advertised_server_mode);
diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c
new file mode 100644
index 0000000000..5f73d9754b
--- /dev/null
+++ b/src/test/test_confmgr.c
@@ -0,0 +1,325 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * Tests for confparse.c's features that support multiple configuration
+ * formats and configuration objects.
+ */
+
+#define CONFPARSE_PRIVATE
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "lib/encoding/confline.h"
+#include "app/config/confparse.h"
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+/*
+ * Set up a few objects: a pasture_cfg is toplevel; it has a llama_cfg and an
+ * alpaca_cfg.
+ */
+
+typedef struct {
+ uint32_t magic;
+ char *address;
+ int opentopublic;
+ config_suite_t *subobjs;
+} pasture_cfg_t;
+
+typedef struct {
+ char *llamaname;
+ int cuteness;
+ uint32_t magic;
+ int eats_meat; /* deprecated; llamas are never carnivorous. */
+
+ char *description; // derived from other fields.
+} llama_cfg_t;
+
+typedef struct {
+ uint32_t magic;
+ int fuzziness;
+ char *alpacaname;
+ int n_wings; /* deprecated; alpacas don't have wings. */
+} alpaca_cfg_t;
+
+/*
+ * Make the above into configuration objects.
+ */
+
+static pasture_cfg_t pasture_cfg_t_dummy;
+static llama_cfg_t llama_cfg_t_dummy;
+static alpaca_cfg_t alpaca_cfg_t_dummy;
+
+#define PV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(pasture_cfg_t, #name, type, name, 0, dflt)
+#define LV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(llama_cfg_t, #name, type, name, 0, dflt)
+#define AV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(alpaca_cfg_t, #name, type, name, 0, dflt)
+static const config_var_t pasture_vars[] = {
+ PV(address, STRING, NULL),
+ PV(opentopublic, BOOL, "1"),
+ END_OF_CONFIG_VARS
+};
+static const config_var_t llama_vars[] =
+{
+ LV(llamaname, STRING, NULL),
+ LV(eats_meat, BOOL, NULL),
+ LV(cuteness, POSINT, "100"),
+ END_OF_CONFIG_VARS
+};
+static const config_var_t alpaca_vars[] =
+{
+ AV(alpacaname, STRING, NULL),
+ AV(fuzziness, POSINT, "50"),
+ AV(n_wings, POSINT, "0"),
+ END_OF_CONFIG_VARS
+};
+
+static config_deprecation_t llama_deprecations[] = {
+ { "eats_meat", "Llamas are herbivores." },
+ {NULL,NULL}
+};
+
+static config_deprecation_t alpaca_deprecations[] = {
+ { "n_wings", "Alpacas are quadrupeds." },
+ {NULL,NULL}
+};
+
+static int clear_llama_cfg_called = 0;
+static void
+clear_llama_cfg(const config_mgr_t *mgr, void *llamacfg)
+{
+ (void)mgr;
+ llama_cfg_t *lc = llamacfg;
+ tor_free(lc->description);
+ ++clear_llama_cfg_called;
+}
+
+static config_abbrev_t llama_abbrevs[] = {
+ { "gracia", "cuteness", 0, 0 },
+ { "gentillesse", "cuteness", 0, 0 },
+ { NULL, NULL, 0, 0 },
+};
+
+static const config_format_t pasture_fmt = {
+ sizeof(pasture_cfg_t),
+ {
+ "pasture_cfg_t",
+ 8989,
+ offsetof(pasture_cfg_t, magic)
+ },
+ .vars = pasture_vars,
+ .config_suite_offset = offsetof(pasture_cfg_t, subobjs),
+};
+
+static const config_format_t llama_fmt = {
+ sizeof(llama_cfg_t),
+ {
+ "llama_cfg_t",
+ 0x11aa11,
+ offsetof(llama_cfg_t, magic)
+ },
+ .vars = llama_vars,
+ .config_suite_offset = -1,
+ .deprecations = llama_deprecations,
+ .abbrevs = llama_abbrevs,
+ .clear_fn = clear_llama_cfg,
+};
+
+static const config_format_t alpaca_fmt = {
+ sizeof(alpaca_cfg_t),
+ {
+ "alpaca_cfg_t",
+ 0xa15aca,
+ offsetof(alpaca_cfg_t, magic)
+ },
+ .vars = alpaca_vars,
+ .config_suite_offset = -1,
+ .deprecations = alpaca_deprecations,
+};
+
+#define LLAMA_IDX 0
+#define ALPACA_IDX 1
+
+static config_mgr_t *
+get_mgr(bool freeze)
+{
+ config_mgr_t *mgr = config_mgr_new(&pasture_fmt);
+ tt_int_op(LLAMA_IDX, OP_EQ, config_mgr_add_format(mgr, &llama_fmt));
+ tt_int_op(ALPACA_IDX, OP_EQ, config_mgr_add_format(mgr, &alpaca_fmt));
+ if (freeze)
+ config_mgr_freeze(mgr);
+ return mgr;
+
+ done:
+ config_mgr_free(mgr);
+ return NULL;
+}
+
+static void
+test_confmgr_init(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ smartlist_t *vars = NULL;
+ tt_ptr_op(mgr, OP_NE, NULL);
+
+ vars = config_mgr_list_vars(mgr);
+ tt_int_op(smartlist_len(vars), OP_EQ, 8); // 8 vars total.
+
+ tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "CUTENESS"));
+ tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "GRACIA"));
+ smartlist_free(vars);
+
+ vars = config_mgr_list_deprecated_vars(mgr); // 2 deprecated vars.
+ tt_int_op(smartlist_len(vars), OP_EQ, 2);
+ tt_assert(smartlist_contains_string(vars, "eats_meat"));
+ tt_assert(smartlist_contains_string(vars, "n_wings"));
+
+ tt_str_op("Llamas are herbivores.", OP_EQ,
+ config_find_deprecation(mgr, "EATS_MEAT"));
+ tt_str_op("Alpacas are quadrupeds.", OP_EQ,
+ config_find_deprecation(mgr, "N_WINGS"));
+
+ done:
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confmgr_magic(void *args)
+{
+ (void)args;
+ // Every time we build a manager, it is supposed to get a different magic
+ // number. Let's test that.
+ config_mgr_t *mgr1 = get_mgr(true);
+ config_mgr_t *mgr2 = get_mgr(true);
+ config_mgr_t *mgr3 = get_mgr(true);
+
+ pasture_cfg_t *p1 = NULL, *p2 = NULL, *p3 = NULL;
+
+ tt_assert(mgr1);
+ tt_assert(mgr2);
+ tt_assert(mgr3);
+
+ p1 = config_new(mgr1);
+ p2 = config_new(mgr2);
+ p3 = config_new(mgr3);
+
+ tt_assert(p1);
+ tt_assert(p2);
+ tt_assert(p3);
+
+ // By chance, two managers get the same magic with P=2^-32. Let's
+ // make sure that at least two of them are different, so that our
+ // odds of a false positive are 1/2^-64.
+ tt_assert((p1->magic != p2->magic) || (p2->magic != p3->magic));
+
+ done:
+ config_free(mgr1, p1);
+ config_free(mgr2, p2);
+ config_free(mgr3, p3);
+
+ config_mgr_free(mgr1);
+ config_mgr_free(mgr2);
+ config_mgr_free(mgr3);
+}
+
+static const char *simple_pasture =
+ "LLamaname hugo\n"
+ "Alpacaname daphne\n"
+ "gentillesse 42\n"
+ "address 123 Camelid ave\n";
+
+static void
+test_confmgr_parse(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, p); // set defaults.
+
+ int r = config_get_lines(simple_pasture, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ tt_int_op(p->opentopublic, OP_EQ, 1);
+ tt_str_op(p->address, OP_EQ, "123 Camelid ave");
+
+ // We are using this API directly; modules outside confparse will, in the
+ // future, not.
+ const alpaca_cfg_t *ac = config_mgr_get_obj(mgr, p, ALPACA_IDX);
+ const llama_cfg_t *lc = config_mgr_get_obj(mgr, p, LLAMA_IDX);
+ tt_str_op(lc->llamaname, OP_EQ, "hugo");
+ tt_str_op(ac->alpacaname, OP_EQ, "daphne");
+ tt_int_op(lc->cuteness, OP_EQ, 42);
+ tt_int_op(ac->fuzziness, OP_EQ, 50);
+
+ // We set the description for the llama here, so that the clear function
+ // can clear it. (Later we can do this in a verification function.)
+ clear_llama_cfg_called = 0;
+ llama_cfg_t *mut_lc = config_mgr_get_obj_mutable(mgr, p, LLAMA_IDX);
+ mut_lc->description = tor_strdup("A llama named Hugo.");
+ config_free(mgr, p);
+ tt_int_op(clear_llama_cfg_called, OP_EQ, 1);
+
+ done:
+ config_free_lines(lines);
+ config_free(mgr, p);
+ config_mgr_free(mgr);
+ tor_free(msg);
+}
+
+static void
+test_confmgr_dump(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p = config_new(mgr);
+ pasture_cfg_t *defaults = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+ char *s = NULL;
+
+ config_init(mgr, p); // set defaults.
+ config_init(mgr, defaults); // set defaults.
+
+ int r = config_get_lines(simple_pasture, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ s = config_dump(mgr, defaults, p, 1, 0);
+ tt_str_op("address 123 Camelid ave\n"
+ "alpacaname daphne\n"
+ "cuteness 42\n"
+ "llamaname hugo\n", OP_EQ, s);
+
+ done:
+ config_free_lines(lines);
+ config_free(mgr, p);
+ config_free(mgr, defaults);
+ config_mgr_free(mgr);
+
+ tor_free(msg);
+ tor_free(s);
+}
+
+#define CONFMGR_TEST(name, flags) \
+ { #name, test_confmgr_ ## name, flags, NULL, NULL }
+
+struct testcase_t confmgr_tests[] = {
+ CONFMGR_TEST(init, 0),
+ CONFMGR_TEST(magic, 0),
+ CONFMGR_TEST(parse, 0),
+ CONFMGR_TEST(dump, 0),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c
index 4df275fc36..bd2b5cdf1b 100644
--- a/src/test/test_confparse.c
+++ b/src/test/test_confparse.c
@@ -119,8 +119,6 @@ test_validate_cb(void *old_options, void *options, void *default_options,
return 0;
}
-static void test_free_cb(void *options);
-
#define TEST_MAGIC 0x1337
static const config_format_t test_fmt = {
@@ -134,29 +132,22 @@ static const config_format_t test_fmt = {
test_deprecation_notes,
test_vars,
test_validate_cb,
- test_free_cb,
NULL,
+ NULL,
+ -1,
};
-static void
-test_free_cb(void *options)
-{
- if (!options)
- return;
-
- config_free(&test_fmt, options);
-}
-
/* Make sure that config_init sets everything to the right defaults. */
static void
test_confparse_init(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
- config_init(&test_fmt, tst);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
+ config_init(mgr, tst);
// Make sure that options are initialized right. */
- tt_uint_op(tst->magic, OP_EQ, TEST_MAGIC);
tt_str_op(tst->s, OP_EQ, "hello");
tt_ptr_op(tst->fn, OP_EQ, NULL);
tt_int_op(tst->pos, OP_EQ, 0);
@@ -178,7 +169,8 @@ test_confparse_init(void *arg)
tt_int_op(tst->hidden_int, OP_EQ, 0);
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
}
static const char simple_settings[] =
@@ -207,18 +199,18 @@ static const char simple_settings[] =
/* Return a configuration object set up from simple_settings above. */
static test_struct_t *
-get_simple_config(void)
+get_simple_config(const config_mgr_t *mgr)
{
test_struct_t *result = NULL;
- test_struct_t *tst = config_new(&test_fmt);
+ test_struct_t *tst = config_new(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines(simple_settings, &lines, 0);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -227,7 +219,7 @@ get_simple_config(void)
done:
tor_free(msg);
config_free_lines(lines);
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
return result;
}
@@ -236,7 +228,9 @@ static void
test_confparse_assign_simple(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
tt_str_op(tst->s, OP_EQ, "this is a");
tt_str_op(tst->fn, OP_EQ, "/simple/test of the");
@@ -284,10 +278,11 @@ test_confparse_assign_simple(void *arg)
tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
tt_assert(!tst->mixed_hidden_lines->next->next);
- tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
+ tt_assert(config_check_ok(mgr, tst, LOG_ERR));
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
}
/* Try to assign to an obsolete option, and make sure we get a warning. */
@@ -295,26 +290,29 @@ static void
test_confparse_assign_obsolete(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines("obsolete option here",
&lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
expect_single_log_msg_containing("Skipping obsolete configuration option");
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Try to assign to an deprecated option, and make sure we get a warning
@@ -323,30 +321,33 @@ static void
test_confparse_assign_deprecated(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines("deprecated_int 7",
&lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+ r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
expect_single_log_msg_containing("This integer is deprecated.");
tt_int_op(tst->deprecated_int, OP_EQ, 7);
- tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
+ tt_assert(config_check_ok(mgr, tst, LOG_ERR));
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Try to re-assign an option name that has been depreacted in favor of
@@ -355,16 +356,18 @@ static void
test_confparse_assign_replaced(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines("float 1000\n", &lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+ r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
expect_single_log_msg_containing("use 'dbl' instead.");
@@ -374,9 +377,10 @@ test_confparse_assign_replaced(void *arg)
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Try to set a linelist value with no option. */
@@ -384,25 +388,28 @@ static void
test_confparse_assign_emptystring(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines("lines\n", &lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
expect_single_log_msg_containing("has no value");
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Try to set a the same option twice; make sure we get a warning. */
@@ -410,26 +417,29 @@ static void
test_confparse_assign_twice(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines("pos 10\n"
"pos 99\n", &lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
expect_single_log_msg_containing("used more than once");
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
typedef struct badval_test_t {
@@ -443,16 +453,18 @@ static void
test_confparse_assign_badval(void *arg)
{
const badval_test_t *bt = arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
- config_init(&test_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines(bt->cfg, &lines, 0);
tt_int_op(r, OP_EQ, 0);
setup_capture_of_logs(LOG_WARN);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_LT, 0);
tt_ptr_op(msg, OP_NE, NULL);
if (! strstr(msg, bt->expect_msg)) {
@@ -461,9 +473,10 @@ test_confparse_assign_badval(void *arg)
done:
teardown_capture_of_logs();
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Various arguments for badval test.
@@ -495,88 +508,90 @@ static void
test_confparse_dump(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
char *dumped = NULL;
/* Minimal version. */
- dumped = config_dump(&test_fmt, NULL, tst, 1, 0);
+ dumped = config_dump(mgr, NULL, tst, 1, 0);
tt_str_op(dumped, OP_EQ,
- "s this is a\n"
- "fn /simple/test of the\n"
- "pos 77\n"
- "i 3\n"
- "u64 1000000000000\n"
- "interval 300\n"
- "msec_interval 300000\n"
- "mem 10\n"
- "dbl 6.060842\n"
- "boolean 1\n"
"autobool 0\n"
- "time 2019-06-14 13:58:51\n"
+ "boolean 1\n"
"csv configuration,parsing,system\n"
"csv_interval 10\n"
+ "dbl 6.060842\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
"lines hello\n"
"lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
"LineTypeA i d\n"
"LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
"routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
- "VisibleLineB ABC\n");
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
- /* Maximal */
tor_free(dumped);
- dumped = config_dump(&test_fmt, NULL, tst, 0, 0);
+ dumped = config_dump(mgr, NULL, tst, 0, 0);
tt_str_op(dumped, OP_EQ,
- "s this is a\n"
- "fn /simple/test of the\n"
- "pos 77\n"
- "i 3\n"
- "deprecated_int 3\n"
- "u64 1000000000000\n"
- "interval 300\n"
- "msec_interval 300000\n"
- "mem 10\n"
- "dbl 6.060842\n"
- "boolean 1\n"
"autobool 0\n"
- "time 2019-06-14 13:58:51\n"
+ "boolean 1\n"
"csv configuration,parsing,system\n"
"csv_interval 10\n"
+ "dbl 6.060842\n"
+ "deprecated_int 3\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
"lines hello\n"
"lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
"LineTypeA i d\n"
"LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
"routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
- "VisibleLineB ABC\n");
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
/* commented */
tor_free(dumped);
- dumped = config_dump(&test_fmt, NULL, tst, 0, 1);
+ dumped = config_dump(mgr, NULL, tst, 0, 1);
tt_str_op(dumped, OP_EQ,
- "s this is a\n"
- "fn /simple/test of the\n"
- "pos 77\n"
- "i 3\n"
- "# deprecated_int 3\n"
- "u64 1000000000000\n"
- "interval 300\n"
- "msec_interval 300000\n"
- "mem 10\n"
- "dbl 6.060842\n"
- "boolean 1\n"
"autobool 0\n"
- "time 2019-06-14 13:58:51\n"
+ "boolean 1\n"
"csv configuration,parsing,system\n"
"csv_interval 10\n"
+ "dbl 6.060842\n"
+ "# deprecated_int 3\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
"lines hello\n"
"lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
"LineTypeA i d\n"
"LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
"routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
- "VisibleLineB ABC\n");
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
tor_free(dumped);
+ config_mgr_free(mgr);
}
/* Try confparse_reset_line(), and make sure it behaves correctly */
@@ -584,20 +599,23 @@ static void
test_confparse_reset(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
- config_reset_line(&test_fmt, tst, "interval", 0);
+ config_reset_line(mgr, tst, "interval", 0);
tt_int_op(tst->interval, OP_EQ, 0);
- config_reset_line(&test_fmt, tst, "interval", 1);
+ config_reset_line(mgr, tst, "interval", 1);
tt_int_op(tst->interval, OP_EQ, 10);
tt_ptr_op(tst->routerset, OP_NE, NULL);
- config_reset_line(&test_fmt, tst, "routerset", 0);
+ config_reset_line(mgr, tst, "routerset", 0);
tt_ptr_op(tst->routerset, OP_EQ, NULL);
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
}
/* Try setting options a second time on a config object, and make sure
@@ -606,7 +624,9 @@ static void
test_confparse_reassign(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL, *rs = NULL;
@@ -617,7 +637,7 @@ test_confparse_reassign(void *arg)
"csv 14,15\n"
"routerset 127.0.0.1\n",
&lines, 0);
- r = config_assign(&test_fmt, tst,lines, 0, &msg);
+ r = config_assign(mgr, tst,lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -637,7 +657,7 @@ test_confparse_reassign(void *arg)
tt_str_op(rs, OP_EQ, "127.0.0.1");
// Try again with the CLEAR_FIRST and USE_DEFAULTS flags
- r = config_assign(&test_fmt, tst, lines,
+ r = config_assign(mgr, tst, lines,
CAL_CLEAR_FIRST|CAL_USE_DEFAULTS, &msg);
tt_int_op(r, OP_EQ, 0);
@@ -648,10 +668,11 @@ test_confparse_reassign(void *arg)
tt_int_op(tst->i, OP_EQ, 12);
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
tor_free(rs);
+ config_mgr_free(mgr);
}
/* Try setting options a second time on a config object, using the +foo
@@ -660,7 +681,9 @@ static void
test_confparse_reassign_extend(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
char *msg = NULL;
@@ -668,7 +691,7 @@ test_confparse_reassign_extend(void *arg)
"+lines 13\n",
&lines, 1); // allow extended format.
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&test_fmt, tst,lines, 0, &msg);
+ r = config_assign(mgr, tst,lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -688,27 +711,28 @@ test_confparse_reassign_extend(void *arg)
"/lines\n",
&lines, 1); // allow extended format.
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
tt_assert(tst->lines == NULL);
config_free_lines(lines);
- config_free(&test_fmt, tst);
- tst = get_simple_config();
+ config_free(mgr, tst);
+ tst = get_simple_config(mgr);
r = config_get_lines(
"/lines away!\n",
&lines, 1); // allow extended format.
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&test_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
tt_assert(tst->lines == NULL);
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
tor_free(msg);
+ config_mgr_free(mgr);
}
/* Test out confparse_get_assigned(). */
@@ -716,30 +740,33 @@ static void
test_confparse_get_assigned(void *arg)
{
(void)arg;
- test_struct_t *tst = get_simple_config();
+
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
config_line_t *lines = NULL;
- lines = config_get_assigned_option(&test_fmt, tst, "I", 1);
+ lines = config_get_assigned_option(mgr, tst, "I", 1);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "i");
tt_str_op(lines->value, OP_EQ, "3");
tt_assert(lines->next == NULL);
config_free_lines(lines);
- lines = config_get_assigned_option(&test_fmt, tst, "s", 1);
+ lines = config_get_assigned_option(mgr, tst, "s", 1);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "s");
tt_str_op(lines->value, OP_EQ, "this is a");
tt_assert(lines->next == NULL);
config_free_lines(lines);
- lines = config_get_assigned_option(&test_fmt, tst, "obsolete", 1);
+ lines = config_get_assigned_option(mgr, tst, "obsolete", 1);
tt_assert(!lines);
- lines = config_get_assigned_option(&test_fmt, tst, "nonesuch", 1);
+ lines = config_get_assigned_option(mgr, tst, "nonesuch", 1);
tt_assert(!lines);
- lines = config_get_assigned_option(&test_fmt, tst, "mixedlines", 1);
+ lines = config_get_assigned_option(mgr, tst, "mixedlines", 1);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "LineTypeA");
tt_str_op(lines->value, OP_EQ, "i d");
@@ -749,7 +776,7 @@ test_confparse_get_assigned(void *arg)
tt_assert(lines->next->next == NULL);
config_free_lines(lines);
- lines = config_get_assigned_option(&test_fmt, tst, "linetypeb", 1);
+ lines = config_get_assigned_option(mgr, tst, "linetypeb", 1);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "LineTypeB");
tt_str_op(lines->value, OP_EQ, "i c");
@@ -758,7 +785,7 @@ test_confparse_get_assigned(void *arg)
tor_free(tst->s);
tst->s = tor_strdup("Hello\nWorld");
- lines = config_get_assigned_option(&test_fmt, tst, "s", 1);
+ lines = config_get_assigned_option(mgr, tst, "s", 1);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "s");
tt_str_op(lines->value, OP_EQ, "\"Hello\\nWorld\"");
@@ -766,8 +793,9 @@ test_confparse_get_assigned(void *arg)
config_free_lines(lines);
done:
- config_free(&test_fmt, tst);
+ config_free(mgr, tst);
config_free_lines(lines);
+ config_mgr_free(mgr);
}
/* Another variant, which accepts and stores unrecognized lines.*/
@@ -790,8 +818,9 @@ static config_format_t etest_fmt = {
test_deprecation_notes,
test_vars,
test_validate_cb,
- test_free_cb,
+ NULL,
&extra,
+ -1,
};
/* Try out the feature where we can store unrecognized lines and dump them
@@ -800,24 +829,26 @@ static void
test_confparse_extra_lines(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&etest_fmt);
+ config_mgr_t *mgr = config_mgr_new(&etest_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
config_line_t *lines = NULL;
char *msg = NULL, *dump = NULL;
- config_init(&etest_fmt, tst);
+ config_init(mgr, tst);
int r = config_get_lines(
"unknotty addita\n"
"pos 99\n"
"wombat knish\n", &lines, 0);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&etest_fmt, tst, lines, 0, &msg);
+ r = config_assign(mgr, tst, lines, 0, &msg);
tt_int_op(r, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
tt_assert(tst->extra_lines);
- dump = config_dump(&etest_fmt, NULL, tst, 1, 0);
+ dump = config_dump(mgr, NULL, tst, 1, 0);
tt_str_op(dump, OP_EQ,
"pos 99\n"
"unknotty addita\n"
@@ -827,7 +858,8 @@ test_confparse_extra_lines(void *arg)
tor_free(msg);
tor_free(dump);
config_free_lines(lines);
- config_free(&etest_fmt, tst);
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
}
static void
@@ -893,12 +925,106 @@ static void
test_confparse_check_ok_fail(void *arg)
{
(void)arg;
- test_struct_t *tst = config_new(&test_fmt);
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
tst->pos = -10;
- tt_assert(! config_check_ok(&test_fmt, tst, LOG_INFO));
+ tt_assert(! config_check_ok(mgr, tst, LOG_INFO));
+
+ done:
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_list_vars(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ smartlist_t *vars = config_mgr_list_vars(mgr);
+ smartlist_t *varnames = smartlist_new();
+ char *joined = NULL;
+
+ tt_assert(vars);
+ SMARTLIST_FOREACH(vars, config_var_t *, cv,
+ smartlist_add(varnames, (void*)cv->member.name));
+ smartlist_sort_strings(varnames);
+ joined = smartlist_join_strings(varnames, "::", 0, NULL);
+ tt_str_op(joined, OP_EQ,
+ "LineTypeA::"
+ "LineTypeB::"
+ "MixedHiddenLines::"
+ "MixedLines::"
+ "VisibleLineB::"
+ "__HiddenInt::"
+ "__HiddenLineA::"
+ "autobool::"
+ "boolean::"
+ "csv::"
+ "csv_interval::"
+ "dbl::"
+ "deprecated_int::"
+ "fn::"
+ "i::"
+ "interval::"
+ "lines::"
+ "mem::"
+ "msec_interval::"
+ "obsolete::"
+ "pos::"
+ "routerset::"
+ "s::"
+ "time::"
+ "u64");
+
+ done:
+ tor_free(joined);
+ smartlist_free(varnames);
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_list_deprecated(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ smartlist_t *vars = config_mgr_list_deprecated_vars(mgr);
+ char *joined = NULL;
+
+ tt_assert(vars);
+ smartlist_sort_strings(vars);
+ joined = smartlist_join_strings(vars, "::", 0, NULL);
+
+ tt_str_op(joined, OP_EQ, "deprecated_int");
+
+ done:
+ tor_free(joined);
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_find_option_name(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+
+ // exact match
+ tt_str_op(config_find_option_name(mgr, "u64"), OP_EQ, "u64");
+ // case-insensitive match
+ tt_str_op(config_find_option_name(mgr, "S"), OP_EQ, "s");
+ tt_str_op(config_find_option_name(mgr, "linetypea"), OP_EQ, "LineTypeA");
+ // prefix match
+ tt_str_op(config_find_option_name(mgr, "deprec"), OP_EQ, "deprecated_int");
+ // explicit abbreviation
+ tt_str_op(config_find_option_name(mgr, "uint"), OP_EQ, "pos");
+ tt_str_op(config_find_option_name(mgr, "UINT"), OP_EQ, "pos");
+ // no match
+ tt_ptr_op(config_find_option_name(mgr, "absent"), OP_EQ, NULL);
done:
- config_free(&test_fmt, tst);
+ config_mgr_free(mgr);
}
#define CONFPARSE_TEST(name, flags) \
@@ -937,5 +1063,8 @@ struct testcase_t confparse_tests[] = {
CONFPARSE_TEST(extra_lines, 0),
CONFPARSE_TEST(unitparse, 0),
CONFPARSE_TEST(check_ok_fail, 0),
+ CONFPARSE_TEST(list_vars, 0),
+ CONFPARSE_TEST(list_deprecated, 0),
+ CONFPARSE_TEST(find_option_name, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index e57bd02584..edfd0c74e1 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -479,8 +479,7 @@ static or_options_t *mock_options = NULL;
static void
init_mock_options(void)
{
- mock_options = tor_malloc(sizeof(or_options_t));
- memset(mock_options, 0, sizeof(or_options_t));
+ mock_options = options_new();
mock_options->TestingTorNetwork = 1;
mock_options->DataDirectory = tor_strdup(get_fname_rnd("datadir_tmp"));
mock_options->CacheDirectory = tor_strdup(mock_options->DataDirectory);
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index c43b21c673..c8dd4b03ea 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -5,6 +5,7 @@
#define CIRCUITLIST_PRIVATE
#define CIRCUITBUILD_PRIVATE
+#define CONFIG_PRIVATE
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
@@ -201,7 +202,7 @@ big_fake_network_setup(const struct testcase_t *testcase)
smartlist_add(big_fake_net_nodes, n);
}
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
dummy_consensus = tor_malloc_zero(sizeof(networkstatus_t));
if (reasonably_future_consensus) {
/* Make the dummy consensus valid in 6 hours, and expiring in 7 hours. */
@@ -235,12 +236,12 @@ mock_randomize_time_no_randomization(time_t a, time_t b)
return a;
}
-static or_options_t mocked_options;
+static or_options_t *mocked_options;
static const or_options_t *
mock_get_options(void)
{
- return &mocked_options;
+ return mocked_options;
}
#define TEST_IPV4_ADDR "123.45.67.89"
@@ -259,7 +260,7 @@ test_node_preferred_orport(void *arg)
tor_addr_port_t ap;
/* Setup options */
- memset(&mocked_options, 0, sizeof(mocked_options));
+ mocked_options = options_new();
/* We don't test ClientPreferIPv6ORPort here, because it's used in
* nodelist_set_consensus to setup node.ipv6_preferred, which we set
* directly. */
@@ -282,8 +283,8 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv4 if we're only using IPv4, regardless
* of whether we prefer it or not */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 0;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 0;
node.ipv6_preferred = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
@@ -296,8 +297,8 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but
* don't prefer the IPv6 address */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 1;
node.ipv6_preferred = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
@@ -305,28 +306,29 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv6 if we prefer it and
* ClientUseIPv6 is 1, regardless of ClientUseIPv4 */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 1;
node.ipv6_preferred = 1;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
- mocked_options.ClientUseIPv4 = 0;
+ mocked_options->ClientUseIPv4 = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
/* Check the preferred address is IPv6 if we don't prefer it, but
* ClientUseIPv4 is 0 */
- mocked_options.ClientUseIPv4 = 0;
- mocked_options.ClientUseIPv6 = 1;
- node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options);
+ mocked_options->ClientUseIPv4 = 0;
+ mocked_options->ClientUseIPv6 = 1;
+ node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(mocked_options);
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
done:
+ or_options_free(mocked_options);
UNMOCK(get_options);
}
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index b4389f2d17..31a6540efc 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -295,7 +295,7 @@ helper_parse_options(const char *conf)
if (ret != 0) {
goto done;
}
- ret = config_assign(&options_format, opt, line, 0, &msg);
+ ret = config_assign(get_options_mgr(), opt, line, 0, &msg);
if (ret != 0) {
goto done;
}
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index c0803a5a59..c5854f0ff8 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1178,7 +1178,7 @@ test_introduce2(void *arg)
MOCK(get_or_state,
get_or_state_replacement);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_INTRO, flags);
tt_assert(circ);
@@ -1343,7 +1343,7 @@ test_rotate_descriptors(void *arg)
(void) arg;
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
hs_init();
MOCK(get_or_state, get_or_state_replacement);
@@ -1460,7 +1460,7 @@ test_build_update_descriptors(void *arg)
MOCK(networkstatus_get_live_consensus,
mock_networkstatus_get_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
&mock_ns.valid_after);
@@ -1691,7 +1691,7 @@ test_build_descriptors(void *arg)
MOCK(networkstatus_get_live_consensus,
mock_networkstatus_get_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
&mock_ns.valid_after);
@@ -1792,7 +1792,7 @@ test_upload_descriptors(void *arg)
MOCK(networkstatus_get_live_consensus,
mock_networkstatus_get_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
&mock_ns.valid_after);
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 53ee799185..ad211c7ea8 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -648,6 +648,41 @@ static const char MD_PARSE_TEST_DATA[] =
"ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
"id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
"p6 allow 80\n"
+ /* Good 11: Normal, non-exit relay with ipv6 address */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
+ /* Good 12: Normal, exit relay with ipv6 address */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
+ /* Good 13: Normal, exit relay with only ipv6 exit policy */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "p6 accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
;
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
ENABLE_GCC_WARNING(overlength-strings)
@@ -665,7 +700,7 @@ test_md_parse(void *arg)
smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA,
NULL, 1, SAVED_NOWHERE,
invalid);
- tt_int_op(smartlist_len(mds), OP_EQ, 11);
+ tt_int_op(smartlist_len(mds), OP_EQ, 14);
tt_int_op(smartlist_len(invalid), OP_EQ, 4);
test_memeq_hex(smartlist_get(invalid,0),
@@ -712,6 +747,21 @@ test_md_parse(void *arg)
tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ md = smartlist_get(mds, 11);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 1);
+
+ md = smartlist_get(mds, 12);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
+
+ md = smartlist_get(mds, 13);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
+
done:
SMARTLIST_FOREACH(mds, microdesc_t *, mdsc, microdesc_free(mdsc));
smartlist_free(mds);
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 64fcd011e7..a6bccdc524 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -96,7 +96,7 @@ clear_log_messages(void)
opt->command = CMD_RUN_TOR; \
options_init(opt); \
\
- dflt = config_dup(&options_format, opt); \
+ dflt = config_dup(get_options_mgr(), opt); \
clear_log_messages(); \
} while (0)
@@ -196,7 +196,7 @@ test_options_validate_impl(const char *configuration,
if (r)
goto done;
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
if (phase == PH_ASSIGN) {
if (test_options_checkmsgs(configuration, expect_errmsg,
expect_log_severity,
@@ -304,7 +304,7 @@ test_have_enough_mem_for_dircache(void *arg)
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled */
@@ -327,7 +327,7 @@ test_have_enough_mem_for_dircache(void *arg)
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled, Bridge */
@@ -350,7 +350,7 @@ test_have_enough_mem_for_dircache(void *arg)
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 200 MB RAM available, DirCache disabled */
@@ -438,7 +438,7 @@ get_options_test_data(const char *conf)
rv = config_get_lines(conf, &cl, 1);
tt_int_op(rv, OP_EQ, 0);
- rv = config_assign(&options_format, result->opt, cl, 0, &msg);
+ rv = config_assign(get_options_mgr(), result->opt, cl, 0, &msg);
if (msg) {
/* Display the parse error message by comparing it with an empty string */
tt_str_op(msg, OP_EQ, "");
@@ -449,7 +449,7 @@ get_options_test_data(const char *conf)
result->opt->TokenBucketRefillInterval = 1;
rv = config_get_lines(TEST_OPTIONS_OLD_VALUES, &cl, 1);
tt_int_op(rv, OP_EQ, 0);
- rv = config_assign(&options_format, result->def_opt, cl, 0, &msg);
+ rv = config_assign(get_options_mgr(), result->def_opt, cl, 0, &msg);
if (msg) {
/* Display the parse error message by comparing it with an empty string */
tt_str_op(msg, OP_EQ, "");
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 87e3ba356c..362c6664db 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -352,7 +352,7 @@ test_pt_configure_proxy(void *arg)
managed_proxy_t *mp = NULL;
(void) arg;
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
MOCK(process_read_stdout, process_read_stdout_replacement);
MOCK(get_or_state,