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