123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- 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_IDENTITY_PrivateKey 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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey);
- key = GNUNET_malloc (key_len);
- GNUNET_memcpy (key,
- label,
- label_len);
- GNUNET_memcpy (key + label_len,
- pkey,
- sizeof(struct GNUNET_IDENTITY_PrivateKey));
- 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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey),
- &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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey));
- 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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey *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_IDENTITY_PrivateKey *zone;
- const struct GNUNET_IDENTITY_PublicKey *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_NO ==
- GNUNET_GNSRECORD_is_zonekey_type (entry->record_data[i].record_type))
- continue;
- if (ztn->value_zone->type != entry->record_data[i].record_type)
- continue;
- if (0 == memcmp (ztn->value_zone,
- entry->record_data[i].data,
- entry->record_data[i].data_size))
- {
- 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_IDENTITY_PrivateKey *zone,
- const struct
- GNUNET_IDENTITY_PublicKey *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 */
|