diff options
author | Tobias Brunner <tobias@strongswan.org> | 2014-01-28 15:20:27 +0100 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2014-02-12 14:34:32 +0100 |
commit | 1713d88278597f79df799cf24fbec34c0b9a1a02 (patch) | |
tree | 727f530b5e44b6d144b13e99b5c0e4c6aa7e7bad /src | |
parent | ef72d4cc3f887f4b1dc1d84304c22564db102a48 (diff) | |
download | strongswan-1713d88278597f79df799cf24fbec34c0b9a1a02.tar.bz2 strongswan-1713d88278597f79df799cf24fbec34c0b9a1a02.tar.xz |
settings: Add method that allows to define fallback sections for other sections
The fallbacks are currently only used for single value lookups.
Enumerators are not affected by them.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/tests/suites/test_settings.c | 109 | ||||
-rw-r--r-- | src/libstrongswan/utils/settings.c | 154 | ||||
-rw-r--r-- | src/libstrongswan/utils/settings.h | 26 |
3 files changed, 276 insertions, 13 deletions
diff --git a/src/libstrongswan/tests/suites/test_settings.c b/src/libstrongswan/tests/suites/test_settings.c index 72ee94e86..0172d5265 100644 --- a/src/libstrongswan/tests/suites/test_settings.c +++ b/src/libstrongswan/tests/suites/test_settings.c @@ -664,6 +664,109 @@ START_TEST(test_load_files_section) } END_TEST +START_SETUP(setup_fallback_config) +{ + create_settings(chunk_from_str( + "main {\n" + " key1 = val1\n" + " sub1 {\n" + " key1 = val1\n" + " }\n" + "}\n" + "sub {\n" + " key1 = subval1\n" + " key2 = subval2\n" + " subsub {\n" + " subkey1 = subsubval1\n" + " }\n" + "}\n" + "base {\n" + " key1 = baseval1\n" + " key2 = baseval2\n" + " sub1 {\n" + " key1 = subbase1\n" + " key2 = subbase2\n" + " key3 = subbase3\n" + " subsub {\n" + " subkey1 = subsubbaseval1\n" + " subkey2 = subsubbaseval2\n" + " }\n" + " }\n" + " sub2 {\n" + " key4 = subbase4\n" + " }\n" + "}")); +} +END_SETUP + +START_TEST(test_add_fallback) +{ + linked_list_t *keys, *values; + + settings->add_fallback(settings, "main.sub1", "sub"); + verify_string("val1", "main.sub1.key1"); + verify_string("subval2", "main.sub1.key2"); + verify_string("subsubval1", "main.sub1.subsub.subkey1"); + + /* fallbacks are preserved even if the complete config is replaced */ + settings->load_files(settings, path, FALSE); + verify_string("val1", "main.sub1.key1"); + verify_string("subval2", "main.sub1.key2"); + verify_string("subsubval1", "main.sub1.subsub.subkey1"); + + /* fallbacks currently have no effect on section & key/value enumerators */ + keys = linked_list_create_with_items(NULL); + verify_sections(keys, "main.sub1"); + + keys = linked_list_create_with_items("key1", NULL); + values = linked_list_create_with_items("val1", NULL); + verify_key_values(keys, values, "main.sub1"); + + settings->add_fallback(settings, "main", "base"); + verify_string("val1", "main.key1"); + verify_string("baseval2", "main.key2"); + verify_string("val1", "main.sub1.key1"); + verify_string("subval2", "main.sub1.key2"); + verify_string("subsubval1", "main.sub1.subsub.subkey1"); + verify_string("subsubbaseval2", "main.sub1.subsub.subkey2"); + verify_string("subbase3", "main.sub1.key3"); + verify_string("subbase4", "main.sub2.key4"); + + keys = linked_list_create_with_items(NULL); + verify_sections(keys, "main.sub1"); + keys = linked_list_create_with_items("sub1", NULL); + verify_sections(keys, "main"); + + keys = linked_list_create_with_items("key1", NULL); + values = linked_list_create_with_items("val1", NULL); + verify_key_values(keys, values, "main.sub1"); + + keys = linked_list_create_with_items("key1", NULL); + values = linked_list_create_with_items("val1", NULL); + verify_key_values(keys, values, "main"); + + settings->set_str(settings, "main.sub1.key2", "val2"); + verify_string("val2", "main.sub1.key2"); + settings->set_str(settings, "main.sub1.subsub.subkey2", "val2"); + verify_string("val2", "main.sub1.subsub.subkey2"); + verify_string("subsubval1", "main.sub1.subsub.subkey1"); +} +END_TEST + +START_TEST(test_add_fallback_printf) +{ + settings->add_fallback(settings, "%s.sub1", "sub", "main"); + verify_string("val1", "main.sub1.key1"); + verify_string("subval2", "main.sub1.key2"); + verify_string("subsubval1", "main.sub1.subsub.subkey1"); + + settings->add_fallback(settings, "%s.%s2", "%s.%s1", "main", "sub"); + verify_string("val1", "main.sub2.key1"); + verify_string("subval2", "main.sub2.key2"); + verify_string("subsubval1", "main.sub2.subsub.subkey1"); +} +END_TEST + Suite *settings_suite_create() { Suite *s; @@ -721,5 +824,11 @@ Suite *settings_suite_create() tcase_add_test(tc, test_load_files_section); suite_add_tcase(s, tc); + tc = tcase_create("fallback"); + tcase_add_checked_fixture(tc, setup_fallback_config, teardown_config); + tcase_add_test(tc, test_add_fallback); + tcase_add_test(tc, test_add_fallback_printf); + suite_add_tcase(s, tc); + return s; } diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c index c3ab52a0e..2727495f0 100644 --- a/src/libstrongswan/utils/settings.c +++ b/src/libstrongswan/utils/settings.c @@ -31,6 +31,7 @@ #include "settings.h" +#include "collections/array.h" #include "collections/linked_list.h" #include "threading/rwlock.h" #include "utils/debug.h" @@ -78,6 +79,11 @@ struct section_t { char *name; /** + * fallback sections, as section_t + */ + array_t *fallbacks; + + /** * subsections, as section_t */ linked_list_t *sections; @@ -147,19 +153,45 @@ static void section_destroy(section_t *this) { this->kv->destroy_function(this->kv, (void*)kv_destroy); this->sections->destroy_function(this->sections, (void*)section_destroy); + array_destroy(this->fallbacks); free(this->name); free(this); } +/* + * forward declaration + */ +static bool section_purge(section_t *this); + +/** + * Check if it is safe to remove the given section. + */ +static bool section_remove(section_t *this) +{ + if (section_purge(this)) + { + return FALSE; + } + section_destroy(this); + return TRUE; +} + /** - * Purge contents of a section + * Purge contents of a section, returns TRUE if section has to be kept due to + * any subsections. */ -static void section_purge(section_t *this) +static bool section_purge(section_t *this) { + int count, removed; + this->kv->destroy_function(this->kv, (void*)kv_destroy); this->kv = linked_list_create(); - this->sections->destroy_function(this->sections, (void*)section_destroy); - this->sections = linked_list_create(); + /* we ensure sections used as fallback, or configured with fallbacks (or + * having any such subsections) are not removed */ + count = this->sections->get_count(this->sections); + removed = this->sections->remove(this->sections, NULL, + (void*)section_remove); + return this->fallbacks || removed < count; } /** @@ -291,7 +323,7 @@ static section_t *find_section(private_settings_t *this, section_t *section, * Ensure that the section with the given key exists (thread-safe). */ static section_t *ensure_section(private_settings_t *this, section_t *section, - char *key, va_list args) + const char *key, va_list args) { char buf[128], keybuf[512]; section_t *found; @@ -309,13 +341,72 @@ static section_t *ensure_section(private_settings_t *this, section_t *section, } /** + * Check if the given fallback section already exists + */ +static bool fallback_exists(section_t *section, section_t *fallback) +{ + if (section == fallback) + { + return TRUE; + } + else if (section->fallbacks) + { + section_t *existing; + int i; + + for (i = 0; i < array_count(section->fallbacks); i++) + { + array_get(section->fallbacks, i, &existing); + if (existing == fallback) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Ensure that the section with the given key exists and add the given fallback + * section (thread-safe). + */ +static void add_fallback_to_section(private_settings_t *this, + section_t *section, const char *key, va_list args, + section_t *fallback) +{ + char buf[128], keybuf[512]; + section_t *found; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return; + } + this->lock->write_lock(this->lock); + found = find_section_buffered(section, keybuf, keybuf, args, buf, + sizeof(buf), TRUE); + if (!fallback_exists(found, fallback)) + { + /* to ensure sections referred to as fallback are not purged, we create + * the array there too */ + if (!fallback->fallbacks) + { + fallback->fallbacks = array_create(0, 0); + } + array_insert_create(&found->fallbacks, ARRAY_TAIL, fallback); + } + this->lock->unlock(this->lock); +} + +/** * Find the key/value pair for a key, using buffered key, reusable buffer * If "ensure" is TRUE, the sections (and key/value pair) are created if they * don't exist. + * Fallbacks are only considered if "ensure" is FALSE. */ static kv_t *find_value_buffered(section_t *section, char *start, char *key, va_list args, char *buf, int len, bool ensure) { + int i; char *pos; kv_t *kv = NULL; section_t *found = NULL; @@ -329,12 +420,12 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key, if (pos) { *pos = '\0'; - pos++; - if (!print_key(buf, len, start, key, args)) { return NULL; } + /* restore so we can retry for fallbacks */ + *pos = '.'; if (!strlen(buf)) { found = section; @@ -343,15 +434,26 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key, (linked_list_match_t)section_find, (void**)&found, buf) != SUCCESS) { - if (!ensure) + if (ensure) { - return NULL; + found = section_create(buf); + section->sections->insert_last(section->sections, found); + } + } + if (found) + { + kv = find_value_buffered(found, start, pos+1, args, buf, len, + ensure); + } + if (!kv && !ensure && section->fallbacks) + { + for (i = 0; !kv && i < array_count(section->fallbacks); i++) + { + array_get(section->fallbacks, i, &found); + kv = find_value_buffered(found, start, key, args, buf, len, + ensure); } - found = section_create(buf); - section->sections->insert_last(section->sections, found); } - return find_value_buffered(found, start, pos, args, buf, len, - ensure); } else { @@ -367,6 +469,15 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key, kv = kv_create(buf, NULL); section->kv->insert_last(section->kv, kv); } + else if (section->fallbacks) + { + for (i = 0; !kv && i < array_count(section->fallbacks); i++) + { + array_get(section->fallbacks, i, &found); + kv = find_value_buffered(found, start, key, args, buf, len, + ensure); + } + } } } return kv; @@ -727,6 +838,22 @@ METHOD(settings_t, create_key_value_enumerator, enumerator_t*, (void*)kv_filter, this->lock, (void*)this->lock->unlock); } +METHOD(settings_t, add_fallback, void, + private_settings_t *this, const char *key, const char *fallback, ...) +{ + section_t *section; + va_list args; + + /* find/create the fallback */ + va_start(args, fallback); + section = ensure_section(this, this->top, fallback, args); + va_end(args); + + va_start(args, fallback); + add_fallback_to_section(this, this->top, key, args, section); + va_end(args); +} + /** * parse text, truncate "skip" chars, delimited by term respecting brackets. * @@ -1235,6 +1362,7 @@ settings_t *settings_create(char *file) .set_default_str = _set_default_str, .create_section_enumerator = _create_section_enumerator, .create_key_value_enumerator = _create_key_value_enumerator, + .add_fallback = _add_fallback, .load_files = _load_files, .load_files_section = _load_files_section, .destroy = _destroy, diff --git a/src/libstrongswan/utils/settings.h b/src/libstrongswan/utils/settings.h index df0c534e9..6154ad8b9 100644 --- a/src/libstrongswan/utils/settings.h +++ b/src/libstrongswan/utils/settings.h @@ -269,6 +269,32 @@ struct settings_t { char *section, ...); /** + * Add a fallback for the given section. + * + * Example: When the fallback 'section-two' is configured for + * 'section-one.two' any failed lookup for a section or key in + * 'section-one.two' will result in a lookup for the same section/key + * in 'section-two'. + * + * @note This has only an effect on single value lookups. Enumerators for + * sections and key/value-pairs are not affected. The reason is that it is + * rather tricky to implement such a merge without requiring allocations for + * each lookup. For instance, if charon.tls has libtls as fallback and + * charon has libstrongswan as fallback, the key/value-enumerator for + * charon.tls had to enumerate the libtls and libstrongswan.tls sections + * too, but it would have to keep track of the already enumerated keys. + * + * @note Additional arguments will be applied to both section format + * strings so they must be compatible. + * + * @param section section for which a fallback is configured, printf style + * @param fallback fallback section, printf style + * @param ... argument list for section and fallback + */ + void (*add_fallback)(settings_t *this, const char *section, + const char *fallback, ...); + + /** * Load settings from the files matching the given pattern. * * If merge is TRUE, existing sections are extended, existing values |