From: Christian Grothoff Date: Sat, 29 Jun 2019 08:18:44 +0000 (+0200) Subject: use mmap() instead of malloc, rename heap->flat as database is persisted in flat... X-Git-Tag: v0.11.6~58 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=e96e9584f2ca6797552fc46bb83e3d10827fad49;p=oweals%2Fgnunet.git use mmap() instead of malloc, rename heap->flat as database is persisted in flat file --- diff --git a/src/namestore/.gitignore b/src/namestore/.gitignore index 5a59afd24..f159cdaff 100644 --- a/src/namestore/.gitignore +++ b/src/namestore/.gitignore @@ -68,21 +68,21 @@ test_namestore_api_zone_iteration_stop_sqlite test_namestore_api_zone_to_name_flat test_namestore_api_zone_to_name_postgres test_namestore_api_zone_to_name_sqlite -test_namestore_api_lookup_nick_heap -test_namestore_api_lookup_private_heap -test_namestore_api_lookup_public_heap -test_namestore_api_lookup_shadow_filter_heap -test_namestore_api_lookup_shadow_heap -test_namestore_api_monitoring_existing_heap -test_namestore_api_monitoring_heap -test_namestore_api_remove_heap -test_namestore_api_remove_not_existing_record_heap -test_namestore_api_store_heap -test_namestore_api_store_update_heap -test_namestore_api_zone_iteration_heap -test_namestore_api_zone_iteration_nick_heap -test_namestore_api_zone_iteration_specific_zone_heap -test_namestore_api_zone_iteration_stop_heap -test_namestore_api_zone_to_name_heap -test_plugin_namestore_heap -perf_namestore_api_zone_iteration_heap +test_namestore_api_lookup_nick_flat +test_namestore_api_lookup_private_flat +test_namestore_api_lookup_public_flat +test_namestore_api_lookup_shadow_filter_flat +test_namestore_api_lookup_shadow_flat +test_namestore_api_monitoring_existing_flat +test_namestore_api_monitoring_flat +test_namestore_api_remove_flat +test_namestore_api_remove_not_existing_record_flat +test_namestore_api_store_flat +test_namestore_api_store_update_flat +test_namestore_api_zone_iteration_flat +test_namestore_api_zone_iteration_nick_flat +test_namestore_api_zone_iteration_specific_zone_flat +test_namestore_api_zone_iteration_stop_flat +test_namestore_api_zone_to_name_flat +test_plugin_namestore_flat +perf_namestore_api_zone_iteration_flat diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am index 25941b4fb..e95add6c7 100644 --- a/src/namestore/Makefile.am +++ b/src/namestore/Makefile.am @@ -20,26 +20,26 @@ if USE_COVERAGE XLIBS = -lgcov endif -HEAP_PLUGIN = libgnunet_plugin_namestore_heap.la +HEAP_PLUGIN = libgnunet_plugin_namestore_flat.la if HAVE_TESTING -HEAP_TESTS = test_plugin_namestore_heap \ - test_namestore_api_store_heap \ - test_namestore_api_store_update_heap \ - test_namestore_api_remove_heap \ - test_namestore_api_zone_iteration_heap \ - test_namestore_api_lookup_nick_heap \ - test_namestore_api_monitoring_heap \ - test_namestore_api_lookup_public_heap \ - test_namestore_api_lookup_private_heap \ - test_namestore_api_lookup_shadow_heap \ - test_namestore_api_lookup_shadow_filter_heap \ - test_namestore_api_remove_not_existing_record_heap \ - test_namestore_api_zone_iteration_nick_heap \ - test_namestore_api_zone_iteration_specific_zone_heap \ - test_namestore_api_zone_iteration_stop_heap \ - test_namestore_api_monitoring_existing_heap \ - test_namestore_api_zone_to_name_heap \ - perf_namestore_api_zone_iteration_heap +HEAP_TESTS = test_plugin_namestore_flat \ + test_namestore_api_store_flat \ + test_namestore_api_store_update_flat \ + test_namestore_api_remove_flat \ + test_namestore_api_zone_iteration_flat \ + test_namestore_api_lookup_nick_flat \ + test_namestore_api_monitoring_flat \ + test_namestore_api_lookup_public_flat \ + test_namestore_api_lookup_private_flat \ + test_namestore_api_lookup_shadow_flat \ + test_namestore_api_lookup_shadow_filter_flat \ + test_namestore_api_remove_not_existing_record_flat \ + test_namestore_api_zone_iteration_nick_flat \ + test_namestore_api_zone_iteration_specific_zone_flat \ + test_namestore_api_zone_iteration_stop_flat \ + test_namestore_api_monitoring_existing_flat \ + test_namestore_api_zone_to_name_flat \ + perf_namestore_api_zone_iteration_flat endif if HAVE_SQLITE @@ -206,14 +206,14 @@ gnunet_service_namestore_LDADD = \ -libgnunet_plugin_namestore_heap_la_SOURCES = \ - plugin_namestore_heap.c -libgnunet_plugin_namestore_heap_la_LIBADD = \ +libgnunet_plugin_namestore_flat_la_SOURCES = \ + plugin_namestore_flat.c +libgnunet_plugin_namestore_flat_la_LIBADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ $(LTLIBINTL) -libgnunet_plugin_namestore_heap_la_LDFLAGS = \ +libgnunet_plugin_namestore_flat_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) @@ -239,9 +239,9 @@ libgnunet_plugin_namestore_postgres_la_LIBADD = \ libgnunet_plugin_namestore_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) -test_namestore_api_store_heap_SOURCES = \ +test_namestore_api_store_flat_SOURCES = \ test_namestore_api_store.c -test_namestore_api_store_heap_LDADD = \ +test_namestore_api_store_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -263,9 +263,9 @@ test_namestore_api_store_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_store_update_heap_SOURCES = \ +test_namestore_api_store_update_flat_SOURCES = \ test_namestore_api_store_update.c -test_namestore_api_store_update_heap_LDADD = \ +test_namestore_api_store_update_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -290,9 +290,9 @@ test_namestore_api_store_update_postgres_LDADD = \ $(top_builddir)/src/namecache/libgnunetnamecache.la \ libgnunetnamestore.la -test_namestore_api_lookup_public_heap_SOURCES = \ +test_namestore_api_lookup_public_flat_SOURCES = \ test_namestore_api_lookup_public.c -test_namestore_api_lookup_public_heap_LDADD = \ +test_namestore_api_lookup_public_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -335,18 +335,18 @@ test_namestore_api_lookup_nick_postgres_LDADD = \ $(top_builddir)/src/namecache/libgnunetnamecache.la \ libgnunetnamestore.la -test_namestore_api_lookup_nick_heap_SOURCES = \ +test_namestore_api_lookup_nick_flat_SOURCES = \ test_namestore_api_lookup_nick.c -test_namestore_api_lookup_nick_heap_LDADD = \ +test_namestore_api_lookup_nick_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ $(top_builddir)/src/namecache/libgnunetnamecache.la \ libgnunetnamestore.la -test_namestore_api_lookup_private_heap_SOURCES = \ +test_namestore_api_lookup_private_flat_SOURCES = \ test_namestore_api_lookup_private.c -test_namestore_api_lookup_private_heap_LDADD = \ +test_namestore_api_lookup_private_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -371,9 +371,9 @@ test_namestore_api_lookup_private_postgres_LDADD = \ $(top_builddir)/src/namecache/libgnunetnamecache.la \ libgnunetnamestore.la -test_namestore_api_lookup_shadow_heap_SOURCES = \ +test_namestore_api_lookup_shadow_flat_SOURCES = \ test_namestore_api_lookup_shadow.c -test_namestore_api_lookup_shadow_heap_LDADD = \ +test_namestore_api_lookup_shadow_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -398,9 +398,9 @@ test_namestore_api_lookup_shadow_postgres_LDADD = \ $(top_builddir)/src/namecache/libgnunetnamecache.la \ libgnunetnamestore.la -test_namestore_api_lookup_shadow_filter_heap_SOURCES = \ +test_namestore_api_lookup_shadow_filter_flat_SOURCES = \ test_namestore_api_lookup_shadow_filter.c -test_namestore_api_lookup_shadow_filter_heap_LDADD = \ +test_namestore_api_lookup_shadow_filter_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -440,17 +440,17 @@ test_namestore_api_remove_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_remove_heap_SOURCES = \ +test_namestore_api_remove_flat_SOURCES = \ test_namestore_api_remove.c -test_namestore_api_remove_heap_LDADD = \ +test_namestore_api_remove_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_remove_not_existing_record_heap_SOURCES = \ +test_namestore_api_remove_not_existing_record_flat_SOURCES = \ test_namestore_api_remove_not_existing_record.c -test_namestore_api_remove_not_existing_record_heap_LDADD = \ +test_namestore_api_remove_not_existing_record_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -472,9 +472,9 @@ test_namestore_api_remove_not_existing_record_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_zone_to_name_heap_SOURCES = \ +test_namestore_api_zone_to_name_flat_SOURCES = \ test_namestore_api_zone_to_name.c -test_namestore_api_zone_to_name_heap_LDADD = \ +test_namestore_api_zone_to_name_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la @@ -493,9 +493,9 @@ test_namestore_api_zone_to_name_postgres_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la -test_namestore_api_monitoring_heap_SOURCES = \ +test_namestore_api_monitoring_flat_SOURCES = \ test_namestore_api_monitoring.c -test_namestore_api_monitoring_heap_LDADD = \ +test_namestore_api_monitoring_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ libgnunetnamestore.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -517,9 +517,9 @@ test_namestore_api_monitoring_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ $(top_builddir)/src/util/libgnunetutil.la -test_namestore_api_monitoring_existing_heap_SOURCES = \ +test_namestore_api_monitoring_existing_flat_SOURCES = \ test_namestore_api_monitoring_existing.c -test_namestore_api_monitoring_existing_heap_LDADD = \ +test_namestore_api_monitoring_existing_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ libgnunetnamestore.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -541,9 +541,9 @@ test_namestore_api_monitoring_existing_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ $(top_builddir)/src/util/libgnunetutil.la -test_namestore_api_zone_iteration_heap_SOURCES = \ +test_namestore_api_zone_iteration_flat_SOURCES = \ test_namestore_api_zone_iteration.c -test_namestore_api_zone_iteration_heap_LDADD = \ +test_namestore_api_zone_iteration_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -581,17 +581,17 @@ perf_namestore_api_zone_iteration_sqlite_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -perf_namestore_api_zone_iteration_heap_SOURCES = \ +perf_namestore_api_zone_iteration_flat_SOURCES = \ perf_namestore_api_zone_iteration.c -perf_namestore_api_zone_iteration_heap_LDADD = \ +perf_namestore_api_zone_iteration_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_zone_iteration_nick_heap_SOURCES = \ +test_namestore_api_zone_iteration_nick_flat_SOURCES = \ test_namestore_api_zone_iteration_nick.c -test_namestore_api_zone_iteration_nick_heap_LDADD = \ +test_namestore_api_zone_iteration_nick_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -613,9 +613,9 @@ test_namestore_api_zone_iteration_nick_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_zone_iteration_specific_zone_heap_SOURCES = \ +test_namestore_api_zone_iteration_specific_zone_flat_SOURCES = \ test_namestore_api_zone_iteration_specific_zone.c -test_namestore_api_zone_iteration_specific_zone_heap_LDADD = \ +test_namestore_api_zone_iteration_specific_zone_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -637,9 +637,9 @@ test_namestore_api_zone_iteration_specific_zone_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_namestore_api_zone_iteration_stop_heap_SOURCES = \ +test_namestore_api_zone_iteration_stop_flat_SOURCES = \ test_namestore_api_zone_iteration_stop.c -test_namestore_api_zone_iteration_stop_heap_LDADD = \ +test_namestore_api_zone_iteration_stop_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ @@ -661,9 +661,9 @@ test_namestore_api_zone_iteration_stop_postgres_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ libgnunetnamestore.la -test_plugin_namestore_heap_SOURCES = \ +test_plugin_namestore_flat_SOURCES = \ test_plugin_namestore.c -test_plugin_namestore_heap_LDADD = \ +test_plugin_namestore_flat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -689,13 +689,13 @@ EXTRA_DIST = \ test_namestore_api.conf \ test_namestore_api_postgres.conf \ test_namestore_api_sqlite.conf \ - test_namestore_api_heap.conf \ + test_namestore_api_flat.conf \ perf_namestore_api_postgres.conf \ perf_namestore_api_sqlite.conf \ - perf_namestore_api_heap.conf \ + perf_namestore_api_flat.conf \ test_plugin_namestore_sqlite.conf \ test_plugin_namestore_postgres.conf \ - test_plugin_namestore_heap.conf \ + test_plugin_namestore_flat.conf \ test_hostkey \ zonefiles/S5I9DSGQVAB5FVV16T3B3CC5H1B2JGL3Q412JBKURME8EKU0600G.zkey \ zonefiles/AQ835GVL939H4O8QJQ7GBLPTQC0QAAO91BN7QK01BA63MDSK6I4G.zkey \ diff --git a/src/namestore/perf_namestore_api_flat.conf b/src/namestore/perf_namestore_api_flat.conf new file mode 100644 index 000000000..30759ce7a --- /dev/null +++ b/src/namestore/perf_namestore_api_flat.conf @@ -0,0 +1,10 @@ +@INLINE@ test_namestore_api.conf + +[namestore] +DATABASE = flat + +[namecache] +DISABLE = YES + +[namestore-heap] +FILENAME = $GNUNET_TEST_HOME/namestore/heap.db diff --git a/src/namestore/perf_namestore_api_heap.conf b/src/namestore/perf_namestore_api_heap.conf deleted file mode 100644 index a12761a7f..000000000 --- a/src/namestore/perf_namestore_api_heap.conf +++ /dev/null @@ -1,10 +0,0 @@ -@INLINE@ test_namestore_api.conf - -[namestore] -DATABASE = heap - -[namecache] -DISABLE = YES - -[namestore-heap] -FILENAME = $GNUNET_TEST_HOME/namestore/heap.db diff --git a/src/namestore/plugin_namestore_flat.c b/src/namestore/plugin_namestore_flat.c new file mode 100644 index 000000000..4e1d33907 --- /dev/null +++ b/src/namestore/plugin_namestore_flat.c @@ -0,0 +1,815 @@ + /* + * This file is part of GNUnet + * Copyright (C) 2009-2015, 2018, 2019 GNUnet e.V. + * + * GNUnet is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * GNUnet is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/** + * @file namestore/plugin_namestore_flat.c + * @brief file-based namestore backend + * @author Martin Schanzenbach + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_namestore_plugin.h" +#include "gnunet_namestore_service.h" +#include "gnunet_gnsrecord_lib.h" +#include "namestore.h" + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Database filename. + */ + char *fn; + + /** + * HashMap + */ + struct GNUNET_CONTAINER_MultiHashMap *hm; + +}; + + +struct FlatFileEntry +{ + /** + * Entry zone + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey private_key; + + /** + * Record cound + */ + uint32_t record_count; + + /** + * Rvalue + */ + uint64_t rvalue; + + /** + * Record data + */ + struct GNUNET_GNSRECORD_Data *record_data; + + /** + * Label + */ + char *label; + +}; + + +/** + * Hash contactenation of @a pkey and @a label into @a h + * + * @param pkey a key + * @param label a label + * @param h[out] initialized hash + */ +static void +hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const char *label, + struct GNUNET_HashCode *h) +{ + char *key; + size_t label_len; + size_t key_len; + + label_len = strlen (label); + key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); + key = GNUNET_malloc (key_len); + GNUNET_memcpy (key, + label, + label_len); + GNUNET_memcpy (key + label_len, + pkey, + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); + GNUNET_CRYPTO_hash (key, + key_len, + h); + GNUNET_free (key); +} + + +/** + * Initialize the database connections and associated + * data structures (create tables and indices + * as needed as well). + * + * @param plugin the plugin context (state for this module) + * @return #GNUNET_OK on success + */ +static int +database_setup (struct Plugin *plugin) +{ + char *flatdbfile; + char *record_data; + char *zone_private_key; + char *record_data_b64; + char *buffer; + char *line; + char *label; + char *rvalue; + char *record_count; + size_t record_data_size; + uint64_t size; + struct GNUNET_HashCode hkey; + struct GNUNET_DISK_FileHandle *fh; + struct FlatFileEntry *entry; + struct GNUNET_DISK_MapHandle *mh; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, + "namestore-flat", + "FILENAME", + &flatdbfile)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "namestore-flat", + "FILENAME"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_DISK_file_test (flatdbfile)) + { + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (flatdbfile)) + { + GNUNET_break (0); + GNUNET_free (flatdbfile); + return GNUNET_SYSERR; + } + } + /* flatdbfile should be UTF-8-encoded. If it isn't, it's a bug */ + plugin->fn = flatdbfile; + + /* Load data from file into hashmap */ + plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, + GNUNET_NO); + fh = GNUNET_DISK_file_open (flatdbfile, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_USER_READ); + if (NULL == fh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to initialize file: %s.\n"), + flatdbfile); + return GNUNET_SYSERR; + } + if (GNUNET_SYSERR == + GNUNET_DISK_file_size (flatdbfile, + &size, + GNUNET_YES, + GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to get filesize: %s.\n"), + flatdbfile); + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + if (size > SIZE_MAX) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("File too big to map: %llu bytes.\n"), + (unsigned long long) size); + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + if (0 == size) + { + GNUNET_DISK_file_close (fh); + return GNUNET_OK; + } + buffer = GNUNET_DISK_file_map (fh, + &mh, + GNUNET_DISK_MAP_TYPE_READ, + size); + if (NULL == buffer) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "mmap"); + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + if ('\0' != buffer[size-1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Namestore database file `%s' malformed\n"), + flatdbfile); + GNUNET_DISK_file_unmap (mh); + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + + line = strtok (buffer, "\n"); + while (NULL != line) + { + zone_private_key = strtok (line, ","); + if (NULL == zone_private_key) + break; + rvalue = strtok (NULL, ","); + if (NULL == rvalue) + break; + record_count = strtok (NULL, ","); + if (NULL == record_count) + break; + record_data_b64 = strtok (NULL, ","); + if (NULL == record_data_b64) + break; + label = strtok (NULL, ","); + if (NULL == label) + break; + line = strtok (NULL, "\n"); + entry = GNUNET_new (struct FlatFileEntry); + { + unsigned long long ll; + + if (1 != sscanf (rvalue, + "%llu", + &ll)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error parsing entry\n"); + GNUNET_free (entry); + break; + } + entry->rvalue = (uint64_t) ll; + } + { + unsigned int ui; + + if (1 != sscanf (record_count, + "%u", + &ui)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error parsing entry\n"); + GNUNET_free (entry); + break; + } + entry->record_count = (uint32_t) ui; + } + entry->label = GNUNET_strdup (label); + record_data_size + = GNUNET_STRINGS_base64_decode (record_data_b64, + strlen (record_data_b64), + (void **) &record_data); + entry->record_data = + GNUNET_new_array (entry->record_count, + struct GNUNET_GNSRECORD_Data); + if (GNUNET_OK != + GNUNET_GNSRECORD_records_deserialize (record_data_size, + record_data, + entry->record_count, + entry->record_data)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to deserialize record %s\n", + label); + GNUNET_free (entry->label); + GNUNET_free (entry); + GNUNET_free (record_data); + break; + } + GNUNET_free (record_data); + + { + struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key; + + GNUNET_STRINGS_base64_decode (zone_private_key, + strlen (zone_private_key), + (void**)&private_key); + entry->private_key = *private_key; + GNUNET_free (private_key); + } + + hash_pkey_and_label (&entry->private_key, + label, + &hkey); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (plugin->hm, + &hkey, + entry, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_free (entry); + GNUNET_break (0); + } + } + GNUNET_DISK_file_unmap (mh); + GNUNET_DISK_file_close (fh); + return GNUNET_OK; +} + + +/** + * Store values in hashmap in file and free data + * + * @param plugin the plugin context + * @param key key in the map + * @param value a `struct FlatFileEntry` + */ +static int +store_and_free_entries (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_DISK_FileHandle *fh = cls; + struct FlatFileEntry *entry = value; + char *line; + char *zone_private_key; + char *record_data_b64; + ssize_t data_size; + + (void) key; + GNUNET_STRINGS_base64_encode (&entry->private_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey), + &zone_private_key); + data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count, + entry->record_data); + if (data_size < 0) + { + GNUNET_break (0); + GNUNET_free (zone_private_key); + return GNUNET_SYSERR; + } + if (data_size >= UINT16_MAX) + { + GNUNET_break (0); + GNUNET_free (zone_private_key); + return GNUNET_SYSERR; + } + { + char data[data_size]; + ssize_t ret; + + ret = GNUNET_GNSRECORD_records_serialize (entry->record_count, + entry->record_data, + data_size, + data); + if ( (ret < 0) || + (data_size != ret) ) + { + GNUNET_break (0); + GNUNET_free (zone_private_key); + return GNUNET_SYSERR; + } + GNUNET_STRINGS_base64_encode (data, + data_size, + &record_data_b64); + } + GNUNET_asprintf (&line, + "%s,%llu,%u,%s,%s\n", + zone_private_key, + (unsigned long long) entry->rvalue, + (unsigned int) entry->record_count, + record_data_b64, + entry->label); + GNUNET_free (record_data_b64); + GNUNET_free (zone_private_key); + + GNUNET_DISK_file_write (fh, + line, + strlen (line)); + + GNUNET_free (line); + GNUNET_free (entry->label); + GNUNET_free (entry->record_data); + GNUNET_free (entry); + return GNUNET_YES; +} + + +/** + * Shutdown database connection and associate data + * structures. + * @param plugin the plugin context (state for this module) + */ +static void +database_shutdown (struct Plugin *plugin) +{ + struct GNUNET_DISK_FileHandle *fh; + + fh = GNUNET_DISK_file_open (plugin->fn, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_TRUNCATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_USER_READ); + if (NULL == fh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to initialize file: %s.\n"), + plugin->fn); + return; + } + + GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, + &store_and_free_entries, + fh); + GNUNET_CONTAINER_multihashmap_destroy (plugin->hm); + /* append 0-terminator */ + GNUNET_DISK_file_write (fh, + "", + 1); + GNUNET_DISK_file_close (fh); +} + + +/** + * Store a record in the datastore. Removes any existing record in the + * same zone with the same name. + * + * @param cls closure (internal context for the plugin) + * @param zone_key private key of the zone + * @param label name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in @a rd array + * @param rd array of records with data to store + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +namestore_flat_store_records (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct Plugin *plugin = cls; + uint64_t rvalue; + struct GNUNET_HashCode hkey; + struct FlatFileEntry *entry; + + rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + hash_pkey_and_label (zone_key, + label, + &hkey); + GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm, + &hkey); + if (0 == rd_count) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Record deleted\n"); + return GNUNET_OK; + } + entry = GNUNET_new (struct FlatFileEntry); + GNUNET_asprintf (&entry->label, + label, + strlen (label)); + GNUNET_memcpy (&entry->private_key, + zone_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); + entry->rvalue = rvalue; + entry->record_count = rd_count; + entry->record_data = GNUNET_new_array (rd_count, + struct GNUNET_GNSRECORD_Data); + for (unsigned int i = 0; i < rd_count; i++) + { + entry->record_data[i].expiration_time = rd[i].expiration_time; + entry->record_data[i].record_type = rd[i].record_type; + entry->record_data[i].flags = rd[i].flags; + entry->record_data[i].data_size = rd[i].data_size; + entry->record_data[i].data = GNUNET_malloc (rd[i].data_size); + GNUNET_memcpy ((char*)entry->record_data[i].data, + rd[i].data, + rd[i].data_size); + } + return GNUNET_CONTAINER_multihashmap_put (plugin->hm, + &hkey, + entry, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); +} + + +/** + * Lookup records in the datastore for which we are the authority. + * + * @param cls closure (internal context for the plugin) + * @param zone private key of the zone + * @param label name of the record in the zone + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR + */ +static int +namestore_flat_lookup_records (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + GNUNET_NAMESTORE_RecordIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + struct FlatFileEntry *entry; + struct GNUNET_HashCode hkey; + + if (NULL == zone) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + hash_pkey_and_label (zone, + label, + &hkey); + entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm, + &hkey); + + if (NULL == entry) + return GNUNET_NO; + if (NULL != iter) + iter (iter_cls, + 1, /* zero is illegal */ + &entry->private_key, + entry->label, + entry->record_count, + entry->record_data); + return GNUNET_YES; +} + + +/** + * Closure for #iterate_zones. + */ +struct IterateContext +{ + /** + * How many more records should we skip before returning results? + */ + uint64_t offset; + + /** + * How many more records should we return? + */ + uint64_t limit; + + /** + * What is the position of the current entry, counting + * starts from 1. + */ + uint64_t pos; + + /** + * Target zone. + */ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone; + + /** + * Function to call on each record. + */ + GNUNET_NAMESTORE_RecordIterator iter; + + /** + * Closure for @e iter. + */ + void *iter_cls; + +}; + + +/** + * Helper function for #namestore_flat_iterate_records(). + * + * @param cls a `struct IterateContext` + * @param key unused + * @param value a `struct FlatFileEntry` + * @return #GNUNET_YES to continue the iteration + */ +static int +iterate_zones (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct IterateContext *ic = cls; + struct FlatFileEntry *entry = value; + + (void) key; + if (0 == ic->limit) + return GNUNET_NO; + if ( (NULL != ic->zone) && + (0 != GNUNET_memcmp (&entry->private_key, + ic->zone)) ) + return GNUNET_YES; + ic->pos++; + if (ic->offset > 0) + { + ic->offset--; + return GNUNET_YES; + } + ic->iter (ic->iter_cls, + ic->pos, + (NULL == ic->zone) + ? &entry->private_key + : ic->zone, + entry->label, + entry->record_count, + entry->record_data); + ic->limit--; + if (0 == ic->limit) + return GNUNET_NO; + return GNUNET_YES; +} + + +/** + * Iterate over the results for a particular key and zone in the + * datastore. Will return at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param zone hash of public key of the zone, NULL to iterate over all zones + * @param serial serial number to exclude in the list of all matching records + * @param limit maximum number of results to return to @a iter + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error + */ +static int +namestore_flat_iterate_records (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + uint64_t serial, + uint64_t limit, + GNUNET_NAMESTORE_RecordIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + struct IterateContext ic; + + ic.offset = serial; + ic.pos = 0; + ic.limit = limit; + ic.iter = iter; + ic.iter_cls = iter_cls; + ic.zone = zone; + GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, + &iterate_zones, + &ic); + return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO; +} + + +/** + * Closure for #zone_to_name. + */ +struct ZoneToNameContext +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone; + const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone; + GNUNET_NAMESTORE_RecordIterator iter; + void *iter_cls; + + int result_found; +}; + + +static int +zone_to_name (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct ZoneToNameContext *ztn = cls; + struct FlatFileEntry *entry = value; + + (void) key; + if (0 != GNUNET_memcmp (&entry->private_key, + ztn->zone)) + return GNUNET_YES; + + for (unsigned int i = 0; i < entry->record_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type) + continue; + if (0 == memcmp (ztn->value_zone, + entry->record_data[i].data, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + ztn->iter (ztn->iter_cls, + i + 1, /* zero is illegal! */ + &entry->private_key, + entry->label, + entry->record_count, + entry->record_data); + ztn->result_found = GNUNET_YES; + } + } + return GNUNET_YES; +} + + +/** + * Look for an existing PKEY delegation record for a given public key. + * Returns at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param zone private key of the zone to look up in, never NULL + * @param value_zone public key of the target zone (value), never NULL + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ +static int +namestore_flat_zone_to_name (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone, + GNUNET_NAMESTORE_RecordIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + struct ZoneToNameContext ztn = { + .iter = iter, + .iter_cls = iter_cls, + .zone = zone, + .value_zone = value_zone, + .result_found = GNUNET_NO + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Performing reverse lookup for `%s'\n", + GNUNET_GNSRECORD_z2s (value_zone)); + GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, + &zone_to_name, + &ztn); + return ztn.result_found; +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_namestore_flat_init (void *cls) +{ + static struct Plugin plugin; + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_NAMESTORE_PluginFunctions *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, + 0, + sizeof (struct Plugin)); + plugin.cfg = cfg; + if (GNUNET_OK != database_setup (&plugin)) + { + database_shutdown (&plugin); + return NULL; + } + api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); + api->cls = &plugin; + api->store_records = &namestore_flat_store_records; + api->iterate_records = &namestore_flat_iterate_records; + api->zone_to_name = &namestore_flat_zone_to_name; + api->lookup_records = &namestore_flat_lookup_records; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Flat file database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_namestore_flat_done (void *cls) +{ + struct GNUNET_NAMESTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + database_shutdown (plugin); + plugin->cfg = NULL; + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Flat file plugin is finished\n"); + return NULL; +} + +/* end of plugin_namestore_flat.c */ diff --git a/src/namestore/plugin_namestore_heap.c b/src/namestore/plugin_namestore_heap.c deleted file mode 100644 index 2a72c0e51..000000000 --- a/src/namestore/plugin_namestore_heap.c +++ /dev/null @@ -1,796 +0,0 @@ - /* - * This file is part of GNUnet - * Copyright (C) 2009-2015, 2018 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file namestore/plugin_namestore_heap.c - * @brief file-based namestore backend - * @author Martin Schanzenbach - * @author Christian Grothoff - */ - -#include "platform.h" -#include "gnunet_namestore_plugin.h" -#include "gnunet_namestore_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "namestore.h" - -/** - * Context for all functions in this plugin. - */ -struct Plugin -{ - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Database filename. - */ - char *fn; - - /** - * HashMap - */ - struct GNUNET_CONTAINER_MultiHashMap *hm; - -}; - - -struct FlatFileEntry -{ - /** - * Entry zone - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey private_key; - - /** - * Record cound - */ - uint32_t record_count; - - /** - * Rvalue - */ - uint64_t rvalue; - - /** - * Record data - */ - struct GNUNET_GNSRECORD_Data *record_data; - - /** - * Label - */ - char *label; - -}; - - -/** - * Hash contactenation of @a pkey and @a label into @a h - * - * @param pkey a key - * @param label a label - * @param h[out] initialized hash - */ -static void -hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, - const char *label, - struct GNUNET_HashCode *h) -{ - char *key; - size_t label_len; - size_t key_len; - - label_len = strlen (label); - key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); - key = GNUNET_malloc (key_len); - GNUNET_memcpy (key, - label, - label_len); - GNUNET_memcpy (key + label_len, - pkey, - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); - GNUNET_CRYPTO_hash (key, - key_len, - h); - GNUNET_free (key); -} - - -/** - * Initialize the database connections and associated - * data structures (create tables and indices - * as needed as well). - * - * @param plugin the plugin context (state for this module) - * @return #GNUNET_OK on success - */ -static int -database_setup (struct Plugin *plugin) -{ - char *afsdir; - char *record_data; - char *zone_private_key; - char *record_data_b64; - char *buffer; - char *line; - char *label; - char *rvalue; - char *record_count; - size_t record_data_size; - uint64_t size; - struct GNUNET_HashCode hkey; - struct GNUNET_DISK_FileHandle *fh; - struct FlatFileEntry *entry; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, - "namestore-heap", - "FILENAME", - &afsdir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "namestore-heap", - "FILENAME"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_DISK_file_test (afsdir)) - { - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (afsdir)) - { - GNUNET_break (0); - GNUNET_free (afsdir); - return GNUNET_SYSERR; - } - } - /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ - plugin->fn = afsdir; - - /* Load data from file into hashmap */ - plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, - GNUNET_NO); - fh = GNUNET_DISK_file_open (afsdir, - GNUNET_DISK_OPEN_CREATE | - GNUNET_DISK_OPEN_READWRITE, - GNUNET_DISK_PERM_USER_WRITE | - GNUNET_DISK_PERM_USER_READ); - if (NULL == fh) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to initialize file: %s.\n"), - afsdir); - return GNUNET_SYSERR; - } - if (GNUNET_SYSERR == - GNUNET_DISK_file_size (afsdir, - &size, - GNUNET_YES, - GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to get filesize: %s.\n"), - afsdir); - GNUNET_DISK_file_close (fh); - return GNUNET_SYSERR; - } - - buffer = GNUNET_malloc_large (size + 1); - if (GNUNET_SYSERR == - GNUNET_DISK_file_read (fh, - buffer, - size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to read file: %s.\n"), - afsdir); - GNUNET_free (buffer); - GNUNET_DISK_file_close (fh); - return GNUNET_SYSERR; - } - buffer[size] = '\0'; - GNUNET_DISK_file_close (fh); - - if (0 < size) - { - line = strtok (buffer, "\n"); - while (line != NULL) - { - zone_private_key = strtok (line, ","); - if (NULL == zone_private_key) - break; - rvalue = strtok (NULL, ","); - if (NULL == rvalue) - break; - record_count = strtok (NULL, ","); - if (NULL == record_count) - break; - record_data_b64 = strtok (NULL, ","); - if (NULL == record_data_b64) - break; - label = strtok (NULL, ","); - if (NULL == label) - break; - line = strtok (NULL, "\n"); - entry = GNUNET_new (struct FlatFileEntry); - { - unsigned long long ll; - - if (1 != sscanf (rvalue, - "%llu", - &ll)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing entry\n"); - GNUNET_free (entry); - break; - } - entry->rvalue = (uint64_t) ll; - } - { - unsigned int ui; - - if (1 != sscanf (record_count, - "%u", - &ui)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing entry\n"); - GNUNET_free (entry); - break; - } - entry->record_count = (uint32_t) ui; - } - entry->label = GNUNET_strdup (label); - record_data_size - = GNUNET_STRINGS_base64_decode (record_data_b64, - strlen (record_data_b64), - (void **) &record_data); - entry->record_data = - GNUNET_new_array (entry->record_count, - struct GNUNET_GNSRECORD_Data); - if (GNUNET_OK != - GNUNET_GNSRECORD_records_deserialize (record_data_size, - record_data, - entry->record_count, - entry->record_data)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to deserialize record %s\n", - label); - GNUNET_free (entry->label); - GNUNET_free (entry); - GNUNET_free (record_data); - break; - } - GNUNET_free (record_data); - - { - struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key; - - GNUNET_STRINGS_base64_decode (zone_private_key, - strlen (zone_private_key), - (void**)&private_key); - entry->private_key = *private_key; - GNUNET_free (private_key); - } - - hash_pkey_and_label (&entry->private_key, - label, - &hkey); - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (plugin->hm, - &hkey, - entry, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_free (entry); - GNUNET_break (0); - } - } - } - GNUNET_free (buffer); - return GNUNET_OK; -} - - -/** - * Store values in hashmap in file and free data - * - * @param plugin the plugin context - * @param key key in the map - * @param value a `struct FlatFileEntry` - */ -static int -store_and_free_entries (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct GNUNET_DISK_FileHandle *fh = cls; - struct FlatFileEntry *entry = value; - char *line; - char *zone_private_key; - char *record_data_b64; - ssize_t data_size; - - (void) key; - GNUNET_STRINGS_base64_encode (&entry->private_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey), - &zone_private_key); - data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count, - entry->record_data); - if (data_size < 0) - { - GNUNET_break (0); - GNUNET_free (zone_private_key); - return GNUNET_SYSERR; - } - if (data_size >= UINT16_MAX) - { - GNUNET_break (0); - GNUNET_free (zone_private_key); - return GNUNET_SYSERR; - } - { - char data[data_size]; - ssize_t ret; - - ret = GNUNET_GNSRECORD_records_serialize (entry->record_count, - entry->record_data, - data_size, - data); - if ( (ret < 0) || - (data_size != ret) ) - { - GNUNET_break (0); - GNUNET_free (zone_private_key); - return GNUNET_SYSERR; - } - GNUNET_STRINGS_base64_encode (data, - data_size, - &record_data_b64); - } - GNUNET_asprintf (&line, - "%s,%llu,%u,%s,%s\n", - zone_private_key, - (unsigned long long) entry->rvalue, - (unsigned int) entry->record_count, - record_data_b64, - entry->label); - GNUNET_free (record_data_b64); - GNUNET_free (zone_private_key); - - GNUNET_DISK_file_write (fh, - line, - strlen (line)); - - GNUNET_free (line); - GNUNET_free (entry->label); - GNUNET_free (entry->record_data); - GNUNET_free (entry); - return GNUNET_YES; -} - - -/** - * Shutdown database connection and associate data - * structures. - * @param plugin the plugin context (state for this module) - */ -static void -database_shutdown (struct Plugin *plugin) -{ - struct GNUNET_DISK_FileHandle *fh; - - fh = GNUNET_DISK_file_open (plugin->fn, - GNUNET_DISK_OPEN_CREATE | - GNUNET_DISK_OPEN_TRUNCATE | - GNUNET_DISK_OPEN_READWRITE, - GNUNET_DISK_PERM_USER_WRITE | - GNUNET_DISK_PERM_USER_READ); - if (NULL == fh) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to initialize file: %s.\n"), - plugin->fn); - return; - } - - GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, - &store_and_free_entries, - fh); - GNUNET_CONTAINER_multihashmap_destroy (plugin->hm); - GNUNET_DISK_file_close (fh); -} - - -/** - * Store a record in the datastore. Removes any existing record in the - * same zone with the same name. - * - * @param cls closure (internal context for the plugin) - * @param zone_key private key of the zone - * @param label name that is being mapped (at most 255 characters long) - * @param rd_count number of entries in @a rd array - * @param rd array of records with data to store - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -namestore_heap_store_records (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct Plugin *plugin = cls; - uint64_t rvalue; - struct GNUNET_HashCode hkey; - struct FlatFileEntry *entry; - - rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX); - hash_pkey_and_label (zone_key, - label, - &hkey); - GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm, - &hkey); - if (0 == rd_count) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Record deleted\n"); - return GNUNET_OK; - } - entry = GNUNET_new (struct FlatFileEntry); - GNUNET_asprintf (&entry->label, - label, - strlen (label)); - GNUNET_memcpy (&entry->private_key, - zone_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); - entry->rvalue = rvalue; - entry->record_count = rd_count; - entry->record_data = GNUNET_new_array (rd_count, - struct GNUNET_GNSRECORD_Data); - for (unsigned int i = 0; i < rd_count; i++) - { - entry->record_data[i].expiration_time = rd[i].expiration_time; - entry->record_data[i].record_type = rd[i].record_type; - entry->record_data[i].flags = rd[i].flags; - entry->record_data[i].data_size = rd[i].data_size; - entry->record_data[i].data = GNUNET_malloc (rd[i].data_size); - GNUNET_memcpy ((char*)entry->record_data[i].data, - rd[i].data, - rd[i].data_size); - } - return GNUNET_CONTAINER_multihashmap_put (plugin->hm, - &hkey, - entry, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); -} - - -/** - * Lookup records in the datastore for which we are the authority. - * - * @param cls closure (internal context for the plugin) - * @param zone private key of the zone - * @param label name of the record in the zone - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR - */ -static int -namestore_heap_lookup_records (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - GNUNET_NAMESTORE_RecordIterator iter, - void *iter_cls) -{ - struct Plugin *plugin = cls; - struct FlatFileEntry *entry; - struct GNUNET_HashCode hkey; - - if (NULL == zone) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - hash_pkey_and_label (zone, - label, - &hkey); - entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm, - &hkey); - - if (NULL == entry) - return GNUNET_NO; - if (NULL != iter) - iter (iter_cls, - 1, /* zero is illegal */ - &entry->private_key, - entry->label, - entry->record_count, - entry->record_data); - return GNUNET_YES; -} - - -/** - * Closure for #iterate_zones. - */ -struct IterateContext -{ - /** - * How many more records should we skip before returning results? - */ - uint64_t offset; - - /** - * How many more records should we return? - */ - uint64_t limit; - - /** - * What is the position of the current entry, counting - * starts from 1. - */ - uint64_t pos; - - /** - * Target zone. - */ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone; - - /** - * Function to call on each record. - */ - GNUNET_NAMESTORE_RecordIterator iter; - - /** - * Closure for @e iter. - */ - void *iter_cls; - -}; - - -/** - * Helper function for #namestore_heap_iterate_records(). - * - * @param cls a `struct IterateContext` - * @param key unused - * @param value a `struct FlatFileEntry` - * @return #GNUNET_YES to continue the iteration - */ -static int -iterate_zones (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct IterateContext *ic = cls; - struct FlatFileEntry *entry = value; - - (void) key; - if (0 == ic->limit) - return GNUNET_NO; - if ( (NULL != ic->zone) && - (0 != GNUNET_memcmp (&entry->private_key, - ic->zone)) ) - return GNUNET_YES; - ic->pos++; - if (ic->offset > 0) - { - ic->offset--; - return GNUNET_YES; - } - ic->iter (ic->iter_cls, - ic->pos, - (NULL == ic->zone) - ? &entry->private_key - : ic->zone, - entry->label, - entry->record_count, - entry->record_data); - ic->limit--; - if (0 == ic->limit) - return GNUNET_NO; - return GNUNET_YES; -} - - -/** - * Iterate over the results for a particular key and zone in the - * datastore. Will return at most one result to the iterator. - * - * @param cls closure (internal context for the plugin) - * @param zone hash of public key of the zone, NULL to iterate over all zones - * @param serial serial number to exclude in the list of all matching records - * @param limit maximum number of results to return to @a iter - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error - */ -static int -namestore_heap_iterate_records (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - uint64_t serial, - uint64_t limit, - GNUNET_NAMESTORE_RecordIterator iter, - void *iter_cls) -{ - struct Plugin *plugin = cls; - struct IterateContext ic; - - ic.offset = serial; - ic.pos = 0; - ic.limit = limit; - ic.iter = iter; - ic.iter_cls = iter_cls; - ic.zone = zone; - GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, - &iterate_zones, - &ic); - return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO; -} - - -/** - * Closure for #zone_to_name. - */ -struct ZoneToNameContext -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone; - const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone; - GNUNET_NAMESTORE_RecordIterator iter; - void *iter_cls; - - int result_found; -}; - - -static int -zone_to_name (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct ZoneToNameContext *ztn = cls; - struct FlatFileEntry *entry = value; - - (void) key; - if (0 != GNUNET_memcmp (&entry->private_key, - ztn->zone)) - return GNUNET_YES; - - for (unsigned int i = 0; i < entry->record_count; i++) - { - if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type) - continue; - if (0 == memcmp (ztn->value_zone, - entry->record_data[i].data, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - ztn->iter (ztn->iter_cls, - i + 1, /* zero is illegal! */ - &entry->private_key, - entry->label, - entry->record_count, - entry->record_data); - ztn->result_found = GNUNET_YES; - } - } - return GNUNET_YES; -} - - -/** - * Look for an existing PKEY delegation record for a given public key. - * Returns at most one result to the iterator. - * - * @param cls closure (internal context for the plugin) - * @param zone private key of the zone to look up in, never NULL - * @param value_zone public key of the target zone (value), never NULL - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error - */ -static int -namestore_heap_zone_to_name (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone, - GNUNET_NAMESTORE_RecordIterator iter, - void *iter_cls) -{ - struct Plugin *plugin = cls; - struct ZoneToNameContext ztn = { - .iter = iter, - .iter_cls = iter_cls, - .zone = zone, - .value_zone = value_zone, - .result_found = GNUNET_NO - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Performing reverse lookup for `%s'\n", - GNUNET_GNSRECORD_z2s (value_zone)); - GNUNET_CONTAINER_multihashmap_iterate (plugin->hm, - &zone_to_name, - &ztn); - return ztn.result_found; -} - - -/** - * Entry point for the plugin. - * - * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_namestore_heap_init (void *cls) -{ - static struct Plugin plugin; - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_NAMESTORE_PluginFunctions *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, - 0, - sizeof (struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) - { - database_shutdown (&plugin); - return NULL; - } - api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); - api->cls = &plugin; - api->store_records = &namestore_heap_store_records; - api->iterate_records = &namestore_heap_iterate_records; - api->zone_to_name = &namestore_heap_zone_to_name; - api->lookup_records = &namestore_heap_lookup_records; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("heap file database running\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_namestore_heap_done (void *cls) -{ - struct GNUNET_NAMESTORE_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - - database_shutdown (plugin); - plugin->cfg = NULL; - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "heap file plugin is finished\n"); - return NULL; -} - -/* end of plugin_namestore_heap.c */ diff --git a/src/namestore/test_namestore_api_flat.conf b/src/namestore/test_namestore_api_flat.conf new file mode 100644 index 000000000..8460d143c --- /dev/null +++ b/src/namestore/test_namestore_api_flat.conf @@ -0,0 +1,7 @@ +@INLINE@ test_namestore_api.conf + +[namestore] +DATABASE = flat + +[namestore-heap] +FILENAME = $GNUNET_TEST_HOME/namestore/flat.db diff --git a/src/namestore/test_namestore_api_heap.conf b/src/namestore/test_namestore_api_heap.conf deleted file mode 100644 index 1d6173e74..000000000 --- a/src/namestore/test_namestore_api_heap.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_namestore_api.conf - -[namestore] -DATABASE = heap - -[namestore-heap] -FILENAME = $GNUNET_TEST_HOME/namestore/flat.db diff --git a/src/namestore/test_plugin_namestore_flat.conf b/src/namestore/test_plugin_namestore_flat.conf new file mode 100644 index 000000000..5c632f0d1 --- /dev/null +++ b/src/namestore/test_plugin_namestore_flat.conf @@ -0,0 +1,2 @@ +[namestore-flat] +FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-flat/flatdb diff --git a/src/namestore/test_plugin_namestore_heap.conf b/src/namestore/test_plugin_namestore_heap.conf deleted file mode 100644 index 94f79b9aa..000000000 --- a/src/namestore/test_plugin_namestore_heap.conf +++ /dev/null @@ -1,2 +0,0 @@ -[namestore-heap] -FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-flat/flatdb diff --git a/src/util/disk.c b/src/util/disk.c index 4f78c7747..f395a375e 100644 --- a/src/util/disk.c +++ b/src/util/disk.c @@ -2021,7 +2021,7 @@ GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, struct GNUNET_DISK_MapHandle **m, enum GNUNET_DISK_MapType access, size_t len) { - if (h == NULL) + if (NULL == h) { errno = EINVAL; return NULL;