]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
metadata-set: Add implementation for a collection of metadata objects
authorTobias Brunner <tobias@strongswan.org>
Thu, 2 Dec 2021 10:25:34 +0000 (11:25 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 14 Jan 2022 09:13:21 +0000 (10:13 +0100)
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/metadata/metadata_set.c [new file with mode: 0644]
src/libstrongswan/metadata/metadata_set.h [new file with mode: 0644]
src/libstrongswan/tests/Makefile.am
src/libstrongswan/tests/suites/test_metadata_set.c [new file with mode: 0644]
src/libstrongswan/tests/tests.h

index be263efbecf321771294878ad2ae734de40a1557..660382da2ea6928316f6b9e9c3d6a81e69315ae7 100644 (file)
@@ -33,7 +33,7 @@ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
 credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \
 database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \
 ipsec/ipsec_types.c \
-metadata/metadata_factory.c metadata/metadata_int.c \
+metadata/metadata_factory.c metadata/metadata_int.c metadata/metadata_set.c \
 networking/host.c networking/host_resolver.c networking/packet.c \
 networking/tun_device.c networking/streams/stream_manager.c \
 networking/streams/stream.c networking/streams/stream_service.c \
index ca3f1e1da51b2ce025a2355d3698828394d8efbb..a125672919bddba3f965eb7fb7acbf4655807932 100644 (file)
@@ -31,7 +31,7 @@ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
 credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \
 database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \
 ipsec/ipsec_types.c \
-metadata/metadata_factory.c metadata/metadata_int.c \
+metadata/metadata_factory.c metadata/metadata_int.c metadata/metadata_set.c \
 networking/host.c networking/host_resolver.c networking/packet.c \
 networking/tun_device.c networking/streams/stream_manager.c \
 networking/streams/stream.c networking/streams/stream_service.c \
@@ -101,6 +101,7 @@ credentials/auth_cfg.h credentials/credential_set.h credentials/cert_validator.h
 database/database.h database/database_factory.h fetcher/fetcher.h \
 fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \
 metadata/metadata.h metadata/metadata_factory.h metadata/metadata_int.h \
+metadata/metadata_set.h \
 networking/host.h networking/host_resolver.h networking/packet.h \
 networking/tun_device.h networking/streams/stream.h \
 networking/streams/stream_unix.h networking/streams/stream_service_unix.h \
diff --git a/src/libstrongswan/metadata/metadata_set.c b/src/libstrongswan/metadata/metadata_set.c
new file mode 100644 (file)
index 0000000..f821e57
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "metadata_set.h"
+
+#include <collections/array.h>
+
+/**
+ * Set of metadata objects, indexed via string.
+ */
+struct metadata_set_t {
+       /** Stored metadata objects (entry_t) */
+       array_t *entries;
+};
+
+/**
+ * Stored data for each metadata object.
+ */
+typedef struct {
+       /** Key of the entry */
+       const char *key;
+       /** Stored metadata object */
+       metadata_t *data;
+} entry_t;
+
+/**
+ * Destroy the given entry.
+ */
+static void destroy_entry(entry_t *entry)
+{
+       entry->data->destroy(entry->data);
+       free((char*)entry->key);
+       free(entry);
+}
+
+/**
+ * Sort entries by key
+ */
+static int entry_sort(const void *a, const void *b, void *user)
+{
+       const entry_t *ea = a, *eb = b;
+       return strcmp(ea->key, eb->key);
+}
+
+/**
+ * Find an entry by key
+ */
+static int entry_find(const void *a, const void *b)
+{
+       return entry_sort(a, b, NULL);
+}
+
+/*
+ * Described in header
+ */
+metadata_set_t *metadata_set_create()
+{
+       metadata_set_t *set;
+
+       INIT(set);
+
+       return set;
+}
+
+/*
+ * Described in header
+ */
+void metadata_set_put(metadata_set_t *set, const char *key, metadata_t *data)
+{
+       entry_t *entry = NULL, lookup = {
+               .key = key,
+       };
+       int idx;
+
+       if (!set)
+       {
+               DESTROY_IF(data);
+               return;
+       }
+
+       idx = array_bsearch(set->entries, &lookup, entry_find, &entry);
+       if (idx != -1)
+       {
+               if (data)
+               {
+                       entry->data->destroy(entry->data);
+                       entry->data = data;
+               }
+               else
+               {
+                       array_remove(set->entries, idx, NULL);
+                       destroy_entry(entry);
+               }
+       }
+       else if (data)
+       {
+               INIT(entry,
+                       .key = strdup(key),
+                       .data = data,
+               );
+               array_insert_create(&set->entries, ARRAY_TAIL, entry);
+               array_sort(set->entries, entry_sort, NULL);
+       }
+}
+
+/*
+ * Described in header
+ */
+metadata_t *metadata_set_get(metadata_set_t *set, const char *key)
+{
+       entry_t *entry = NULL, lookup = {
+               .key = key,
+       };
+
+       if (set && array_bsearch(set->entries, &lookup, entry_find, &entry) != -1)
+       {
+               return entry->data;
+       }
+       return NULL;
+}
+
+/*
+ * Described in header
+ */
+metadata_set_t *metadata_set_clone(metadata_set_t *set)
+{
+       metadata_set_t *clone;
+       entry_t *entry, *entry_clone;
+       int i;
+
+       if (!set)
+       {
+               return NULL;
+       }
+
+       INIT(clone,
+               .entries = array_create(0, array_count(set->entries)),
+       );
+       for (i = 0; i < array_count(set->entries); i++)
+       {
+               array_get(set->entries, i, &entry);
+               INIT(entry_clone,
+                       .key = strdup(entry->key),
+                       .data = entry->data->clone(entry->data),
+               );
+               array_insert(clone->entries, i, entry_clone);
+       }
+       return clone;
+}
+
+/*
+ * Described in header
+ */
+void metadata_set_destroy(metadata_set_t *set)
+{
+       if (set)
+       {
+               array_destroy_function(set->entries, (void*)destroy_entry, NULL);
+               free(set);
+       }
+}
diff --git a/src/libstrongswan/metadata/metadata_set.h b/src/libstrongswan/metadata/metadata_set.h
new file mode 100644 (file)
index 0000000..38ab51d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup metadata_set metadata_set
+ * @{ @ingroup metadata
+ */
+
+#ifndef METADATA_SET_H_
+#define METADATA_SET_H_
+
+#include "metadata.h"
+
+/**
+ * Set of metadata objects, indexed via string.
+ */
+typedef struct metadata_set_t metadata_set_t;
+
+/**
+ * Create a metadata_set_t instance.
+ */
+metadata_set_t *metadata_set_create();
+
+/**
+ * Add a metadata object with the given key to the set, replacing any previous
+ * object with the same key.
+ *
+ * @param set                  set to add metadata to
+ * @param key                  key under which to store metadata (cloned)
+ * @param data                 metadata object (adopted), NULL to remove/destroy
+ *                                             existing object
+ */
+void metadata_set_put(metadata_set_t *set, const char *key, metadata_t *data);
+
+/**
+ * Retrieve the metadata object with the given key.
+ *
+ * @param set                  set to query
+ * @param key                  key of the metadata object
+ * @return                             metadata object, NULL if not found
+ */
+metadata_t *metadata_set_get(metadata_set_t *set, const char *key);
+
+/**
+ * Clone a complete metadata set.
+ *
+ * @param set                  set to clone
+ * @return                             cloned set
+ */
+metadata_set_t *metadata_set_clone(metadata_set_t *set);
+
+/**
+ * Destroy a metadata set, destroying all contained metadata objects.
+ *
+ * @param set                  set to destroy
+ */
+void metadata_set_destroy(metadata_set_t *set);
+
+#endif /** METADATA_SET_H_ @}*/
index 37ea1077210dd2a126f62d6c723078187dd5f945..eb96396762d7ec48a934d7f8fce7d3267d3a7d94 100644 (file)
@@ -66,7 +66,8 @@ libstrongswan_tests_SOURCES = tests.h tests.c \
   suites/test_ed25519.c \
   suites/test_ed448.c \
   suites/test_signature_params.c \
-  suites/test_metadata.c
+  suites/test_metadata.c \
+  suites/test_metadata_set.c
 
 libstrongswan_tests_CFLAGS = \
   -I$(top_srcdir)/src/libstrongswan \
diff --git a/src/libstrongswan/tests/suites/test_metadata_set.c b/src/libstrongswan/tests/suites/test_metadata_set.c
new file mode 100644 (file)
index 0000000..0a307c4
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2021 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "test_suite.h"
+
+#include <metadata/metadata_set.h>
+
+START_TEST(test_destroy_null)
+{
+       metadata_set_t *set = NULL;
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_destroy_empty)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_put_null)
+{
+       metadata_set_t *set = NULL;
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       metadata_set_put(set, "other", NULL);
+}
+END_TEST
+
+START_TEST(test_put)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_get_null)
+{
+       metadata_set_t *set = NULL;
+       metadata_t *metadata;
+
+       metadata = metadata_set_get(set, "key");
+       ck_assert(!metadata);
+}
+END_TEST
+
+/**
+ * Assert that the given int metadata value is found with the given key.
+ */
+static void assert_int_value(metadata_set_t *set, const char *key, int expected)
+{
+       metadata_t *metadata;
+       int value;
+
+       metadata = metadata_set_get(set, key);
+       ck_assert(metadata);
+       metadata->get(metadata, &value);
+       ck_assert_int_eq(expected, value);
+}
+
+START_TEST(test_get)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       assert_int_value(set, "key", 42);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_get_missing)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = metadata_set_get(set, "key");
+       ck_assert(!metadata);
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "other", metadata);
+       metadata = metadata_set_get(set, "key");
+       ck_assert(!metadata);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_get_multi)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       metadata = lib->metadata->create(lib->metadata, "int", 0);
+       metadata_set_put(set, "other", metadata);
+       assert_int_value(set, "key", 42);
+       assert_int_value(set, "other", 0);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_put_replace)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "whatever", metadata);
+       metadata = lib->metadata->create(lib->metadata, "int", 0);
+       metadata_set_put(set, "other", metadata);
+       metadata = lib->metadata->create(lib->metadata, "int", 666);
+       metadata_set_put(set, "other", metadata);
+       assert_int_value(set, "whatever", 42);
+       assert_int_value(set, "other", 666);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_put_remove)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       metadata = lib->metadata->create(lib->metadata, "int", 0);
+       metadata_set_put(set, "other", metadata);
+       metadata_set_put(set, "other", NULL);
+       assert_int_value(set, "key", 42);
+       metadata = metadata_set_get(set, "other");
+       ck_assert(!metadata);
+       metadata_set_put(set, "key", NULL);
+       metadata = metadata_set_get(set, "key");
+       ck_assert(!metadata);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_put_remove_missing)
+{
+       metadata_set_t *set = metadata_set_create();
+       metadata_t *metadata;
+
+       metadata_set_put(set, "key", NULL);
+       metadata = lib->metadata->create(lib->metadata, "int", 42);
+       metadata_set_put(set, "key", metadata);
+       assert_int_value(set, "key", 42);
+       metadata_set_put(set, "key", NULL);
+       metadata = metadata_set_get(set, "key");
+       ck_assert(!metadata);
+       metadata_set_put(set, "key", NULL);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_clone_null)
+{
+       metadata_set_t *set = NULL, *clone;
+
+       clone = metadata_set_clone(set);
+       ck_assert(!clone);
+}
+END_TEST
+
+START_TEST(test_clone_empty)
+{
+       metadata_set_t *set = metadata_set_create(), *clone;
+
+       clone = metadata_set_clone(set);
+       ck_assert(clone != set);
+
+       metadata_set_destroy(clone);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+START_TEST(test_clone)
+{
+       metadata_set_t *set = metadata_set_create(), *clone;
+       metadata_t *metadata;
+       struct {
+               const char *key;
+               int value;
+       }  expected[] = {
+               { "key", 42, },
+               { "other", 666, },
+               { "abc", 4500, },
+       };
+       int i;
+
+       for (i = 0; i < countof(expected); i++)
+       {
+               metadata = lib->metadata->create(lib->metadata, "int", expected[i].value);
+               metadata_set_put(set, expected[i].key, metadata);
+       }
+
+       clone = metadata_set_clone(set);
+       ck_assert(clone != set);
+
+       for (i = 0; i < countof(expected); i++)
+       {
+               assert_int_value(set, expected[i].key, expected[i].value);
+               assert_int_value(clone, expected[i].key, expected[i].value);
+       }
+
+       metadata_set_put(set, expected[0].key, NULL);
+       assert_int_value(clone, expected[0].key, expected[0].value);
+
+       metadata_set_destroy(clone);
+       metadata_set_destroy(set);
+}
+END_TEST
+
+Suite *metadata_set_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("metadata_set");
+
+       tc = tcase_create("create/destroy");
+       tcase_add_test(tc, test_destroy_null);
+       tcase_add_test(tc, test_destroy_empty);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("put/get");
+       tcase_add_test(tc, test_put_null);
+       tcase_add_test(tc, test_put);
+       tcase_add_test(tc, test_get_null);
+       tcase_add_test(tc, test_get);
+       tcase_add_test(tc, test_get_missing);
+       tcase_add_test(tc, test_get_multi);
+       tcase_add_test(tc, test_put_replace);
+       tcase_add_test(tc, test_put_remove);
+       tcase_add_test(tc, test_put_remove_missing);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("clone");
+       tcase_add_test(tc, test_clone_null);
+       tcase_add_test(tc, test_clone_empty);
+       tcase_add_test(tc, test_clone);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
index 7ff66d76bf6be43095a026b2db57cd6619442f2f..fc685d1930397d07773ed3357d6b73de41354c1f 100644 (file)
@@ -62,3 +62,4 @@ TEST_SUITE_DEPEND(ed25519_suite_create, PRIVKEY_GEN, KEY_ED25519)
 TEST_SUITE_DEPEND(ed448_suite_create, PRIVKEY_GEN, KEY_ED448)
 TEST_SUITE(signature_params_suite_create)
 TEST_SUITE(metadata_suite_create)
+TEST_SUITE(metadata_set_suite_create)