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