Merge branch 'master' of gnunet.org:gnunet
[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
6   * it under the terms of the GNU General Public License as published
7   * by the Free Software Foundation; either version 3, or (at your
8   * 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   * General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with GNUnet; see the file COPYING.  If not, write to the
17   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18   * Boston, MA 02110-1301, USA.
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, "namestore-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
54
55 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
56
57
58 /**
59  * Context for all functions in this plugin.
60  */
61 struct Plugin
62 {
63
64   const struct GNUNET_CONFIGURATION_Handle *cfg;
65
66   /**
67    * Database filename.
68    */
69   char *fn;
70
71   /**
72    * Native SQLite database handle.
73    */
74   sqlite3 *dbh;
75
76   /**
77    * Precompiled SQL to store records.
78    */
79   sqlite3_stmt *store_records;
80
81   /**
82    * Precompiled SQL to deltete existing records.
83    */
84   sqlite3_stmt *delete_records;
85
86   /**
87    * Precompiled SQL for iterate records within a zone.
88    */
89   sqlite3_stmt *iterate_zone;
90
91   /**
92    * Precompiled SQL for iterate all records within all zones.
93    */
94   sqlite3_stmt *iterate_all_zones;
95
96   /**
97    * Precompiled SQL to for reverse lookup based on PKEY.
98    */
99   sqlite3_stmt *zone_to_name;
100
101   /**
102    * Precompiled SQL to lookup records based on label.
103    */
104   sqlite3_stmt *lookup_label;
105 };
106
107
108 /**
109  * Initialize the database connections and associated
110  * data structures (create tables and indices
111  * as needed as well).
112  *
113  * @param plugin the plugin context (state for this module)
114  * @return #GNUNET_OK on success
115  */
116 static int
117 database_setup (struct Plugin *plugin)
118 {
119   char *sqlite_filename;
120   struct GNUNET_SQ_ExecuteStatement es[] = {
121     GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
122     GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
123     GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
124     GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
125     GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
126     GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=EXCLUSIVE"),
127     GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
128     GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
129                             " uid INTEGER PRIMARY KEY,"
130                             " zone_private_key BLOB NOT NULL,"
131                             " pkey BLOB,"
132                             " rvalue INT8 NOT NULL,"
133                             " record_count INT NOT NULL,"
134                             " record_data BLOB NOT NULL,"
135                             " label TEXT NOT NULL"
136                             ")"),
137     GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
138                                 "ON ns098records (zone_private_key,pkey)"),
139     GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
140                                 "ON ns098records (zone_private_key,uid)"),
141     GNUNET_SQ_EXECUTE_STATEMENT_END
142   };
143   struct GNUNET_SQ_PrepareStatement ps[] = {
144     GNUNET_SQ_make_prepare ("INSERT INTO ns098records "
145                             "(zone_private_key,pkey,rvalue,record_count,record_data,label)"
146                             " VALUES (?, ?, ?, ?, ?, ?)",
147                             &plugin->store_records),
148     GNUNET_SQ_make_prepare ("DELETE FROM ns098records "
149                             "WHERE zone_private_key=? AND label=?",
150                             &plugin->delete_records),
151     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
152                             " FROM ns098records"
153                             " WHERE zone_private_key=? AND pkey=?",
154                             &plugin->zone_to_name),
155     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
156                             " FROM ns098records"
157                             " WHERE zone_private_key=? AND _rowid_ >= ?"
158                             " ORDER BY _rowid_ ASC"
159                             " LIMIT ?",
160                             &plugin->iterate_zone),
161     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,zone_private_key"
162                             " FROM ns098records"
163                             " WHERE _rowid_ >= ?"
164                             " ORDER BY _rowid_ ASC"
165                             " LIMIT ?",
166                             &plugin->iterate_all_zones),
167     GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,zone_private_key"
168                             " FROM ns098records"
169                             " WHERE zone_private_key=? AND label=?",
170                             &plugin->lookup_label),
171     GNUNET_SQ_PREPARE_END
172   };
173
174   if (GNUNET_OK !=
175       GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
176                                                "namestore-sqlite",
177                                                "FILENAME",
178                                                &sqlite_filename))
179   {
180     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
181                                "namestore-sqlite",
182                                "FILENAME");
183     return GNUNET_SYSERR;
184   }
185   if (GNUNET_OK !=
186       GNUNET_DISK_file_test (sqlite_filename))
187   {
188     if (GNUNET_OK !=
189         GNUNET_DISK_directory_create_for_file (sqlite_filename))
190     {
191       GNUNET_break (0);
192       GNUNET_free (sqlite_filename);
193       return GNUNET_SYSERR;
194     }
195   }
196   /* sqlite_filename should be UTF-8-encoded. If it isn't, it's a bug */
197   plugin->fn = sqlite_filename;
198
199   /* Open database and precompile statements */
200   if (SQLITE_OK !=
201       sqlite3_open (plugin->fn,
202                     &plugin->dbh))
203   {
204     LOG (GNUNET_ERROR_TYPE_ERROR,
205          _("Unable to initialize SQLite: %s.\n"),
206          sqlite3_errmsg (plugin->dbh));
207     return GNUNET_SYSERR;
208   }
209   GNUNET_break (SQLITE_OK ==
210                 sqlite3_busy_timeout (plugin->dbh,
211                                       BUSY_TIMEOUT_MS));
212   if (GNUNET_OK !=
213       GNUNET_SQ_exec_statements (plugin->dbh,
214                                  es))
215   {
216     GNUNET_break (0);
217     LOG (GNUNET_ERROR_TYPE_ERROR,
218          _("Failed to setup database at `%s'\n"),
219          plugin->fn);
220     return GNUNET_SYSERR;
221   }
222
223   if (GNUNET_OK !=
224       GNUNET_SQ_prepare (plugin->dbh,
225                          ps))
226   {
227     GNUNET_break (0);
228     LOG (GNUNET_ERROR_TYPE_ERROR,
229          _("Failed to setup database at `%s'\n"),
230          plugin->fn);
231     return GNUNET_SYSERR;
232   }
233   return GNUNET_OK;
234 }
235
236
237 /**
238  * Shutdown database connection and associate data
239  * structures.
240  * @param plugin the plugin context (state for this module)
241  */
242 static void
243 database_shutdown (struct Plugin *plugin)
244 {
245   int result;
246   sqlite3_stmt *stmt;
247
248   if (NULL != plugin->store_records)
249     sqlite3_finalize (plugin->store_records);
250   if (NULL != plugin->delete_records)
251     sqlite3_finalize (plugin->delete_records);
252   if (NULL != plugin->iterate_zone)
253     sqlite3_finalize (plugin->iterate_zone);
254   if (NULL != plugin->iterate_all_zones)
255     sqlite3_finalize (plugin->iterate_all_zones);
256   if (NULL != plugin->zone_to_name)
257     sqlite3_finalize (plugin->zone_to_name);
258   if (NULL != plugin->lookup_label)
259     sqlite3_finalize (plugin->lookup_label);
260   result = sqlite3_close (plugin->dbh);
261   if (result == SQLITE_BUSY)
262   {
263     LOG (GNUNET_ERROR_TYPE_WARNING,
264          _("Tried to close sqlite without finalizing all prepared statements.\n"));
265     stmt = sqlite3_next_stmt (plugin->dbh,
266                               NULL);
267     while (NULL != stmt)
268     {
269       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
270                        "sqlite",
271                        "Closing statement %p\n",
272                        stmt);
273       result = sqlite3_finalize (stmt);
274       if (result != SQLITE_OK)
275         GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
276                          "sqlite",
277                          "Failed to close statement %p: %d\n",
278                          stmt,
279                          result);
280       stmt = sqlite3_next_stmt (plugin->dbh,
281                                 NULL);
282     }
283     result = sqlite3_close (plugin->dbh);
284   }
285   if (SQLITE_OK != result)
286     LOG_SQLITE (plugin,
287                 GNUNET_ERROR_TYPE_ERROR,
288                 "sqlite3_close");
289
290   GNUNET_free_non_null (plugin->fn);
291 }
292
293
294 /**
295  * Store a record in the datastore.  Removes any existing record in the
296  * same zone with the same name.
297  *
298  * @param cls closure (internal context for the plugin)
299  * @param zone_key private key of the zone
300  * @param label name that is being mapped (at most 255 characters long)
301  * @param rd_count number of entries in @a rd array
302  * @param rd array of records with data to store
303  * @return #GNUNET_OK on success, else #GNUNET_SYSERR
304  */
305 static int
306 namestore_sqlite_store_records (void *cls,
307                                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
308                                 const char *label,
309                                 unsigned int rd_count,
310                                 const struct GNUNET_GNSRECORD_Data *rd)
311 {
312   struct Plugin *plugin = cls;
313   int n;
314   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
315   uint64_t rvalue;
316   size_t data_size;
317
318   memset (&pkey,
319           0,
320           sizeof (pkey));
321   for (unsigned int i=0;i<rd_count;i++)
322     if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
323     {
324       GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) ==
325                     rd[i].data_size);
326       GNUNET_memcpy (&pkey,
327                      rd[i].data,
328                      rd[i].data_size);
329       break;
330     }
331   rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
332                                      UINT64_MAX);
333   data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
334                                                  rd);
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 != (size_t) 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 */