c1d5d3ca84840c78fed20a1ff41e67858a1273fe
[oweals/gnunet.git] / src / namestore / plugin_namestore_sqlite.c
1  /*
2   * This file is part of GNUnet
3   * (C) 2009, 2011, 2012 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 <sqlite3.h>
30
31 /**
32  * After how many ms "busy" should a DB operation fail for good?
33  * A low value makes sure that we are more responsive to requests
34  * (especially PUTs).  A high value guarantees a higher success
35  * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
36  *
37  * The default value of 1s should ensure that users do not experience
38  * huge latencies while at the same time allowing operations to succeed
39  * with reasonable probability.
40  */
41 #define BUSY_TIMEOUT_MS 1000
42
43
44 /**
45  * Log an error message at log-level 'level' that indicates
46  * a failure of the command 'cmd' on file 'filename'
47  * with the message given by strerror(errno).
48  */
49 #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)
50
51 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
52
53
54 /**
55  * Context for all functions in this plugin.
56  */
57 struct Plugin
58 {
59
60   const struct GNUNET_CONFIGURATION_Handle *cfg;
61
62   /**
63    * Database filename.
64    */
65   char *fn;
66
67   /**
68    * Native SQLite database handle.
69    */
70   sqlite3 *dbh;
71
72   /**
73    * Precompiled SQL for put record
74    */
75   sqlite3_stmt *put_record;
76
77   /**
78    * Precompiled SQL for put node
79    */
80   sqlite3_stmt *put_node;
81
82   /**
83    * Precompiled SQL for put signature
84    */
85   sqlite3_stmt *put_signature;
86
87   /**
88    * Precompiled SQL for iterate records
89    */
90   sqlite3_stmt *iterate_records;
91
92   /**
93    * Precompiled SQL for get node
94    */
95   sqlite3_stmt *get_node;
96
97   /**
98    * Precompiled SQL for get signature
99    */
100   sqlite3_stmt *get_signature;
101
102   /**
103    * Precompiled SQL for delete zone
104    */
105   sqlite3_stmt *delete_zone_records;
106
107   /**
108    * Precompiled SQL for delete zone
109    */
110   sqlite3_stmt *delete_zone_nodes;
111
112   /**
113    * Precompiled SQL for delete zone
114    */
115   sqlite3_stmt *delete_zone_signatures;
116
117 };
118
119
120 /**
121  * @brief Prepare a SQL statement
122  *
123  * @param dbh handle to the database
124  * @param zSql SQL statement, UTF-8 encoded
125  * @param ppStmt set to the prepared statement
126  * @return 0 on success
127  */
128 static int
129 sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt)
130 {
131   char *dummy;
132   int result;
133
134   result =
135       sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
136                           (const char **) &dummy);
137   LOG (GNUNET_ERROR_TYPE_DEBUG, 
138        "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
139   return result;
140 }
141
142
143 /**
144  * Create our database indices.
145  *
146  * @param dbh handle to the database
147  */
148 static void
149 create_indices (sqlite3 * dbh)
150 {
151   /* create indices */
152   if (SQLITE_OK !=
153       sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_name_hash ON ns090records (zone_hash,record_name_hash)",
154                     NULL, NULL, NULL))
155     LOG (GNUNET_ERROR_TYPE_ERROR, 
156          "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
157
158
159   if (SQLITE_OK !=
160       sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS in_zone_location ON ns090nodes (zone_hash,zone_revision,node_location_depth,node_location_offset DESC)",
161                     NULL, NULL, NULL))
162     LOG (GNUNET_ERROR_TYPE_ERROR, 
163          "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
164
165
166   if (SQLITE_OK !=
167       sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS is_zone ON ns090signatures (zone_hash)",
168                     NULL, NULL, NULL))
169     LOG (GNUNET_ERROR_TYPE_ERROR, 
170          "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
171 }
172
173
174 #if 0
175 #define CHECK(a) GNUNET_break(a)
176 #define ENULL NULL
177 #else
178 #define ENULL &e
179 #define ENULL_DEFINED 1
180 #define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); }
181 #endif
182
183
184 /**
185  * Initialize the database connections and associated
186  * data structures (create tables and indices
187  * as needed as well).
188  *
189  * @param plugin the plugin context (state for this module)
190  * @return GNUNET_OK on success
191  */
192 static int
193 database_setup (struct Plugin *plugin)
194 {
195   sqlite3_stmt *stmt;
196   char *afsdir;
197 #if ENULL_DEFINED
198   char *e;
199 #endif
200
201   if (GNUNET_OK !=
202       GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namestore-sqlite",
203                                                "FILENAME", &afsdir))
204     {
205     LOG (GNUNET_ERROR_TYPE_ERROR, 
206          _ ("Option `%s' in section `%s' missing in configuration!\n"),
207          "FILENAME", "namestore-sqlite");
208     return GNUNET_SYSERR;
209   }
210   if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
211   {
212     if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
213     {
214       GNUNET_break (0);
215       GNUNET_free (afsdir);
216       return GNUNET_SYSERR;
217     }
218   }
219 #ifdef ENABLE_NLS
220   plugin->fn =
221       GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET));
222 #else
223   plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8");       /* good luck */
224 #endif
225   GNUNET_free (afsdir);
226
227   /* Open database and precompile statements */
228   if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
229   {
230     LOG (GNUNET_ERROR_TYPE_ERROR,
231          _("Unable to initialize SQLite: %s.\n"),
232          sqlite3_errmsg (plugin->dbh));
233     return GNUNET_SYSERR;
234   }
235   CHECK (SQLITE_OK ==
236          sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL,
237                        ENULL));
238   CHECK (SQLITE_OK ==
239          sqlite3_exec (plugin->dbh, "PRAGMA synchronous=NORMAL", NULL, NULL,
240                        ENULL));
241   CHECK (SQLITE_OK ==
242          sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL,
243                        ENULL));
244   CHECK (SQLITE_OK ==
245          sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL,
246                        NULL, ENULL));
247   CHECK (SQLITE_OK ==
248          sqlite3_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"", NULL,
249                        NULL, ENULL));
250   CHECK (SQLITE_OK ==
251          sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
252                        ENULL));
253   CHECK (SQLITE_OK ==
254          sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL,
255                        ENULL));
256   CHECK (SQLITE_OK ==
257          sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL,
258                        ENULL));
259
260   CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
261
262
263   /* Create tables */
264   CHECK (SQLITE_OK ==
265          sq_prepare (plugin->dbh,
266                      "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns090records'",
267                      &stmt));
268   if ((sqlite3_step (stmt) == SQLITE_DONE) &&
269       (sqlite3_exec
270        (plugin->dbh,
271         "CREATE TABLE ns090records (" 
272         " zone_hash BLOB NOT NULL DEFAULT ''," 
273         " zone_revision INT4 NOT NULL DEFAULT 0," 
274         " record_name_hash BLOB NOT NULL DEFAULT ''," 
275         " record_name TEXT NOT NULL DEFAULT ''," 
276         " record_type INT4 NOT NULL DEFAULT 0,"
277         " node_location_depth INT4 NOT NULL DEFAULT 0," 
278         " node_location_offset INT8 NOT NULL DEFAULT 0," 
279         " record_expiration_time INT8 NOT NULL DEFAULT 0," 
280         " record_flags INT4 NOT NULL DEFAULT 0,"
281         " record_value BLOB NOT NULL DEFAULT ''"
282         ")", 
283         NULL, NULL, NULL) != SQLITE_OK))
284   {
285     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
286     sqlite3_finalize (stmt);
287     return GNUNET_SYSERR;
288   }
289   sqlite3_finalize (stmt);
290
291   CHECK (SQLITE_OK ==
292          sq_prepare (plugin->dbh,
293                      "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns090nodes'",
294                      &stmt));
295   if ((sqlite3_step (stmt) == SQLITE_DONE) &&
296       (sqlite3_exec
297        (plugin->dbh,
298         "CREATE TABLE ns090nodes (" 
299         " zone_hash BLOB NOT NULL DEFAULT ''," 
300         " zone_revision INT4 NOT NULL DEFAULT 0," 
301         " node_location_depth INT4 NOT NULL DEFAULT 0," 
302         " node_location_offset INT8 NOT NULL DEFAULT 0," 
303         " node_parent_offset INT8 NOT NULL DEFAULT 0," 
304         " node_hashcodes BLOB NOT NULL DEFAULT ''"
305         ")", 
306         NULL, NULL, NULL) != SQLITE_OK))
307   {
308     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
309     sqlite3_finalize (stmt);
310     return GNUNET_SYSERR;
311   }
312   sqlite3_finalize (stmt);
313
314
315   CHECK (SQLITE_OK ==
316          sq_prepare (plugin->dbh,
317                      "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns090signatures'",
318                      &stmt));
319   if ((sqlite3_step (stmt) == SQLITE_DONE) &&
320       (sqlite3_exec
321        (plugin->dbh,
322         "CREATE TABLE ns090signatures (" 
323         " zone_hash BLOB NOT NULL DEFAULT ''," 
324         " zone_revision INT4 NOT NULL DEFAULT 0," 
325         " zone_time INT8 NOT NULL DEFAULT 0," 
326         " zone_root_hash BLOB NOT NULL DEFAULT 0," 
327         " zone_root_depth INT4 NOT NULL DEFAULT 0," 
328         " zone_public_key BLOB NOT NULL DEFAULT 0," 
329         " zone_signature BLOB NOT NULL DEFAULT 0" 
330         ")", 
331         NULL, NULL, NULL) != SQLITE_OK))
332   {
333     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
334     sqlite3_finalize (stmt);
335     return GNUNET_SYSERR;
336   }
337   sqlite3_finalize (stmt);
338
339
340   create_indices (plugin->dbh);
341
342   if ((sq_prepare
343        (plugin->dbh,
344         "INSERT INTO ns090records (zone_hash, zone_revision, record_name_hash, record_name, "
345         "record_type, node_location_depth, node_location_offset, "
346         "record_expiration_time, record_flags, record_value) VALUES "
347         "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
348         &plugin->put_record) != SQLITE_OK) ||
349       (sq_prepare
350        (plugin->dbh,
351         "INSERT INTO ns090nodes (zone_hash, zone_revision, "
352         "node_location_depth, node_location_offset, node_parent_offset, node_hashcodes) "
353         "VALUES (?, ?, ?, ?, ?, ?)",
354         &plugin->put_node) != SQLITE_OK) ||
355       (sq_prepare
356        (plugin->dbh,
357         "INSERT INTO ns090signatures (zone_hash, zone_revision, zone_time, zone_root_hash, "
358         "zone_root_depth, zone_public_key, zone_signature) "
359         "VALUES (?, ?, ?, ?, ?, ?, ?)",
360         &plugin->put_signature) != SQLITE_OK) ||
361       (sq_prepare
362        (plugin->dbh,
363         "SELECT zone_revision,record_name,record_type,node_location_depth,node_location_offset,record_expiration_time,record_flags,record_value "
364         "FROM ns090records WHERE zone_hash=? AND record_name_hash=?",
365         &plugin->iterate_records) != SQLITE_OK) ||
366       (sq_prepare
367        (plugin->dbh,
368         "SELECT node_parent_offset,node_location_offset,node_hashcodes FROM ns090nodes "
369         "WHERE zone_hash=? AND zone_revision=? AND node_location_depth=? AND node_location_offset<=? ORDER BY node_location_offset DESC LIMIT 1",
370         &plugin->get_node) != SQLITE_OK) ||
371       (sq_prepare
372        (plugin->dbh,
373         "SELECT zone_revision,zone_time,zone_root_hash,zone_root_depth,zone_public_key,zone_signature "
374         "FROM ns090signatures WHERE zone_hash=?",
375         &plugin->get_signature) != SQLITE_OK) ||
376       (sq_prepare
377        (plugin->dbh,
378         "DELETE FROM ns090records WHERE zone_hash=?",
379         &plugin->delete_zone_records) != SQLITE_OK) ||
380       (sq_prepare
381        (plugin->dbh,
382         "DELETE FROM ns090nodes WHERE zone_hash=?",
383         &plugin->delete_zone_nodes) != SQLITE_OK) ||
384       (sq_prepare
385        (plugin->dbh,
386         "DELETE FROM ns090signatures WHERE zone_hash=?",
387         &plugin->delete_zone_signatures) != SQLITE_OK) )
388   {
389     LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling");
390     return GNUNET_SYSERR;
391   }
392   return GNUNET_OK;
393 }
394
395
396 /**
397  * Shutdown database connection and associate data
398  * structures.
399  * @param plugin the plugin context (state for this module)
400  */
401 static void
402 database_shutdown (struct Plugin *plugin)
403 {
404   int result;
405   sqlite3_stmt *stmt;
406
407   if (NULL != plugin->put_record)
408     sqlite3_finalize (plugin->put_record);
409   if (NULL != plugin->put_node)
410     sqlite3_finalize (plugin->put_node);
411   if (NULL != plugin->put_signature)
412     sqlite3_finalize (plugin->put_signature);
413   if (NULL != plugin->iterate_records)
414     sqlite3_finalize (plugin->iterate_records);
415   if (NULL != plugin->get_node)
416     sqlite3_finalize (plugin->get_node);
417   if (NULL != plugin->get_signature)
418     sqlite3_finalize (plugin->get_signature);
419   if (NULL != plugin->delete_zone_records)
420     sqlite3_finalize (plugin->delete_zone_records);
421   if (NULL != plugin->delete_zone_nodes)
422     sqlite3_finalize (plugin->delete_zone_nodes);
423   if (NULL != plugin->delete_zone_signatures)
424     sqlite3_finalize (plugin->delete_zone_signatures);
425   result = sqlite3_close (plugin->dbh);
426   if (result == SQLITE_BUSY)
427   {
428     LOG (GNUNET_ERROR_TYPE_WARNING,
429          _("Tried to close sqlite without finalizing all prepared statements.\n"));
430     stmt = sqlite3_next_stmt (plugin->dbh, NULL);
431     while (stmt != NULL)
432     {
433       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
434                        "Closing statement %p\n", stmt);
435       result = sqlite3_finalize (stmt);
436       if (result != SQLITE_OK)
437         GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
438                          "Failed to close statement %p: %d\n", stmt, result);
439       stmt = sqlite3_next_stmt (plugin->dbh, NULL);
440     }
441     result = sqlite3_close (plugin->dbh);
442   }
443   if (SQLITE_OK != result)
444     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
445
446   GNUNET_free_non_null (plugin->fn);
447 }
448
449
450 /**
451  * Store a record in the datastore.
452  *
453  * @param cls closure (internal context for the plugin)
454  * @param zone hash of the public key of the zone
455  * @param name name that is being mapped (at most 255 characters long)
456  * @param record_type type of the record (A, AAAA, PKEY, etc.)
457  * @param loc location of the signature for the record
458  * @param expiration expiration time for the content
459  * @param flags flags for the content
460  * @param data_size number of bytes in data
461  * @param data value, semantics depend on 'record_type' (see RFCs for DNS and 
462  *             GNS specification for GNS extensions)
463  * @return GNUNET_OK on success
464  */
465 static int 
466 namestore_sqlite_put_record (void *cls, 
467                              const GNUNET_HashCode *zone,
468                              const char *name,
469                              uint32_t record_type,
470                              const struct GNUNET_NAMESTORE_SignatureLocation *loc,
471                              struct GNUNET_TIME_Absolute expiration,
472                              enum GNUNET_NAMESTORE_RecordFlags flags,
473                              size_t data_size,
474                              const void *data)
475 {
476   struct Plugin *plugin = cls;
477   int n;
478   GNUNET_HashCode nh;
479   size_t name_len;
480
481   name_len = strlen (name);
482   GNUNET_CRYPTO_hash (name, name_len, &nh);
483   if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_record, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
484       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_record, 2, loc->revision)) ||
485       (SQLITE_OK != sqlite3_bind_blob (plugin->put_record, 3, &nh, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
486       (SQLITE_OK != sqlite3_bind_text (plugin->put_record, 4, name, -1, SQLITE_STATIC)) ||
487       (SQLITE_OK != sqlite3_bind_int (plugin->put_record, 5, record_type)) ||
488       (SQLITE_OK != sqlite3_bind_int (plugin->put_record, 6, loc->depth)) ||
489       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_record, 7, loc->offset)) ||
490       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_record, 8, expiration.abs_value)) ||
491       (SQLITE_OK != sqlite3_bind_int (plugin->put_record, 9, flags)) ||
492       (SQLITE_OK != sqlite3_bind_blob (plugin->put_record, 10, data, data_size, SQLITE_STATIC)) )
493   {
494     LOG_SQLITE (plugin, 
495                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
496                 "sqlite3_bind_XXXX");
497     if (SQLITE_OK != sqlite3_reset (plugin->put_record))
498       LOG_SQLITE (plugin, 
499                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
500                   "sqlite3_reset");
501     return GNUNET_SYSERR;
502
503   }
504   n = sqlite3_step (plugin->put_record);
505   if (SQLITE_OK != sqlite3_reset (plugin->put_record))
506     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
507                 "sqlite3_reset");
508   switch (n)
509   {
510   case SQLITE_DONE:
511     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n");
512     return GNUNET_OK;
513   case SQLITE_BUSY:
514     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
515                 "sqlite3_step");
516     return GNUNET_NO;
517   default:
518     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
519                 "sqlite3_step");
520     return GNUNET_SYSERR;
521   }
522 }
523
524
525 /**
526  * Store a Merkle tree node in the datastore.
527  *
528  * @param cls closure (internal context for the plugin)
529  * @param zone hash of public key of the zone
530  * @param loc location in the B-tree
531  * @param ploc parent's location in the B-tree (must have depth = loc.depth + 1), NULL for root
532  * @param num_entries number of entries at this node in the B-tree
533  * @param entries the 'num_entries' entries to store (hashes over the
534  *                records)
535  * @return GNUNET_OK on success
536  */
537 static int 
538 namestore_sqlite_put_node (void *cls, 
539                            const GNUNET_HashCode *zone,
540                            const struct GNUNET_NAMESTORE_SignatureLocation *loc,
541                            const struct GNUNET_NAMESTORE_SignatureLocation *ploc,
542                            unsigned int num_entries,
543                            const GNUNET_HashCode *entries)
544 {
545   struct Plugin *plugin = cls;
546   int n;
547
548   if ( (loc->revision != ploc->revision) ||
549        (loc->depth + 1 != ploc->depth) ||
550        (0 == num_entries))
551   {
552     GNUNET_break (0);
553     return GNUNET_SYSERR;
554   }
555   if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_node, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
556       (SQLITE_OK != sqlite3_bind_int (plugin->put_node, 2, loc->revision)) ||
557       (SQLITE_OK != sqlite3_bind_int (plugin->put_node, 3, loc->depth)) ||
558       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_node, 4, loc->offset)) ||
559       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_node, 5, ploc->offset)) ||
560       (SQLITE_OK != sqlite3_bind_blob (plugin->put_node, 6, entries, num_entries * sizeof (GNUNET_HashCode), SQLITE_STATIC)) )
561   {
562     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
563                 "sqlite3_bind_XXXX");
564     if (SQLITE_OK != sqlite3_reset (plugin->put_node))
565       LOG_SQLITE (plugin,
566                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
567                   "sqlite3_reset");
568     return GNUNET_SYSERR;
569
570   }
571   n = sqlite3_step (plugin->put_node);
572   if (SQLITE_OK != sqlite3_reset (plugin->put_node))
573     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
574                 "sqlite3_reset");
575   switch (n)
576   {
577   case SQLITE_DONE:
578     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Node stored\n");
579     return GNUNET_OK;
580   case SQLITE_BUSY:
581     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
582                 "sqlite3_step");
583     return GNUNET_NO;
584   default:
585     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
586                 "sqlite3_step");
587     return GNUNET_SYSERR;
588   }
589 }
590   
591   
592 /**
593  * Iterate over the results for a particular key and zone in the
594  * datastore.  Will only query the latest revision known for the
595  * zone (as adding a new zone revision will cause the plugin to
596  * delete all records from previous revisions).
597  *
598  * @param cls closure (internal context for the plugin)
599  * @param zone hash of public key of the zone
600  * @param name_hash hash of name, NULL to iterate over all records of the zone
601  * @param iter maybe NULL (to just count)
602  * @param iter_cls closure for iter
603  * @return the number of results found
604  */
605 static unsigned int 
606 namestore_sqlite_iterate_records (void *cls, 
607                                   const GNUNET_HashCode *zone,
608                                   const GNUNET_HashCode *name_hash,
609                                   GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
610 {
611   struct Plugin *plugin = cls;
612   unsigned int ret;
613   int sret;
614   struct GNUNET_TIME_Absolute expiration;
615   uint32_t record_type;
616   enum GNUNET_NAMESTORE_RecordFlags flags;
617   size_t data_size;
618   const void *data;
619   struct GNUNET_NAMESTORE_SignatureLocation loc;
620   const char *name;
621
622   if ((SQLITE_OK != sqlite3_bind_blob (plugin->iterate_records, 1, 
623                                        zone, sizeof (GNUNET_HashCode), 
624                                        SQLITE_STATIC)) ||
625       (SQLITE_OK != sqlite3_bind_blob (plugin->iterate_records, 2, 
626                                        name_hash, sizeof (GNUNET_HashCode), 
627                                        SQLITE_STATIC)) )
628   {
629     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
630                 "sqlite3_bind_XXXX");
631     if (SQLITE_OK != sqlite3_reset (plugin->iterate_records))
632       LOG_SQLITE (plugin,
633                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
634                   "sqlite3_reset");
635     return GNUNET_SYSERR;
636   }
637   ret = 0;
638   while (SQLITE_ROW == (sret = sqlite3_step (plugin->iterate_records)))
639   {
640     ret++;
641     if (NULL == iter)
642       continue; /* FIXME: just counting can be done more cheaply... */
643     loc.revision = sqlite3_column_int (plugin->iterate_records, 0);
644     name = (const char*) sqlite3_column_text (plugin->iterate_records, 1);
645     record_type = sqlite3_column_int (plugin->iterate_records, 2);
646     loc.depth = sqlite3_column_int (plugin->iterate_records, 3);
647     loc.offset = sqlite3_column_int64 (plugin->iterate_records, 4);
648     expiration.abs_value = (uint64_t) sqlite3_column_int64 (plugin->iterate_records, 5);
649     flags = (enum GNUNET_NAMESTORE_RecordFlags) sqlite3_column_int (plugin->iterate_records, 6);
650     data = sqlite3_column_blob (plugin->iterate_records, 7);
651     data_size = sqlite3_column_bytes (plugin->iterate_records, 7);
652     iter (iter_cls, zone,
653           &loc, name, record_type,
654           expiration, flags, data_size, data);
655   }
656   if (SQLITE_DONE != sret)
657     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
658   if (SQLITE_OK != sqlite3_reset (plugin->iterate_records))
659     LOG_SQLITE (plugin,
660                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
661                 "sqlite3_reset");
662   return ret;
663 }
664
665  
666 /**
667  * Get a particular node from the signature tree.
668  *
669  * @param cls closure (internal context for the plugin)
670  * @param zone hash of public key of the zone
671  * @param loc location of the node in the signature tree
672  * @param cb function to call with the result
673  * @param cb_cls closure for cont
674  * @return GNUNET_OK on success, GNUNET_NO if no node was found
675  */
676 static int
677 namestore_sqlite_get_node (void *cls, 
678                            const GNUNET_HashCode *zone,
679                            const struct GNUNET_NAMESTORE_SignatureLocation *loc,
680                            GNUNET_NAMESTORE_NodeCallback cb, void *cb_cls)
681 {
682   struct Plugin *plugin = cls;
683   int ret;
684   size_t hashcodes_size;
685   const GNUNET_HashCode *hashcodes;
686   struct GNUNET_NAMESTORE_SignatureLocation ploc;
687   struct GNUNET_NAMESTORE_SignatureLocation rloc;
688
689   GNUNET_assert (NULL != cb);
690   if ((SQLITE_OK != sqlite3_bind_blob (plugin->get_node, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
691       (SQLITE_OK != sqlite3_bind_int (plugin->get_node, 2, loc->revision)) ||
692       (SQLITE_OK != sqlite3_bind_int (plugin->get_node, 3, loc->depth)) ||
693       (SQLITE_OK != sqlite3_bind_int64 (plugin->get_node, 4, loc->offset)) )
694   {
695     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
696                 "sqlite3_bind_XXXX");
697     if (SQLITE_OK != sqlite3_reset (plugin->get_node))
698       LOG_SQLITE (plugin,
699                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
700                   "sqlite3_reset");
701     return GNUNET_SYSERR;
702
703   }
704   rloc.revision = loc->revision;
705   rloc.depth = loc->depth;
706   ploc.revision = loc->revision;
707   ploc.depth = loc->depth + 1;
708   ret = GNUNET_NO;
709   if (SQLITE_ROW == (ret = sqlite3_step (plugin->get_node)))    
710   {
711     ploc.offset = sqlite3_column_int64 (plugin->get_node, 0);
712     rloc.offset = sqlite3_column_int64 (plugin->get_node, 1);
713     hashcodes = sqlite3_column_blob (plugin->get_node, 2);
714     hashcodes_size = sqlite3_column_bytes (plugin->get_node, 2);
715     if (0 != (hashcodes_size % sizeof (GNUNET_HashCode)))
716     {
717       GNUNET_break (0);
718       /* FIXME: delete bogus record? */
719     } 
720     else
721     {
722       ret = GNUNET_OK;
723       cb (cb_cls,
724           zone,
725           &rloc,
726           &ploc,
727           hashcodes_size / sizeof (GNUNET_HashCode),
728           hashcodes);
729     }
730   }
731   else if (SQLITE_DONE != ret)
732     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
733   if (SQLITE_OK != sqlite3_reset (plugin->get_node))
734     LOG_SQLITE (plugin,
735                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
736                 "sqlite3_reset");
737   return ret;
738 }
739
740
741 /**
742  * Get the current signature for a zone.
743  *
744  * @param cls closure (internal context for the plugin)
745  * @param zone hash of public key of the zone
746  * @param cb function to call with the result
747  * @param cb_cls closure for cont
748  * @return GNUNET_OK on success, GNUNET_NO if no node was found
749  */
750 static int
751 namestore_sqlite_get_signature (void *cls, 
752                                 const GNUNET_HashCode *zone,
753                                 GNUNET_NAMESTORE_SignatureCallback cb, void *cb_cls)
754 {
755   struct Plugin *plugin = cls;
756   int ret;
757   int sret;
758   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key;
759   struct GNUNET_NAMESTORE_SignatureLocation top_loc;
760   const struct GNUNET_CRYPTO_RsaSignature *zone_sig;
761   struct GNUNET_TIME_Absolute zone_time;
762   const GNUNET_HashCode *top_hash;
763
764   GNUNET_assert (NULL != cb);
765   if (SQLITE_OK != sqlite3_bind_blob (plugin->get_signature, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC))
766   {
767     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
768                 "sqlite3_bind_XXXX");
769     if (SQLITE_OK != sqlite3_reset (plugin->get_signature))
770       LOG_SQLITE (plugin,
771                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
772                   "sqlite3_reset");
773     return GNUNET_SYSERR;
774   }
775   ret = GNUNET_NO;
776   if (SQLITE_ROW == (sret = sqlite3_step (plugin->get_signature)))    
777   {
778     top_loc.offset = 0;
779     top_loc.revision = sqlite3_column_int (plugin->get_signature, 0);
780     zone_time.abs_value = sqlite3_column_int64 (plugin->get_signature, 1);
781     top_hash = sqlite3_column_blob (plugin->get_signature, 2);
782     top_loc.depth = sqlite3_column_int (plugin->get_signature, 3);
783     zone_key = sqlite3_column_blob (plugin->get_signature, 4);
784     zone_sig = sqlite3_column_blob (plugin->get_signature, 5);
785
786     if ((sizeof (GNUNET_HashCode) != sqlite3_column_bytes (plugin->get_signature, 2)) ||
787         (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != sqlite3_column_bytes (plugin->get_signature, 4)) ||
788         (sizeof (struct GNUNET_CRYPTO_RsaSignature) != sqlite3_column_bytes (plugin->get_signature, 5)))
789     {
790       GNUNET_break (0);
791       /* FIXME: delete bogus record & full zone (!?) */
792     } 
793     else
794     {
795       ret = GNUNET_OK;
796       cb (cb_cls,
797           zone_key,
798           &top_loc,
799           zone_sig,
800           zone_time,
801           top_hash);
802     }
803   }
804   else if (SQLITE_DONE != sret)
805     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
806   if (SQLITE_OK != sqlite3_reset (plugin->get_signature))
807     LOG_SQLITE (plugin,
808                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
809                 "sqlite3_reset");
810   return ret;
811 }
812
813
814 /**
815  * Run a SQL statement that takes only a 'zone' as the argument
816  * and returns nothing (deletes records).
817  *
818  * @param plugin our plugin
819  * @param zone zone argument to pass
820  * @param stmt prepared statement to run
821  */
822 static void
823 run_delete_statement (struct Plugin *plugin,
824                       const GNUNET_HashCode *zone,
825                       sqlite3_stmt *stmt)
826 {
827   int n;
828
829   if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC))
830   {
831     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
832                 "sqlite3_bind_XXXX");
833     if (SQLITE_OK != sqlite3_reset (stmt))
834       LOG_SQLITE (plugin,
835                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
836                   "sqlite3_reset");
837     return;
838   }
839   n = sqlite3_step (stmt);
840   if (SQLITE_OK != sqlite3_reset (stmt))
841     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
842                 "sqlite3_reset");
843   switch (n)
844   {
845   case SQLITE_DONE:
846     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Values deleted\n");
847     break;
848   case SQLITE_BUSY:
849     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
850                 "sqlite3_step");
851     break;
852   default:
853     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
854                 "sqlite3_step");
855     break;
856   }
857 }
858
859
860 /**
861  * Delete an entire zone (all revisions, all records, all nodes,
862  * all signatures).  Not used in normal operation.
863  *
864  * @param cls closure (internal context for the plugin)
865  * @param zone zone to delete
866  */
867 static void 
868 namestore_sqlite_delete_zone (void *cls,
869                               const GNUNET_HashCode *zone)
870 {
871   struct Plugin *plugin = cls;
872   
873   run_delete_statement (plugin, zone, plugin->delete_zone_records);
874   run_delete_statement (plugin, zone, plugin->delete_zone_nodes);
875   run_delete_statement (plugin, zone, plugin->delete_zone_signatures);
876 }
877
878
879 /**
880  * Context for 'delete_old_zone_information'.
881  */
882 struct DeleteContext
883 {
884   /**
885    * Plugin handle.
886    */
887   struct Plugin *plugin;
888
889   /**
890    * Hash of the public key of the zone (to avoid having to
891    * recalculate it).
892    */
893   const GNUNET_HashCode *zone;
894
895   /**
896    * Revision to compare against.
897    */
898   uint32_t revision;
899   
900 };
901
902
903 /**
904  * Function called on the current signature in the database for
905  * a zone.  If the revision given in the closure is more recent,
906  * delete all information about the zone.  Otherwise, only delete
907  * the signature.
908  * 
909  * @param cls a 'struct DeleteContext' with a revision to compare against
910  * @param zone_key public key of the zone
911  * @param loc location of the root in the B-tree (depth, revision)
912  * @param top_sig signature signing the zone
913  * @param zone_time time the signature was created
914  * @param root_hash top level hash that is being signed
915  */
916 static void
917 delete_old_zone_information (void *cls,
918                              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
919                              const struct GNUNET_NAMESTORE_SignatureLocation *loc,
920                              const struct GNUNET_CRYPTO_RsaSignature *top_sig,
921                              struct GNUNET_TIME_Absolute zone_time,
922                              const GNUNET_HashCode *root_hash)
923 {
924   struct DeleteContext *dc = cls;
925
926   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_signatures);    
927   if (loc->revision == dc->revision)
928     return;
929   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_records);
930   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_nodes);
931 }
932   
933
934 /**
935  * Store a zone signature in the datastore.  If a signature for the zone with a
936  * lower depth exists, the old signature is removed.  If a signature for an
937  * older revision of the zone exists, this will delete all records, nodes
938  * and signatures for the older revision of the zone.
939  *
940  * @param cls closure (internal context for the plugin)
941  * @param zone_key public key of the zone
942  * @param loc location in the B-tree (top of the tree, offset 0, depth at 'maximum')
943  * @param top_sig signature at the top, NULL if 'loc.depth > 0'
944  * @param root_hash top level hash that is signed
945  * @param zone_time time the zone was signed
946  * @return GNUNET_OK on success
947  */
948 static int
949 namestore_sqlite_put_signature (void *cls, 
950                                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
951                                 const struct GNUNET_NAMESTORE_SignatureLocation *loc,
952                                 const struct GNUNET_CRYPTO_RsaSignature *top_sig,
953                                 const GNUNET_HashCode *root_hash,
954                                 struct GNUNET_TIME_Absolute zone_time)
955 {
956   struct Plugin *plugin = cls;
957   int n;
958   GNUNET_HashCode zone;
959   struct DeleteContext dc;
960
961   GNUNET_break (0 == loc->offset); /* little sanity check */
962   GNUNET_CRYPTO_hash (zone_key,
963                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
964                       &zone);
965   /* get "old" signature, if older revision, delete all existing
966      records/nodes for the zone, if same revision, delete only the signature */
967   dc.plugin = plugin;
968   dc.zone = &zone;
969   dc.revision = loc->revision;
970   (void) namestore_sqlite_get_signature (plugin,
971                                          &zone,
972                                          &delete_old_zone_information,
973                                          &dc);
974   if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 1, &zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
975       (SQLITE_OK != sqlite3_bind_int (plugin->put_signature, 2, loc->revision)) ||
976       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_signature, 3, zone_time.abs_value)) ||
977       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 4, root_hash, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
978       (SQLITE_OK != sqlite3_bind_int (plugin->put_signature, 5, loc->depth)) ||
979       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 6, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), SQLITE_STATIC))||
980       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 7, top_sig, sizeof (struct GNUNET_CRYPTO_RsaSignature), SQLITE_STATIC)) )
981   {
982     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
983                 "sqlite3_bind_XXXX");
984     if (SQLITE_OK != sqlite3_reset (plugin->put_signature))
985       LOG_SQLITE (plugin,
986                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
987                   "sqlite3_reset");
988     return GNUNET_SYSERR;
989   }
990   n = sqlite3_step (plugin->put_signature);
991   if (SQLITE_OK != sqlite3_reset (plugin->put_signature))
992     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
993                 "sqlite3_reset");
994   switch (n)
995   {
996   case SQLITE_DONE:
997     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Signature stored\n");
998     return GNUNET_OK;
999   case SQLITE_BUSY:
1000     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1001                 "sqlite3_step");
1002     return GNUNET_NO;
1003   default:
1004     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1005                 "sqlite3_step");
1006     return GNUNET_SYSERR;
1007   }
1008 }
1009
1010
1011 /**
1012  * Entry point for the plugin.
1013  *
1014  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
1015  * @return NULL on error, othrewise the plugin context
1016  */
1017 void *
1018 libgnunet_plugin_namestore_sqlite_init (void *cls)
1019 {
1020   static struct Plugin plugin;
1021   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1022   struct GNUNET_NAMESTORE_PluginFunctions *api;
1023
1024   if (NULL != plugin.cfg)
1025     return NULL;                /* can only initialize once! */
1026   memset (&plugin, 0, sizeof (struct Plugin));
1027   plugin.cfg = cfg;  
1028   if (GNUNET_OK != database_setup (&plugin))
1029   {
1030     database_shutdown (&plugin);
1031     return NULL;
1032   }
1033   api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions));
1034   api->cls = &plugin;
1035   api->put_record = &namestore_sqlite_put_record;
1036   api->put_node = &namestore_sqlite_put_node;
1037   api->put_signature = &namestore_sqlite_put_signature;
1038   api->iterate_records = &namestore_sqlite_iterate_records;
1039   api->get_node = &namestore_sqlite_get_node;
1040   api->get_signature = &namestore_sqlite_get_signature;
1041   api->delete_zone = &namestore_sqlite_delete_zone;
1042   LOG (GNUNET_ERROR_TYPE_INFO, 
1043        _("Sqlite database running\n"));
1044   return api;
1045 }
1046
1047
1048 /**
1049  * Exit point from the plugin.
1050  *
1051  * @param cls the plugin context (as returned by "init")
1052  * @return always NULL
1053  */
1054 void *
1055 libgnunet_plugin_namestore_sqlite_done (void *cls)
1056 {
1057   struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
1058   struct Plugin *plugin = api->cls;
1059
1060   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1061        "sqlite plugin is done\n");
1062   database_shutdown (plugin);
1063   plugin->cfg = NULL;
1064   GNUNET_free (api);
1065   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1066        "sqlite plugin is finished\n");
1067   return NULL;
1068 }
1069
1070 /* end of plugin_namestore_sqlite.c */