add response headers, add replace api to namestore
[oweals/gnunet.git] / src / namestore / plugin_namestore_sqlite.c
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2009-2017 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 /**
22  * @file namestore/plugin_namestore_sqlite.c
23  * @brief sqlite-based namestore backend
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 "gnunet_sq_lib.h"
32 #include "namestore.h"
33 #include <sqlite3.h>
34
35 /**
36  * After how many ms "busy" should a DB operation fail for good?  A
37  * low value makes sure that we are more responsive to requests
38  * (especially PUTs).  A high value guarantees a higher success rate
39  * (SELECTs in iterate can take several seconds despite LIMIT=1).
40  *
41  * The default value of 1s should ensure that users do not experience
42  * huge latencies while at the same time allowing operations to
43  * succeed with reasonable probability.
44  */
45 #define BUSY_TIMEOUT_MS 1000
46
47
48 /**
49  * Log an error message at log-level 'level' that indicates
50  * a failure of the command 'cmd' on file 'filename'
51  * with the message given by strerror(errno).
52  */
53 #define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, \
54                                                          "namestore-sqlite", _ ( \
55                                                            "`%s' failed at %s:%d with error: %s\n"), \
56                                                          cmd, \
57                                                          __FILE__, __LINE__, \
58                                                          sqlite3_errmsg ( \
59                                                            db->dbh)); \
60 } while (0)
61
62 #define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
63
64
65 /**
66  * Context for all functions in this plugin.
67  */
68 struct Plugin
69 {
70   const struct GNUNET_CONFIGURATION_Handle *cfg;
71
72   /**
73    * Database filename.
74    */
75   char *fn;
76
77   /**
78    * Native SQLite database handle.
79    */
80   sqlite3 *dbh;
81
82   /**
83    * Precompiled SQL to store records.
84    */
85   sqlite3_stmt *store_records;
86
87   /**
88    * Precompiled SQL to deltete existing records.
89    */
90   sqlite3_stmt *delete_records;
91
92   /**
93    * Precompiled SQL for iterate records within a zone.
94    */
95   sqlite3_stmt *iterate_zone;
96
97   /**
98    * Precompiled SQL for iterate all records within all zones.
99    */
100   sqlite3_stmt *iterate_all_zones;
101
102   /**
103    * Precompiled SQL to for reverse lookup based on PKEY.
104    */
105   sqlite3_stmt *zone_to_name;
106
107   /**
108    * Precompiled SQL to lookup records based on label.
109    */
110   sqlite3_stmt *lookup_label;
111 };
112
113
114 /**
115  * Initialize the database connections and associated
116  * data structures (create tables and indices
117  * as needed as well).
118  *
119  * @param plugin the plugin context (state for this module)
120  * @return #GNUNET_OK on success
121  */
122 static int
123 database_setup (struct Plugin *plugin)
124 {
125   char *sqlite_filename;
126   struct GNUNET_SQ_ExecuteStatement es[] = {
127     GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
128     GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
129     GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
130     GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
131     GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
132     GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=EXCLUSIVE"),
133     GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
134     GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
135     GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
136                             " uid INTEGER PRIMARY KEY,"
137                             " zone_private_key BLOB NOT NULL,"
138                             " pkey BLOB,"
139                             " rvalue INT8 NOT NULL,"
140                             " record_count INT NOT NULL,"
141                             " record_data BLOB NOT NULL,"
142                             " label TEXT NOT NULL"
143                             ")"),
144     GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
145                                 "ON ns098records (zone_private_key,pkey)"),
146     GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
147                                 "ON ns098records (zone_private_key,uid)"),
148     GNUNET_SQ_EXECUTE_STATEMENT_END
149   };
150   struct GNUNET_SQ_PrepareStatement ps[] = {
151     GNUNET_SQ_make_prepare ("INSERT INTO ns098records "
152                             "(zone_private_key,pkey,rvalue,record_count,record_data,label)"
153                             " VALUES (?, ?, ?, ?, ?, ?)",
154                             &plugin->store_records),
155     GNUNET_SQ_make_prepare ("DELETE FROM ns098records "
156                             "WHERE zone_private_key=? AND label=?",
157                             &plugin->delete_records),
158     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
159                             " FROM ns098records"
160                             " WHERE zone_private_key=? AND pkey=?",
161                             &plugin->zone_to_name),
162     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
163                             " FROM ns098records"
164                             " WHERE zone_private_key=? AND uid > ?"
165                             " ORDER BY uid ASC"
166                             " LIMIT ?",
167                             &plugin->iterate_zone),
168     GNUNET_SQ_make_prepare (
169       "SELECT uid,record_count,record_data,label,zone_private_key"
170       " FROM ns098records"
171       " WHERE uid > ?"
172       " ORDER BY uid ASC"
173       " LIMIT ?",
174       &plugin->iterate_all_zones),
175     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
176                             " FROM ns098records"
177                             " WHERE zone_private_key=? AND label=?",
178                             &plugin->lookup_label),
179     GNUNET_SQ_PREPARE_END
180   };
181
182   if (GNUNET_OK !=
183       GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
184                                                "namestore-sqlite",
185                                                "FILENAME",
186                                                &sqlite_filename))
187   {
188     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
189                                "namestore-sqlite",
190                                "FILENAME");
191     return GNUNET_SYSERR;
192   }
193   if (GNUNET_OK !=
194       GNUNET_DISK_file_test (sqlite_filename))
195   {
196     if (GNUNET_OK !=
197         GNUNET_DISK_directory_create_for_file (sqlite_filename))
198     {
199       GNUNET_break (0);
200       GNUNET_free (sqlite_filename);
201       return GNUNET_SYSERR;
202     }
203   }
204   /* sqlite_filename should be UTF-8-encoded. If it isn't, it's a bug */
205   plugin->fn = sqlite_filename;
206
207   /* Open database and precompile statements */
208   if (SQLITE_OK !=
209       sqlite3_open (plugin->fn,
210                     &plugin->dbh))
211   {
212     LOG (GNUNET_ERROR_TYPE_ERROR,
213          _ ("Unable to initialize SQLite: %s.\n"),
214          sqlite3_errmsg (plugin->dbh));
215     return GNUNET_SYSERR;
216   }
217   GNUNET_break (SQLITE_OK ==
218                 sqlite3_busy_timeout (plugin->dbh,
219                                       BUSY_TIMEOUT_MS));
220   if (GNUNET_OK !=
221       GNUNET_SQ_exec_statements (plugin->dbh,
222                                  es))
223   {
224     GNUNET_break (0);
225     LOG (GNUNET_ERROR_TYPE_ERROR,
226          _ ("Failed to setup database at `%s'\n"),
227          plugin->fn);
228     return GNUNET_SYSERR;
229   }
230
231   if (GNUNET_OK !=
232       GNUNET_SQ_prepare (plugin->dbh,
233                          ps))
234   {
235     GNUNET_break (0);
236     LOG (GNUNET_ERROR_TYPE_ERROR,
237          _ ("Failed to setup database at `%s'\n"),
238          plugin->fn);
239     return GNUNET_SYSERR;
240   }
241   return GNUNET_OK;
242 }
243
244
245 /**
246  * Shutdown database connection and associate data
247  * structures.
248  * @param plugin the plugin context (state for this module)
249  */
250 static void
251 database_shutdown (struct Plugin *plugin)
252 {
253   int result;
254   sqlite3_stmt *stmt;
255
256   if (NULL != plugin->store_records)
257     sqlite3_finalize (plugin->store_records);
258   if (NULL != plugin->delete_records)
259     sqlite3_finalize (plugin->delete_records);
260   if (NULL != plugin->iterate_zone)
261     sqlite3_finalize (plugin->iterate_zone);
262   if (NULL != plugin->iterate_all_zones)
263     sqlite3_finalize (plugin->iterate_all_zones);
264   if (NULL != plugin->zone_to_name)
265     sqlite3_finalize (plugin->zone_to_name);
266   if (NULL != plugin->lookup_label)
267     sqlite3_finalize (plugin->lookup_label);
268   result = sqlite3_close (plugin->dbh);
269   if (result == SQLITE_BUSY)
270   {
271     LOG (GNUNET_ERROR_TYPE_WARNING,
272          _ (
273            "Tried to close sqlite without finalizing all prepared statements.\n"));
274     stmt = sqlite3_next_stmt (plugin->dbh,
275                               NULL);
276     while (NULL != stmt)
277     {
278       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
279                        "sqlite",
280                        "Closing statement %p\n",
281                        stmt);
282       result = sqlite3_finalize (stmt);
283       if (result != SQLITE_OK)
284         GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
285                          "sqlite",
286                          "Failed to close statement %p: %d\n",
287                          stmt,
288                          result);
289       stmt = sqlite3_next_stmt (plugin->dbh,
290                                 NULL);
291     }
292     result = sqlite3_close (plugin->dbh);
293   }
294   if (SQLITE_OK != result)
295     LOG_SQLITE (plugin,
296                 GNUNET_ERROR_TYPE_ERROR,
297                 "sqlite3_close");
298
299   GNUNET_free_non_null (plugin->fn);
300 }
301
302
303 /**
304  * Store a record in the datastore.  Removes any existing record in the
305  * same zone with the same name.
306  *
307  * @param cls closure (internal context for the plugin)
308  * @param zone_key private key of the zone
309  * @param label name that is being mapped (at most 255 characters long)
310  * @param rd_count number of entries in @a rd array
311  * @param rd array of records with data to store
312  * @return #GNUNET_OK on success, else #GNUNET_SYSERR
313  */
314 static int
315 namestore_sqlite_store_records (void *cls,
316                                 const struct
317                                 GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
318                                 const char *label,
319                                 unsigned int rd_count,
320                                 const struct GNUNET_GNSRECORD_Data *rd)
321 {
322   struct Plugin *plugin = cls;
323   int n;
324   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
325   uint64_t rvalue;
326   ssize_t data_size;
327
328   memset (&pkey,
329           0,
330           sizeof(pkey));
331   for (unsigned int i = 0; i < rd_count; i++)
332     if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
333     {
334       GNUNET_break (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) ==
335                     rd[i].data_size);
336       GNUNET_memcpy (&pkey,
337                      rd[i].data,
338                      rd[i].data_size);
339       break;
340     }
341   rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
342                                      UINT64_MAX);
343   data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
344                                                  rd);
345   if (data_size < 0)
346   {
347     GNUNET_break (0);
348     return GNUNET_SYSERR;
349   }
350   if (data_size > 64 * 65536)
351   {
352     GNUNET_break (0);
353     return GNUNET_SYSERR;
354   }
355   {
356     /* First delete 'old' records */
357     char data[data_size];
358     struct GNUNET_SQ_QueryParam dparams[] = {
359       GNUNET_SQ_query_param_auto_from_type (zone_key),
360       GNUNET_SQ_query_param_string (label),
361       GNUNET_SQ_query_param_end
362     };
363     ssize_t ret;
364
365     ret = GNUNET_GNSRECORD_records_serialize (rd_count,
366                                               rd,
367                                               data_size,
368                                               data);
369     if ((ret < 0) ||
370         (data_size != ret))
371     {
372       GNUNET_break (0);
373       return GNUNET_SYSERR;
374     }
375     if (GNUNET_OK !=
376         GNUNET_SQ_bind (plugin->delete_records,
377                         dparams))
378     {
379       LOG_SQLITE (plugin,
380                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
381                   "sqlite3_bind_XXXX");
382       GNUNET_SQ_reset (plugin->dbh,
383                        plugin->delete_records);
384       return GNUNET_SYSERR;
385     }
386     n = sqlite3_step (plugin->delete_records);
387     GNUNET_SQ_reset (plugin->dbh,
388                      plugin->delete_records);
389
390     if (0 != rd_count)
391     {
392       uint32_t rd_count32 = (uint32_t) rd_count;
393       struct GNUNET_SQ_QueryParam sparams[] = {
394         GNUNET_SQ_query_param_auto_from_type (zone_key),
395         GNUNET_SQ_query_param_auto_from_type (&pkey),
396         GNUNET_SQ_query_param_uint64 (&rvalue),
397         GNUNET_SQ_query_param_uint32 (&rd_count32),
398         GNUNET_SQ_query_param_fixed_size (data, data_size),
399         GNUNET_SQ_query_param_string (label),
400         GNUNET_SQ_query_param_end
401       };
402
403       if (GNUNET_OK !=
404           GNUNET_SQ_bind (plugin->store_records,
405                           sparams))
406       {
407         LOG_SQLITE (plugin,
408                     GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
409                     "sqlite3_bind_XXXX");
410         GNUNET_SQ_reset (plugin->dbh,
411                          plugin->store_records);
412         return GNUNET_SYSERR;
413       }
414       n = sqlite3_step (plugin->store_records);
415       GNUNET_SQ_reset (plugin->dbh,
416                        plugin->store_records);
417     }
418   }
419   switch (n)
420   {
421   case SQLITE_DONE:
422     if (0 != rd_count)
423       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
424                        "sqlite",
425                        "Record stored\n");
426     else
427       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
428                        "sqlite",
429                        "Record deleted\n");
430     return GNUNET_OK;
431
432   case SQLITE_BUSY:
433     LOG_SQLITE (plugin,
434                 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
435                 "sqlite3_step");
436     return GNUNET_NO;
437
438   default:
439     LOG_SQLITE (plugin,
440                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
441                 "sqlite3_step");
442     return GNUNET_SYSERR;
443   }
444 }
445
446
447 /**
448  * The given 'sqlite' statement has been prepared to be run.
449  * It will return a record which should be given to the iterator.
450  * Runs the statement and parses the returned record.
451  *
452  * @param plugin plugin context
453  * @param stmt to run (and then clean up)
454  * @param zone_key private key of the zone
455  * @param limit maximum number of results to fetch
456  * @param iter iterator to call with the result
457  * @param iter_cls closure for @a iter
458  * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
459  */
460 static int
461 get_records_and_call_iterator (struct Plugin *plugin,
462                                sqlite3_stmt *stmt,
463                                const struct
464                                GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
465                                uint64_t limit,
466                                GNUNET_NAMESTORE_RecordIterator iter,
467                                void *iter_cls)
468 {
469   int ret;
470   int sret;
471
472   ret = GNUNET_OK;
473   for (uint64_t i = 0; i < limit; i++)
474   {
475     sret = sqlite3_step (stmt);
476
477     if (SQLITE_DONE == sret)
478     {
479       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
480                   "Iteration done (no results)\n");
481       ret = GNUNET_NO;
482       break;
483     }
484     if (SQLITE_ROW != sret)
485     {
486       LOG_SQLITE (plugin,
487                   GNUNET_ERROR_TYPE_ERROR,
488                   "sqlite_step");
489       ret = GNUNET_SYSERR;
490       break;
491     }
492
493     {
494       uint64_t seq;
495       uint32_t record_count;
496       size_t data_size;
497       void *data;
498       char *label;
499       struct GNUNET_CRYPTO_EcdsaPrivateKey zk;
500       struct GNUNET_SQ_ResultSpec rs[] = {
501         GNUNET_SQ_result_spec_uint64 (&seq),
502         GNUNET_SQ_result_spec_uint32 (&record_count),
503         GNUNET_SQ_result_spec_variable_size (&data,
504                                              &data_size),
505         GNUNET_SQ_result_spec_string (&label),
506         GNUNET_SQ_result_spec_end
507       };
508       struct GNUNET_SQ_ResultSpec rsx[] = {
509         GNUNET_SQ_result_spec_uint64 (&seq),
510         GNUNET_SQ_result_spec_uint32 (&record_count),
511         GNUNET_SQ_result_spec_variable_size (&data,
512                                              &data_size),
513         GNUNET_SQ_result_spec_string (&label),
514         GNUNET_SQ_result_spec_auto_from_type (&zk),
515         GNUNET_SQ_result_spec_end
516       };
517
518       ret = GNUNET_SQ_extract_result (stmt,
519                                       (NULL == zone_key)
520                                       ? rsx
521                                       : rs);
522       if ((GNUNET_OK != ret) ||
523           (record_count > 64 * 1024))
524       {
525         /* sanity check, don't stack allocate far too much just
526            because database might contain a large value here */
527         GNUNET_break (0);
528         ret = GNUNET_SYSERR;
529         break;
530       }
531       else
532       {
533         struct GNUNET_GNSRECORD_Data rd[record_count];
534
535         GNUNET_assert (0 != seq);
536         if (GNUNET_OK !=
537             GNUNET_GNSRECORD_records_deserialize (data_size,
538                                                   data,
539                                                   record_count,
540                                                   rd))
541         {
542           GNUNET_break (0);
543           ret = GNUNET_SYSERR;
544           break;
545         }
546         else
547         {
548           if (NULL != zone_key)
549             zk = *zone_key;
550           if (NULL != iter)
551             iter (iter_cls,
552                   seq,
553                   &zk,
554                   label,
555                   record_count,
556                   rd);
557         }
558       }
559       GNUNET_SQ_cleanup_result (rs);
560     }
561   }
562   GNUNET_SQ_reset (plugin->dbh,
563                    stmt);
564   return ret;
565 }
566
567
568 /**
569  * Lookup records in the datastore for which we are the authority.
570  *
571  * @param cls closure (internal context for the plugin)
572  * @param zone private key of the zone
573  * @param label name of the record in the zone
574  * @param iter function to call with the result
575  * @param iter_cls closure for @a iter
576  * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
577  */
578 static int
579 namestore_sqlite_lookup_records (void *cls,
580                                  const struct
581                                  GNUNET_CRYPTO_EcdsaPrivateKey *zone,
582                                  const char *label,
583                                  GNUNET_NAMESTORE_RecordIterator iter,
584                                  void *iter_cls)
585 {
586   struct Plugin *plugin = cls;
587   struct GNUNET_SQ_QueryParam params[] = {
588     GNUNET_SQ_query_param_auto_from_type (zone),
589     GNUNET_SQ_query_param_string (label),
590     GNUNET_SQ_query_param_end
591   };
592
593   if (NULL == zone)
594   {
595     GNUNET_break (0);
596     return GNUNET_SYSERR;
597   }
598   if (GNUNET_OK !=
599       GNUNET_SQ_bind (plugin->lookup_label,
600                       params))
601   {
602     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
603                 "sqlite3_bind_XXXX");
604     GNUNET_SQ_reset (plugin->dbh,
605                      plugin->lookup_label);
606     return GNUNET_SYSERR;
607   }
608   return get_records_and_call_iterator (plugin,
609                                         plugin->lookup_label,
610                                         zone,
611                                         1,
612                                         iter,
613                                         iter_cls);
614 }
615
616
617 /**
618  * Iterate over the results for a particular key and zone in the
619  * datastore.  Will return at most one result to the iterator.
620  *
621  * @param cls closure (internal context for the plugin)
622  * @param zone hash of public key of the zone, NULL to iterate over all zones
623  * @param serial serial number to exclude in the list of all matching records
624  * @param limit maximum number of results to return
625  * @param iter function to call with the result
626  * @param iter_cls closure for @a iter
627  * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
628  */
629 static int
630 namestore_sqlite_iterate_records (void *cls,
631                                   const struct
632                                   GNUNET_CRYPTO_EcdsaPrivateKey *zone,
633                                   uint64_t serial,
634                                   uint64_t limit,
635                                   GNUNET_NAMESTORE_RecordIterator iter,
636                                   void *iter_cls)
637 {
638   struct Plugin *plugin = cls;
639   sqlite3_stmt *stmt;
640   int err;
641
642   if (NULL == zone)
643   {
644     struct GNUNET_SQ_QueryParam params[] = {
645       GNUNET_SQ_query_param_uint64 (&serial),
646       GNUNET_SQ_query_param_uint64 (&limit),
647       GNUNET_SQ_query_param_end
648     };
649
650     stmt = plugin->iterate_all_zones;
651     err = GNUNET_SQ_bind (stmt,
652                           params);
653   }
654   else
655   {
656     struct GNUNET_SQ_QueryParam params[] = {
657       GNUNET_SQ_query_param_auto_from_type (zone),
658       GNUNET_SQ_query_param_uint64 (&serial),
659       GNUNET_SQ_query_param_uint64 (&limit),
660       GNUNET_SQ_query_param_end
661     };
662
663     stmt = plugin->iterate_zone;
664     err = GNUNET_SQ_bind (stmt,
665                           params);
666   }
667   if (GNUNET_OK != err)
668   {
669     LOG_SQLITE (plugin,
670                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
671                 "sqlite3_bind_XXXX");
672     GNUNET_SQ_reset (plugin->dbh,
673                      stmt);
674     return GNUNET_SYSERR;
675   }
676   return get_records_and_call_iterator (plugin,
677                                         stmt,
678                                         zone,
679                                         limit,
680                                         iter,
681                                         iter_cls);
682 }
683
684
685 /**
686  * Look for an existing PKEY delegation record for a given public key.
687  * Returns at most one result to the iterator.
688  *
689  * @param cls closure (internal context for the plugin)
690  * @param zone private key of the zone to look up in, never NULL
691  * @param value_zone public key of the target zone (value), never NULL
692  * @param iter function to call with the result
693  * @param iter_cls closure for @a iter
694  * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
695  */
696 static int
697 namestore_sqlite_zone_to_name (void *cls,
698                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
699                                const struct
700                                GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
701                                GNUNET_NAMESTORE_RecordIterator iter,
702                                void *iter_cls)
703 {
704   struct Plugin *plugin = cls;
705   struct GNUNET_SQ_QueryParam params[] = {
706     GNUNET_SQ_query_param_auto_from_type (zone),
707     GNUNET_SQ_query_param_auto_from_type (value_zone),
708     GNUNET_SQ_query_param_end
709   };
710
711   if (GNUNET_OK !=
712       GNUNET_SQ_bind (plugin->zone_to_name,
713                       params))
714   {
715     LOG_SQLITE (plugin,
716                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
717                 "sqlite3_bind_XXXX");
718     GNUNET_SQ_reset (plugin->dbh,
719                      plugin->zone_to_name);
720     return GNUNET_SYSERR;
721   }
722   LOG (GNUNET_ERROR_TYPE_DEBUG,
723        "Performing reverse lookup for `%s'\n",
724        GNUNET_GNSRECORD_z2s (value_zone));
725   return get_records_and_call_iterator (plugin,
726                                         plugin->zone_to_name,
727                                         zone,
728                                         1,
729                                         iter,
730                                         iter_cls);
731 }
732
733
734 /**
735  * Entry point for the plugin.
736  *
737  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
738  * @return NULL on error, otherwise the plugin context
739  */
740 void *
741 libgnunet_plugin_namestore_sqlite_init (void *cls)
742 {
743   static struct Plugin plugin;
744   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
745   struct GNUNET_NAMESTORE_PluginFunctions *api;
746
747   if (NULL != plugin.cfg)
748     return NULL;                /* can only initialize once! */
749   memset (&plugin,
750           0,
751           sizeof(struct Plugin));
752   plugin.cfg = cfg;
753   if (GNUNET_OK != database_setup (&plugin))
754   {
755     database_shutdown (&plugin);
756     return NULL;
757   }
758   api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
759   api->cls = &plugin;
760   api->store_records = &namestore_sqlite_store_records;
761   api->iterate_records = &namestore_sqlite_iterate_records;
762   api->zone_to_name = &namestore_sqlite_zone_to_name;
763   api->lookup_records = &namestore_sqlite_lookup_records;
764   LOG (GNUNET_ERROR_TYPE_INFO,
765        _ ("Sqlite database running\n"));
766   return api;
767 }
768
769
770 /**
771  * Exit point from the plugin.
772  *
773  * @param cls the plugin context (as returned by "init")
774  * @return always NULL
775  */
776 void *
777 libgnunet_plugin_namestore_sqlite_done (void *cls)
778 {
779   struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
780   struct Plugin *plugin = api->cls;
781
782   database_shutdown (plugin);
783   plugin->cfg = NULL;
784   GNUNET_free (api);
785   LOG (GNUNET_ERROR_TYPE_DEBUG,
786        "sqlite plugin is finished\n");
787   return NULL;
788 }
789
790
791 /* end of plugin_namestore_sqlite.c */