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