a03f8cc37b1b7b0fcbe055de040ca46384495b47
[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   sqlite3_finalize (plugin->iterate_records);
659   return ret;
660 }
661
662  
663 /**
664  * Get a particular node from the signature tree.
665  *
666  * @param cls closure (internal context for the plugin)
667  * @param zone hash of public key of the zone
668  * @param loc location of the node in the signature tree
669  * @param cb function to call with the result
670  * @param cb_cls closure for cont
671  * @return GNUNET_OK on success, GNUNET_NO if no node was found
672  */
673 static int
674 namestore_sqlite_get_node (void *cls, 
675                            const GNUNET_HashCode *zone,
676                            const struct GNUNET_NAMESTORE_SignatureLocation *loc,
677                            GNUNET_NAMESTORE_NodeCallback cb, void *cb_cls)
678 {
679   struct Plugin *plugin = cls;
680   int ret;
681   size_t hashcodes_size;
682   const GNUNET_HashCode *hashcodes;
683   struct GNUNET_NAMESTORE_SignatureLocation ploc;
684   struct GNUNET_NAMESTORE_SignatureLocation rloc;
685
686   GNUNET_assert (NULL != cb);
687   if ((SQLITE_OK != sqlite3_bind_blob (plugin->get_node, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
688       (SQLITE_OK != sqlite3_bind_int (plugin->get_node, 2, loc->revision)) ||
689       (SQLITE_OK != sqlite3_bind_int (plugin->get_node, 3, loc->depth)) ||
690       (SQLITE_OK != sqlite3_bind_int64 (plugin->get_node, 4, loc->offset)) )
691   {
692     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
693                 "sqlite3_bind_XXXX");
694     if (SQLITE_OK != sqlite3_reset (plugin->get_node))
695       LOG_SQLITE (plugin,
696                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
697                   "sqlite3_reset");
698     return GNUNET_SYSERR;
699
700   }
701   rloc.revision = loc->revision;
702   rloc.depth = loc->depth;
703   ploc.revision = loc->revision;
704   ploc.depth = loc->depth + 1;
705   ret = GNUNET_NO;
706   if (SQLITE_ROW == (ret = sqlite3_step (plugin->get_node)))    
707   {
708     ploc.offset = sqlite3_column_int64 (plugin->get_node, 0);
709     rloc.offset = sqlite3_column_int64 (plugin->get_node, 1);
710     hashcodes = sqlite3_column_blob (plugin->get_node, 2);
711     hashcodes_size = sqlite3_column_bytes (plugin->get_node, 2);
712     if (0 != (hashcodes_size % sizeof (GNUNET_HashCode)))
713     {
714       GNUNET_break (0);
715       /* FIXME: delete bogus record? */
716     } 
717     else
718     {
719       ret = GNUNET_OK;
720       cb (cb_cls,
721           zone,
722           &rloc,
723           &ploc,
724           hashcodes_size / sizeof (GNUNET_HashCode),
725           hashcodes);
726     }
727   }
728   else if (SQLITE_DONE != ret)
729     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
730   sqlite3_finalize (plugin->get_node);
731   return ret;
732 }
733
734
735 /**
736  * Get the current signature for a zone.
737  *
738  * @param cls closure (internal context for the plugin)
739  * @param zone hash of public key of the zone
740  * @param cb function to call with the result
741  * @param cb_cls closure for cont
742  * @return GNUNET_OK on success, GNUNET_NO if no node was found
743  */
744 static int
745 namestore_sqlite_get_signature (void *cls, 
746                                 const GNUNET_HashCode *zone,
747                                 GNUNET_NAMESTORE_SignatureCallback cb, void *cb_cls)
748 {
749   struct Plugin *plugin = cls;
750   int ret;
751   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key;
752   struct GNUNET_NAMESTORE_SignatureLocation top_loc;
753   const struct GNUNET_CRYPTO_RsaSignature *zone_sig;
754   struct GNUNET_TIME_Absolute zone_time;
755   const GNUNET_HashCode *top_hash;
756
757   GNUNET_assert (NULL != cb);
758   if (SQLITE_OK != sqlite3_bind_blob (plugin->get_signature, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC))
759   {
760     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
761                 "sqlite3_bind_XXXX");
762     if (SQLITE_OK != sqlite3_reset (plugin->get_signature))
763       LOG_SQLITE (plugin,
764                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
765                   "sqlite3_reset");
766     return GNUNET_SYSERR;
767   }
768   ret = GNUNET_NO;
769   if (SQLITE_ROW == (ret = sqlite3_step (plugin->get_signature)))    
770   {
771     top_loc.offset = 0;
772     top_loc.revision = sqlite3_column_int (plugin->get_signature, 0);
773     zone_time.abs_value = sqlite3_column_int64 (plugin->get_signature, 1);
774     top_hash = sqlite3_column_blob (plugin->get_signature, 2);
775     top_loc.depth = sqlite3_column_int (plugin->get_signature, 3);
776     zone_key = sqlite3_column_blob (plugin->get_signature, 4);
777     zone_sig = sqlite3_column_blob (plugin->get_signature, 5);
778
779     if ((sizeof (GNUNET_HashCode) != sqlite3_column_bytes (plugin->get_signature, 2)) ||
780         (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != sqlite3_column_bytes (plugin->get_signature, 4)) ||
781         (sizeof (struct GNUNET_CRYPTO_RsaSignature) != sqlite3_column_bytes (plugin->get_signature, 5)))
782     {
783       GNUNET_break (0);
784       /* FIXME: delete bogus record & full zone (!?) */
785     } 
786     else
787     {
788       ret = GNUNET_OK;
789       cb (cb_cls,
790           zone_key,
791           &top_loc,
792           zone_sig,
793           zone_time,
794           top_hash);
795     }
796   }
797   if (SQLITE_DONE != ret)
798     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
799   sqlite3_finalize (plugin->get_signature);
800   return ret;
801 }
802
803
804 /**
805  * Run a SQL statement that takes only a 'zone' as the argument
806  * and returns nothing (deletes records).
807  *
808  * @param plugin our plugin
809  * @param zone zone argument to pass
810  * @param stmt prepared statement to run
811  */
812 static void
813 run_delete_statement (struct Plugin *plugin,
814                       const GNUNET_HashCode *zone,
815                       sqlite3_stmt *stmt)
816 {
817   int n;
818
819   if (SQLITE_OK != sqlite3_bind_blob (plugin->delete_zone_records, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC))
820   {
821     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
822                 "sqlite3_bind_XXXX");
823     if (SQLITE_OK != sqlite3_reset (plugin->delete_zone_records))
824       LOG_SQLITE (plugin,
825                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
826                   "sqlite3_reset");
827     return;
828   }
829   n = sqlite3_step (plugin->put_signature);
830   if (SQLITE_OK != sqlite3_reset (plugin->delete_zone_records))
831     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
832                 "sqlite3_reset");
833   switch (n)
834   {
835   case SQLITE_DONE:
836     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Zone records deleted\n");
837     break;
838   case SQLITE_BUSY:
839     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
840                 "sqlite3_step");
841     break;
842   default:
843     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
844                 "sqlite3_step");
845     break;
846   }
847 }
848
849
850 /**
851  * Delete an entire zone (all revisions, all records, all nodes,
852  * all signatures).  Not used in normal operation.
853  *
854  * @param cls closure (internal context for the plugin)
855  * @param zone zone to delete
856  */
857 static void 
858 namestore_sqlite_delete_zone (void *cls,
859                               const GNUNET_HashCode *zone)
860 {
861   struct Plugin *plugin = cls;
862   
863   run_delete_statement (plugin, zone, plugin->delete_zone_records);
864   run_delete_statement (plugin, zone, plugin->delete_zone_nodes);
865   run_delete_statement (plugin, zone, plugin->delete_zone_signatures);
866 }
867
868
869 /**
870  * Context for 'delete_old_zone_information'.
871  */
872 struct DeleteContext
873 {
874   /**
875    * Plugin handle.
876    */
877   struct Plugin *plugin;
878
879   /**
880    * Hash of the public key of the zone (to avoid having to
881    * recalculate it).
882    */
883   const GNUNET_HashCode *zone;
884
885   /**
886    * Revision to compare against.
887    */
888   uint32_t revision;
889   
890 };
891
892
893 /**
894  * Function called on the current signature in the database for
895  * a zone.  If the revision given in the closure is more recent,
896  * delete all information about the zone.  Otherwise, only delete
897  * the signature.
898  * 
899  * @param cls a 'struct DeleteContext' with a revision to compare against
900  * @param zone_key public key of the zone
901  * @param loc location of the root in the B-tree (depth, revision)
902  * @param top_sig signature signing the zone
903  * @param zone_time time the signature was created
904  * @param root_hash top level hash that is being signed
905  */
906 static void
907 delete_old_zone_information (void *cls,
908                              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
909                              const struct GNUNET_NAMESTORE_SignatureLocation *loc,
910                              const struct GNUNET_CRYPTO_RsaSignature *top_sig,
911                              struct GNUNET_TIME_Absolute zone_time,
912                              const GNUNET_HashCode *root_hash)
913 {
914   struct DeleteContext *dc = cls;
915
916   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_signatures);    
917   if (loc->revision == dc->revision)
918     return;
919   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_records);
920   run_delete_statement (dc->plugin, dc->zone, dc->plugin->delete_zone_nodes);
921 }
922   
923
924 /**
925  * Store a zone signature in the datastore.  If a signature for the zone with a
926  * lower depth exists, the old signature is removed.  If a signature for an
927  * older revision of the zone exists, this will delete all records, nodes
928  * and signatures for the older revision of the zone.
929  *
930  * @param cls closure (internal context for the plugin)
931  * @param zone_key public key of the zone
932  * @param loc location in the B-tree (top of the tree, offset 0, depth at 'maximum')
933  * @param top_sig signature at the top, NULL if 'loc.depth > 0'
934  * @param root_hash top level hash that is signed
935  * @param zone_time time the zone was signed
936  * @return GNUNET_OK on success
937  */
938 static int
939 namestore_sqlite_put_signature (void *cls, 
940                                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
941                                 const struct GNUNET_NAMESTORE_SignatureLocation *loc,
942                                 const struct GNUNET_CRYPTO_RsaSignature *top_sig,
943                                 const GNUNET_HashCode *root_hash,
944                                 struct GNUNET_TIME_Absolute zone_time)
945 {
946   struct Plugin *plugin = cls;
947   int n;
948   GNUNET_HashCode zone;
949   struct DeleteContext dc;
950
951   GNUNET_CRYPTO_hash (zone_key,
952                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
953                       &zone);
954   /* get "old" signature, if older revision, delete all existing
955      records/nodes for the zone, if same revision, delete only the signature */
956   dc.plugin = plugin;
957   dc.zone = &zone;
958   dc.revision = loc->revision;
959   (void) namestore_sqlite_get_signature (plugin,
960                                          &zone,
961                                          &delete_old_zone_information,
962                                          &dc);
963   if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 1, &zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
964       (SQLITE_OK != sqlite3_bind_int (plugin->put_signature, 2, loc->revision)) ||
965       (SQLITE_OK != sqlite3_bind_int64 (plugin->put_signature, 3, zone_time.abs_value)) ||
966       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 4, root_hash, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
967       (SQLITE_OK != sqlite3_bind_int (plugin->put_signature, 5, loc->depth)) ||
968       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 6, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), SQLITE_STATIC))||
969       (SQLITE_OK != sqlite3_bind_blob (plugin->put_signature, 7, top_sig, sizeof (struct GNUNET_CRYPTO_RsaSignature), SQLITE_STATIC)) )
970   {
971     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
972                 "sqlite3_bind_XXXX");
973     if (SQLITE_OK != sqlite3_reset (plugin->put_signature))
974       LOG_SQLITE (plugin,
975                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
976                   "sqlite3_reset");
977     return GNUNET_SYSERR;
978
979   }
980   n = sqlite3_step (plugin->put_signature);
981   if (SQLITE_OK != sqlite3_reset (plugin->put_signature))
982     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
983                 "sqlite3_reset");
984   switch (n)
985   {
986   case SQLITE_DONE:
987     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Signature stored\n");
988     return GNUNET_OK;
989   case SQLITE_BUSY:
990     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
991                 "sqlite3_step");
992     return GNUNET_NO;
993   default:
994     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
995                 "sqlite3_step");
996     return GNUNET_SYSERR;
997   }
998 }
999
1000
1001 /**
1002  * Entry point for the plugin.
1003  *
1004  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
1005  * @return NULL on error, othrewise the plugin context
1006  */
1007 void *
1008 libgnunet_plugin_namestore_sqlite_init (void *cls)
1009 {
1010   static struct Plugin plugin;
1011   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1012   struct GNUNET_NAMESTORE_PluginFunctions *api;
1013
1014   if (NULL != plugin.cfg)
1015     return NULL;                /* can only initialize once! */
1016   memset (&plugin, 0, sizeof (struct Plugin));
1017   plugin.cfg = cfg;  
1018   if (GNUNET_OK != database_setup (&plugin))
1019   {
1020     database_shutdown (&plugin);
1021     return NULL;
1022   }
1023   api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions));
1024   api->cls = &plugin;
1025   api->put_record = &namestore_sqlite_put_record;
1026   api->put_node = &namestore_sqlite_put_node;
1027   api->put_signature = &namestore_sqlite_put_signature;
1028   api->iterate_records = &namestore_sqlite_iterate_records;
1029   api->get_node = &namestore_sqlite_get_node;
1030   api->get_signature = &namestore_sqlite_get_signature;
1031   api->delete_zone = &namestore_sqlite_delete_zone;
1032   LOG (GNUNET_ERROR_TYPE_INFO, 
1033        _("Sqlite database running\n"));
1034   return api;
1035 }
1036
1037
1038 /**
1039  * Exit point from the plugin.
1040  *
1041  * @param cls the plugin context (as returned by "init")
1042  * @return always NULL
1043  */
1044 void *
1045 libgnunet_plugin_namestore_sqlite_done (void *cls)
1046 {
1047   struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
1048   struct Plugin *plugin = api->cls;
1049
1050   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1051        "sqlite plugin is done\n");
1052   database_shutdown (plugin);
1053   plugin->cfg = NULL;
1054   GNUNET_free (api);
1055   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1056        "sqlite plugin is finished\n");
1057   return NULL;
1058 }
1059
1060 /* end of plugin_namestore_sqlite.c */