aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_namestore_flat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/plugin_namestore_flat.c')
-rw-r--r--src/namestore/plugin_namestore_flat.c815
1 files changed, 815 insertions, 0 deletions
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 @@
1 /*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2015, 2018, 2019 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file namestore/plugin_namestore_flat.c
22 * @brief file-based namestore backend
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "namestore.h"
32
33/**
34 * Context for all functions in this plugin.
35 */
36struct Plugin
37{
38
39 const struct GNUNET_CONFIGURATION_Handle *cfg;
40
41 /**
42 * Database filename.
43 */
44 char *fn;
45
46 /**
47 * HashMap
48 */
49 struct GNUNET_CONTAINER_MultiHashMap *hm;
50
51};
52
53
54struct FlatFileEntry
55{
56 /**
57 * Entry zone
58 */
59 struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
60
61 /**
62 * Record cound
63 */
64 uint32_t record_count;
65
66 /**
67 * Rvalue
68 */
69 uint64_t rvalue;
70
71 /**
72 * Record data
73 */
74 struct GNUNET_GNSRECORD_Data *record_data;
75
76 /**
77 * Label
78 */
79 char *label;
80
81};
82
83
84/**
85 * Hash contactenation of @a pkey and @a label into @a h
86 *
87 * @param pkey a key
88 * @param label a label
89 * @param h[out] initialized hash
90 */
91static void
92hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
93 const char *label,
94 struct GNUNET_HashCode *h)
95{
96 char *key;
97 size_t label_len;
98 size_t key_len;
99
100 label_len = strlen (label);
101 key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
102 key = GNUNET_malloc (key_len);
103 GNUNET_memcpy (key,
104 label,
105 label_len);
106 GNUNET_memcpy (key + label_len,
107 pkey,
108 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
109 GNUNET_CRYPTO_hash (key,
110 key_len,
111 h);
112 GNUNET_free (key);
113}
114
115
116/**
117 * Initialize the database connections and associated
118 * data structures (create tables and indices
119 * as needed as well).
120 *
121 * @param plugin the plugin context (state for this module)
122 * @return #GNUNET_OK on success
123 */
124static int
125database_setup (struct Plugin *plugin)
126{
127 char *flatdbfile;
128 char *record_data;
129 char *zone_private_key;
130 char *record_data_b64;
131 char *buffer;
132 char *line;
133 char *label;
134 char *rvalue;
135 char *record_count;
136 size_t record_data_size;
137 uint64_t size;
138 struct GNUNET_HashCode hkey;
139 struct GNUNET_DISK_FileHandle *fh;
140 struct FlatFileEntry *entry;
141 struct GNUNET_DISK_MapHandle *mh;
142
143 if (GNUNET_OK !=
144 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
145 "namestore-flat",
146 "FILENAME",
147 &flatdbfile))
148 {
149 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
150 "namestore-flat",
151 "FILENAME");
152 return GNUNET_SYSERR;
153 }
154 if (GNUNET_OK !=
155 GNUNET_DISK_file_test (flatdbfile))
156 {
157 if (GNUNET_OK !=
158 GNUNET_DISK_directory_create_for_file (flatdbfile))
159 {
160 GNUNET_break (0);
161 GNUNET_free (flatdbfile);
162 return GNUNET_SYSERR;
163 }
164 }
165 /* flatdbfile should be UTF-8-encoded. If it isn't, it's a bug */
166 plugin->fn = flatdbfile;
167
168 /* Load data from file into hashmap */
169 plugin->hm = GNUNET_CONTAINER_multihashmap_create (10,
170 GNUNET_NO);
171 fh = GNUNET_DISK_file_open (flatdbfile,
172 GNUNET_DISK_OPEN_CREATE |
173 GNUNET_DISK_OPEN_READWRITE,
174 GNUNET_DISK_PERM_USER_WRITE |
175 GNUNET_DISK_PERM_USER_READ);
176 if (NULL == fh)
177 {
178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
179 _("Unable to initialize file: %s.\n"),
180 flatdbfile);
181 return GNUNET_SYSERR;
182 }
183 if (GNUNET_SYSERR ==
184 GNUNET_DISK_file_size (flatdbfile,
185 &size,
186 GNUNET_YES,
187 GNUNET_YES))
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190 _("Unable to get filesize: %s.\n"),
191 flatdbfile);
192 GNUNET_DISK_file_close (fh);
193 return GNUNET_SYSERR;
194 }
195 if (size > SIZE_MAX)
196 {
197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 _("File too big to map: %llu bytes.\n"),
199 (unsigned long long) size);
200 GNUNET_DISK_file_close (fh);
201 return GNUNET_SYSERR;
202 }
203 if (0 == size)
204 {
205 GNUNET_DISK_file_close (fh);
206 return GNUNET_OK;
207 }
208 buffer = GNUNET_DISK_file_map (fh,
209 &mh,
210 GNUNET_DISK_MAP_TYPE_READ,
211 size);
212 if (NULL == buffer)
213 {
214 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
215 "mmap");
216 GNUNET_DISK_file_close (fh);
217 return GNUNET_SYSERR;
218 }
219 if ('\0' != buffer[size-1])
220 {
221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222 _("Namestore database file `%s' malformed\n"),
223 flatdbfile);
224 GNUNET_DISK_file_unmap (mh);
225 GNUNET_DISK_file_close (fh);
226 return GNUNET_SYSERR;
227 }
228
229 line = strtok (buffer, "\n");
230 while (NULL != line)
231 {
232 zone_private_key = strtok (line, ",");
233 if (NULL == zone_private_key)
234 break;
235 rvalue = strtok (NULL, ",");
236 if (NULL == rvalue)
237 break;
238 record_count = strtok (NULL, ",");
239 if (NULL == record_count)
240 break;
241 record_data_b64 = strtok (NULL, ",");
242 if (NULL == record_data_b64)
243 break;
244 label = strtok (NULL, ",");
245 if (NULL == label)
246 break;
247 line = strtok (NULL, "\n");
248 entry = GNUNET_new (struct FlatFileEntry);
249 {
250 unsigned long long ll;
251
252 if (1 != sscanf (rvalue,
253 "%llu",
254 &ll))
255 {
256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257 "Error parsing entry\n");
258 GNUNET_free (entry);
259 break;
260 }
261 entry->rvalue = (uint64_t) ll;
262 }
263 {
264 unsigned int ui;
265
266 if (1 != sscanf (record_count,
267 "%u",
268 &ui))
269 {
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271 "Error parsing entry\n");
272 GNUNET_free (entry);
273 break;
274 }
275 entry->record_count = (uint32_t) ui;
276 }
277 entry->label = GNUNET_strdup (label);
278 record_data_size
279 = GNUNET_STRINGS_base64_decode (record_data_b64,
280 strlen (record_data_b64),
281 (void **) &record_data);
282 entry->record_data =
283 GNUNET_new_array (entry->record_count,
284 struct GNUNET_GNSRECORD_Data);
285 if (GNUNET_OK !=
286 GNUNET_GNSRECORD_records_deserialize (record_data_size,
287 record_data,
288 entry->record_count,
289 entry->record_data))
290 {
291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
292 "Unable to deserialize record %s\n",
293 label);
294 GNUNET_free (entry->label);
295 GNUNET_free (entry);
296 GNUNET_free (record_data);
297 break;
298 }
299 GNUNET_free (record_data);
300
301 {
302 struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key;
303
304 GNUNET_STRINGS_base64_decode (zone_private_key,
305 strlen (zone_private_key),
306 (void**)&private_key);
307 entry->private_key = *private_key;
308 GNUNET_free (private_key);
309 }
310
311 hash_pkey_and_label (&entry->private_key,
312 label,
313 &hkey);
314 if (GNUNET_OK !=
315 GNUNET_CONTAINER_multihashmap_put (plugin->hm,
316 &hkey,
317 entry,
318 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
319 {
320 GNUNET_free (entry);
321 GNUNET_break (0);
322 }
323 }
324 GNUNET_DISK_file_unmap (mh);
325 GNUNET_DISK_file_close (fh);
326 return GNUNET_OK;
327}
328
329
330/**
331 * Store values in hashmap in file and free data
332 *
333 * @param plugin the plugin context
334 * @param key key in the map
335 * @param value a `struct FlatFileEntry`
336 */
337static int
338store_and_free_entries (void *cls,
339 const struct GNUNET_HashCode *key,
340 void *value)
341{
342 struct GNUNET_DISK_FileHandle *fh = cls;
343 struct FlatFileEntry *entry = value;
344 char *line;
345 char *zone_private_key;
346 char *record_data_b64;
347 ssize_t data_size;
348
349 (void) key;
350 GNUNET_STRINGS_base64_encode (&entry->private_key,
351 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
352 &zone_private_key);
353 data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count,
354 entry->record_data);
355 if (data_size < 0)
356 {
357 GNUNET_break (0);
358 GNUNET_free (zone_private_key);
359 return GNUNET_SYSERR;
360 }
361 if (data_size >= UINT16_MAX)
362 {
363 GNUNET_break (0);
364 GNUNET_free (zone_private_key);
365 return GNUNET_SYSERR;
366 }
367 {
368 char data[data_size];
369 ssize_t ret;
370
371 ret = GNUNET_GNSRECORD_records_serialize (entry->record_count,
372 entry->record_data,
373 data_size,
374 data);
375 if ( (ret < 0) ||
376 (data_size != ret) )
377 {
378 GNUNET_break (0);
379 GNUNET_free (zone_private_key);
380 return GNUNET_SYSERR;
381 }
382 GNUNET_STRINGS_base64_encode (data,
383 data_size,
384 &record_data_b64);
385 }
386 GNUNET_asprintf (&line,
387 "%s,%llu,%u,%s,%s\n",
388 zone_private_key,
389 (unsigned long long) entry->rvalue,
390 (unsigned int) entry->record_count,
391 record_data_b64,
392 entry->label);
393 GNUNET_free (record_data_b64);
394 GNUNET_free (zone_private_key);
395
396 GNUNET_DISK_file_write (fh,
397 line,
398 strlen (line));
399
400 GNUNET_free (line);
401 GNUNET_free (entry->label);
402 GNUNET_free (entry->record_data);
403 GNUNET_free (entry);
404 return GNUNET_YES;
405}
406
407
408/**
409 * Shutdown database connection and associate data
410 * structures.
411 * @param plugin the plugin context (state for this module)
412 */
413static void
414database_shutdown (struct Plugin *plugin)
415{
416 struct GNUNET_DISK_FileHandle *fh;
417
418 fh = GNUNET_DISK_file_open (plugin->fn,
419 GNUNET_DISK_OPEN_CREATE |
420 GNUNET_DISK_OPEN_TRUNCATE |
421 GNUNET_DISK_OPEN_READWRITE,
422 GNUNET_DISK_PERM_USER_WRITE |
423 GNUNET_DISK_PERM_USER_READ);
424 if (NULL == fh)
425 {
426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427 _("Unable to initialize file: %s.\n"),
428 plugin->fn);
429 return;
430 }
431
432 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
433 &store_and_free_entries,
434 fh);
435 GNUNET_CONTAINER_multihashmap_destroy (plugin->hm);
436 /* append 0-terminator */
437 GNUNET_DISK_file_write (fh,
438 "",
439 1);
440 GNUNET_DISK_file_close (fh);
441}
442
443
444/**
445 * Store a record in the datastore. Removes any existing record in the
446 * same zone with the same name.
447 *
448 * @param cls closure (internal context for the plugin)
449 * @param zone_key private key of the zone
450 * @param label name that is being mapped (at most 255 characters long)
451 * @param rd_count number of entries in @a rd array
452 * @param rd array of records with data to store
453 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
454 */
455static int
456namestore_flat_store_records (void *cls,
457 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
458 const char *label,
459 unsigned int rd_count,
460 const struct GNUNET_GNSRECORD_Data *rd)
461{
462 struct Plugin *plugin = cls;
463 uint64_t rvalue;
464 struct GNUNET_HashCode hkey;
465 struct FlatFileEntry *entry;
466
467 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
468 UINT64_MAX);
469 hash_pkey_and_label (zone_key,
470 label,
471 &hkey);
472 GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
473 &hkey);
474 if (0 == rd_count)
475 {
476 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
477 "sqlite",
478 "Record deleted\n");
479 return GNUNET_OK;
480 }
481 entry = GNUNET_new (struct FlatFileEntry);
482 GNUNET_asprintf (&entry->label,
483 label,
484 strlen (label));
485 GNUNET_memcpy (&entry->private_key,
486 zone_key,
487 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
488 entry->rvalue = rvalue;
489 entry->record_count = rd_count;
490 entry->record_data = GNUNET_new_array (rd_count,
491 struct GNUNET_GNSRECORD_Data);
492 for (unsigned int i = 0; i < rd_count; i++)
493 {
494 entry->record_data[i].expiration_time = rd[i].expiration_time;
495 entry->record_data[i].record_type = rd[i].record_type;
496 entry->record_data[i].flags = rd[i].flags;
497 entry->record_data[i].data_size = rd[i].data_size;
498 entry->record_data[i].data = GNUNET_malloc (rd[i].data_size);
499 GNUNET_memcpy ((char*)entry->record_data[i].data,
500 rd[i].data,
501 rd[i].data_size);
502 }
503 return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
504 &hkey,
505 entry,
506 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
507}
508
509
510/**
511 * Lookup records in the datastore for which we are the authority.
512 *
513 * @param cls closure (internal context for the plugin)
514 * @param zone private key of the zone
515 * @param label name of the record in the zone
516 * @param iter function to call with the result
517 * @param iter_cls closure for @a iter
518 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
519 */
520static int
521namestore_flat_lookup_records (void *cls,
522 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
523 const char *label,
524 GNUNET_NAMESTORE_RecordIterator iter,
525 void *iter_cls)
526{
527 struct Plugin *plugin = cls;
528 struct FlatFileEntry *entry;
529 struct GNUNET_HashCode hkey;
530
531 if (NULL == zone)
532 {
533 GNUNET_break (0);
534 return GNUNET_SYSERR;
535 }
536 hash_pkey_and_label (zone,
537 label,
538 &hkey);
539 entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
540 &hkey);
541
542 if (NULL == entry)
543 return GNUNET_NO;
544 if (NULL != iter)
545 iter (iter_cls,
546 1, /* zero is illegal */
547 &entry->private_key,
548 entry->label,
549 entry->record_count,
550 entry->record_data);
551 return GNUNET_YES;
552}
553
554
555/**
556 * Closure for #iterate_zones.
557 */
558struct IterateContext
559{
560 /**
561 * How many more records should we skip before returning results?
562 */
563 uint64_t offset;
564
565 /**
566 * How many more records should we return?
567 */
568 uint64_t limit;
569
570 /**
571 * What is the position of the current entry, counting
572 * starts from 1.
573 */
574 uint64_t pos;
575
576 /**
577 * Target zone.
578 */
579 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
580
581 /**
582 * Function to call on each record.
583 */
584 GNUNET_NAMESTORE_RecordIterator iter;
585
586 /**
587 * Closure for @e iter.
588 */
589 void *iter_cls;
590
591};
592
593
594/**
595 * Helper function for #namestore_flat_iterate_records().
596 *
597 * @param cls a `struct IterateContext`
598 * @param key unused
599 * @param value a `struct FlatFileEntry`
600 * @return #GNUNET_YES to continue the iteration
601 */
602static int
603iterate_zones (void *cls,
604 const struct GNUNET_HashCode *key,
605 void *value)
606{
607 struct IterateContext *ic = cls;
608 struct FlatFileEntry *entry = value;
609
610 (void) key;
611 if (0 == ic->limit)
612 return GNUNET_NO;
613 if ( (NULL != ic->zone) &&
614 (0 != GNUNET_memcmp (&entry->private_key,
615 ic->zone)) )
616 return GNUNET_YES;
617 ic->pos++;
618 if (ic->offset > 0)
619 {
620 ic->offset--;
621 return GNUNET_YES;
622 }
623 ic->iter (ic->iter_cls,
624 ic->pos,
625 (NULL == ic->zone)
626 ? &entry->private_key
627 : ic->zone,
628 entry->label,
629 entry->record_count,
630 entry->record_data);
631 ic->limit--;
632 if (0 == ic->limit)
633 return GNUNET_NO;
634 return GNUNET_YES;
635}
636
637
638/**
639 * Iterate over the results for a particular key and zone in the
640 * datastore. Will return at most one result to the iterator.
641 *
642 * @param cls closure (internal context for the plugin)
643 * @param zone hash of public key of the zone, NULL to iterate over all zones
644 * @param serial serial number to exclude in the list of all matching records
645 * @param limit maximum number of results to return to @a iter
646 * @param iter function to call with the result
647 * @param iter_cls closure for @a iter
648 * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
649 */
650static int
651namestore_flat_iterate_records (void *cls,
652 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
653 uint64_t serial,
654 uint64_t limit,
655 GNUNET_NAMESTORE_RecordIterator iter,
656 void *iter_cls)
657{
658 struct Plugin *plugin = cls;
659 struct IterateContext ic;
660
661 ic.offset = serial;
662 ic.pos = 0;
663 ic.limit = limit;
664 ic.iter = iter;
665 ic.iter_cls = iter_cls;
666 ic.zone = zone;
667 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
668 &iterate_zones,
669 &ic);
670 return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO;
671}
672
673
674/**
675 * Closure for #zone_to_name.
676 */
677struct ZoneToNameContext
678{
679 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
680 const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone;
681 GNUNET_NAMESTORE_RecordIterator iter;
682 void *iter_cls;
683
684 int result_found;
685};
686
687
688static int
689zone_to_name (void *cls,
690 const struct GNUNET_HashCode *key,
691 void *value)
692{
693 struct ZoneToNameContext *ztn = cls;
694 struct FlatFileEntry *entry = value;
695
696 (void) key;
697 if (0 != GNUNET_memcmp (&entry->private_key,
698 ztn->zone))
699 return GNUNET_YES;
700
701 for (unsigned int i = 0; i < entry->record_count; i++)
702 {
703 if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type)
704 continue;
705 if (0 == memcmp (ztn->value_zone,
706 entry->record_data[i].data,
707 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
708 {
709 ztn->iter (ztn->iter_cls,
710 i + 1, /* zero is illegal! */
711 &entry->private_key,
712 entry->label,
713 entry->record_count,
714 entry->record_data);
715 ztn->result_found = GNUNET_YES;
716 }
717 }
718 return GNUNET_YES;
719}
720
721
722/**
723 * Look for an existing PKEY delegation record for a given public key.
724 * Returns at most one result to the iterator.
725 *
726 * @param cls closure (internal context for the plugin)
727 * @param zone private key of the zone to look up in, never NULL
728 * @param value_zone public key of the target zone (value), never NULL
729 * @param iter function to call with the result
730 * @param iter_cls closure for @a iter
731 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
732 */
733static int
734namestore_flat_zone_to_name (void *cls,
735 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
736 const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
737 GNUNET_NAMESTORE_RecordIterator iter,
738 void *iter_cls)
739{
740 struct Plugin *plugin = cls;
741 struct ZoneToNameContext ztn = {
742 .iter = iter,
743 .iter_cls = iter_cls,
744 .zone = zone,
745 .value_zone = value_zone,
746 .result_found = GNUNET_NO
747 };
748
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750 "Performing reverse lookup for `%s'\n",
751 GNUNET_GNSRECORD_z2s (value_zone));
752 GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
753 &zone_to_name,
754 &ztn);
755 return ztn.result_found;
756}
757
758
759/**
760 * Entry point for the plugin.
761 *
762 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
763 * @return NULL on error, otherwise the plugin context
764 */
765void *
766libgnunet_plugin_namestore_flat_init (void *cls)
767{
768 static struct Plugin plugin;
769 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
770 struct GNUNET_NAMESTORE_PluginFunctions *api;
771
772 if (NULL != plugin.cfg)
773 return NULL; /* can only initialize once! */
774 memset (&plugin,
775 0,
776 sizeof (struct Plugin));
777 plugin.cfg = cfg;
778 if (GNUNET_OK != database_setup (&plugin))
779 {
780 database_shutdown (&plugin);
781 return NULL;
782 }
783 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
784 api->cls = &plugin;
785 api->store_records = &namestore_flat_store_records;
786 api->iterate_records = &namestore_flat_iterate_records;
787 api->zone_to_name = &namestore_flat_zone_to_name;
788 api->lookup_records = &namestore_flat_lookup_records;
789 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
790 _("Flat file database running\n"));
791 return api;
792}
793
794
795/**
796 * Exit point from the plugin.
797 *
798 * @param cls the plugin context (as returned by "init")
799 * @return always NULL
800 */
801void *
802libgnunet_plugin_namestore_flat_done (void *cls)
803{
804 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
805 struct Plugin *plugin = api->cls;
806
807 database_shutdown (plugin);
808 plugin->cfg = NULL;
809 GNUNET_free (api);
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Flat file plugin is finished\n");
812 return NULL;
813}
814
815/* end of plugin_namestore_flat.c */