-fix
[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_records;
76
77   /**
78    * Precompiled SQL for remove record
79    */
80   sqlite3_stmt *remove_records;
81
82   /**
83    * Precompiled SQL for iterate over all records.
84    */
85   sqlite3_stmt *iterate_all;
86
87   /**
88    * Precompiled SQL for iterate records with same name.
89    */
90   sqlite3_stmt *iterate_by_name;
91
92   /**
93    * Precompiled SQL for iterate records with same zone.
94    */
95   sqlite3_stmt *iterate_by_zone;
96
97   /**
98    * Precompiled SQL for iterate records with same name and zone.
99    */
100   sqlite3_stmt *iterate_records;
101
102   /**
103    * Precompiled SQL for delete zone
104    */
105   sqlite3_stmt *delete_zone;
106
107 };
108
109
110 /**
111  * Internal format of a record in the BLOB in the database.
112  */
113 struct DbRecord
114 {
115
116   /**
117    * Expiration time for the DNS record.
118    */
119   struct GNUNET_TIME_AbsoluteNBO expiration;
120
121   /**
122    * Number of bytes in 'data', network byte order.
123    */
124   uint32_t data_size;
125
126   /**
127    * Type of the GNS/DNS record, network byte order.
128    */
129   uint32_t record_type;
130
131   /**
132    * Flags for the record, network byte order.
133    */
134   uint32_t flags;
135   
136 };
137
138
139 /**
140  * @brief Prepare a SQL statement
141  *
142  * @param dbh handle to the database
143  * @param zSql SQL statement, UTF-8 encoded
144  * @param ppStmt set to the prepared statement
145  * @return 0 on success
146  */
147 static int
148 sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt)
149 {
150   char *dummy;
151   int result;
152
153   result =
154       sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
155                           (const char **) &dummy);
156   LOG (GNUNET_ERROR_TYPE_DEBUG, 
157        "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
158   return result;
159 }
160
161
162 /**
163  * Create our database indices.
164  *
165  * @param dbh handle to the database
166  */
167 static void
168 create_indices (sqlite3 * dbh)
169 {
170   /* create indices */
171   if ( (SQLITE_OK !=
172         sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_name_rv ON ns090records (zone_hash,record_name_hash,rvalue)",
173                       NULL, NULL, NULL)) ||
174        (SQLITE_OK !=
175         sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_rv ON ns090records (zone_hash,rvalue)",
176                       NULL, NULL, NULL)) ||
177        (SQLITE_OK !=
178         sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone ON ns090records (zone_hash)",
179                       NULL, NULL, NULL)) ||
180        (SQLITE_OK !=
181         sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_name_rv ON ns090records (record_name_hash,rvalue)",
182                       NULL, NULL, NULL)) ||
183        (SQLITE_OK !=
184         sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_rv ON ns090records (rvalue)",
185                       NULL, NULL, NULL)) )    
186     LOG (GNUNET_ERROR_TYPE_ERROR, 
187          "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
188 }
189
190
191 #if 0
192 #define CHECK(a) GNUNET_break(a)
193 #define ENULL NULL
194 #else
195 #define ENULL &e
196 #define ENULL_DEFINED 1
197 #define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); }
198 #endif
199
200
201 /**
202  * Initialize the database connections and associated
203  * data structures (create tables and indices
204  * as needed as well).
205  *
206  * @param plugin the plugin context (state for this module)
207  * @return GNUNET_OK on success
208  */
209 static int
210 database_setup (struct Plugin *plugin)
211 {
212   sqlite3_stmt *stmt;
213   char *afsdir;
214 #if ENULL_DEFINED
215   char *e;
216 #endif
217
218   if (GNUNET_OK !=
219       GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namestore-sqlite",
220                                                "FILENAME", &afsdir))
221     {
222     LOG (GNUNET_ERROR_TYPE_ERROR, 
223          _ ("Option `%s' in section `%s' missing in configuration!\n"),
224          "FILENAME", "namestore-sqlite");
225     return GNUNET_SYSERR;
226   }
227   if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
228   {
229     if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
230     {
231       GNUNET_break (0);
232       GNUNET_free (afsdir);
233       return GNUNET_SYSERR;
234     }
235   }
236 #ifdef ENABLE_NLS
237   plugin->fn =
238       GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET));
239 #else
240   plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8");       /* good luck */
241 #endif
242   GNUNET_free (afsdir);
243
244   /* Open database and precompile statements */
245   if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
246   {
247     LOG (GNUNET_ERROR_TYPE_ERROR,
248          _("Unable to initialize SQLite: %s.\n"),
249          sqlite3_errmsg (plugin->dbh));
250     return GNUNET_SYSERR;
251   }
252   CHECK (SQLITE_OK ==
253          sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL,
254                        ENULL));
255   CHECK (SQLITE_OK ==
256          sqlite3_exec (plugin->dbh, "PRAGMA synchronous=NORMAL", NULL, NULL,
257                        ENULL));
258   CHECK (SQLITE_OK ==
259          sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL,
260                        ENULL));
261   CHECK (SQLITE_OK ==
262          sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL,
263                        NULL, ENULL));
264   CHECK (SQLITE_OK ==
265          sqlite3_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"", NULL,
266                        NULL, ENULL));
267   CHECK (SQLITE_OK ==
268          sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
269                        ENULL));
270   CHECK (SQLITE_OK ==
271          sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL,
272                        ENULL));
273   CHECK (SQLITE_OK ==
274          sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL,
275                        ENULL));
276
277   CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
278
279
280   /* Create tables */
281   CHECK (SQLITE_OK ==
282          sq_prepare (plugin->dbh,
283                      "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns090records'",
284                      &stmt));
285   if ((sqlite3_step (stmt) == SQLITE_DONE) &&
286       (sqlite3_exec
287        (plugin->dbh,
288         "CREATE TABLE ns090records (" 
289         " zone_key BLOB NOT NULL DEFAULT ''," 
290         " zone_hash BLOB NOT NULL DEFAULT ''," 
291         " record_count INT NOT NULL DEFAULT 0,"
292         " record_data BLOB NOT NULL DEFAULT '',"
293         " block_expiration_time INT8 NOT NULL DEFAULT 0," 
294         " signature BLOB NOT NULL DEFAULT '',"
295         " record_name TEXT NOT NULL DEFAULT ''," 
296         " record_name_hash BLOB NOT NULL DEFAULT ''," 
297         " rvalue INT8 NOT NULL DEFAULT ''"
298         ")", 
299         NULL, NULL, NULL) != SQLITE_OK))
300   {
301     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
302     sqlite3_finalize (stmt);
303     return GNUNET_SYSERR;
304   }
305   sqlite3_finalize (stmt);
306
307   create_indices (plugin->dbh);
308
309 #define ALL "zone_key, record_name, record_count, record_data, block_expiration_time, signature"
310   if ((sq_prepare
311        (plugin->dbh,
312         "INSERT INTO ns090records (" ALL ", zone_hash, record_name_hash, rvalue) VALUES "
313         "(?, ?, ?, ?, ?, ?, ?, ?, ?)",
314         &plugin->put_records) != SQLITE_OK) ||
315       (sq_prepare
316        (plugin->dbh,
317         "DELETE FROM ns090records WHERE zone_hash=? AND record_name_hash=?",
318         &plugin->remove_records) != SQLITE_OK) ||
319       (sq_prepare
320        (plugin->dbh,
321         "SELECT " ALL
322         " FROM ns090records WHERE zone_hash=? AND record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?",
323         &plugin->iterate_records) != SQLITE_OK) ||
324       (sq_prepare
325        (plugin->dbh,
326         "SELECT " ALL
327         " FROM ns090records WHERE zone_hash=? ORDER BY rvalue  LIMIT 1 OFFSET ?",
328         &plugin->iterate_by_zone) != SQLITE_OK) ||
329       (sq_prepare
330        (plugin->dbh,
331         "SELECT " ALL 
332         " FROM ns090records WHERE record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?",
333         &plugin->iterate_by_name) != SQLITE_OK) ||
334       (sq_prepare
335         (plugin->dbh,
336         "SELECT " ALL
337         " FROM ns090records ORDER BY rvalue LIMIT 1 OFFSET ?",
338         &plugin->iterate_all) != SQLITE_OK) ||
339       (sq_prepare
340        (plugin->dbh,
341         "DELETE FROM ns090records WHERE zone_hash=?",
342         &plugin->delete_zone) != SQLITE_OK) )
343   {
344     LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling");
345     return GNUNET_SYSERR;
346   }
347 #undef ALL
348   return GNUNET_OK;
349 }
350
351
352 /**
353  * Shutdown database connection and associate data
354  * structures.
355  * @param plugin the plugin context (state for this module)
356  */
357 static void
358 database_shutdown (struct Plugin *plugin)
359 {
360   int result;
361   sqlite3_stmt *stmt;
362
363   if (NULL != plugin->put_records)
364     sqlite3_finalize (plugin->put_records);
365   if (NULL != plugin->remove_records)
366     sqlite3_finalize (plugin->remove_records);
367   if (NULL != plugin->iterate_records)
368     sqlite3_finalize (plugin->iterate_records);
369   if (NULL != plugin->iterate_records)
370     sqlite3_finalize (plugin->iterate_by_zone);
371   if (NULL != plugin->iterate_records)
372     sqlite3_finalize (plugin->iterate_by_name);
373   if (NULL != plugin->iterate_records)
374     sqlite3_finalize (plugin->iterate_all);
375   if (NULL != plugin->delete_zone)
376     sqlite3_finalize (plugin->delete_zone);
377   result = sqlite3_close (plugin->dbh);
378   if (result == SQLITE_BUSY)
379   {
380     LOG (GNUNET_ERROR_TYPE_WARNING,
381          _("Tried to close sqlite without finalizing all prepared statements.\n"));
382     stmt = sqlite3_next_stmt (plugin->dbh, NULL);
383     while (stmt != NULL)
384     {
385       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
386                        "Closing statement %p\n", stmt);
387       result = sqlite3_finalize (stmt);
388       if (result != SQLITE_OK)
389         GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
390                          "Failed to close statement %p: %d\n", stmt, result);
391       stmt = sqlite3_next_stmt (plugin->dbh, NULL);
392     }
393     result = sqlite3_close (plugin->dbh);
394   }
395   if (SQLITE_OK != result)
396     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
397
398   GNUNET_free_non_null (plugin->fn);
399 }
400
401
402 /**
403  * Removes any existing record in the given zone with the same name.
404  *
405  * @param cls closure (internal context for the plugin)
406  * @param zone hash of the public key of the zone
407  * @param name name to remove (at most 255 characters long)
408  * @return GNUNET_OK on success
409  */
410 static int 
411 namestore_sqlite_remove_records (void *cls, 
412                                  const GNUNET_HashCode *zone,
413                                  const char *name)
414 {
415   struct Plugin *plugin = cls;
416   GNUNET_HashCode nh;
417   size_t name_len;
418   int n;
419
420   name_len = strlen (name);
421   GNUNET_CRYPTO_hash (name, name_len, &nh);
422
423   if ((SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
424       (SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 2, &nh, sizeof (GNUNET_HashCode), SQLITE_STATIC)))
425   {
426     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
427                 "sqlite3_bind_XXXX");
428     if (SQLITE_OK != sqlite3_reset (plugin->remove_records))
429       LOG_SQLITE (plugin,
430                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
431                   "sqlite3_reset");
432     return GNUNET_SYSERR;
433   }
434   n = sqlite3_step (plugin->remove_records);
435   if (SQLITE_OK != sqlite3_reset (plugin->remove_records))
436     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
437                 "sqlite3_reset");
438   switch (n)
439   {
440   case SQLITE_DONE:
441     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record removed\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  * Store a record in the datastore.  Removes any existing record in the
457  * same zone with the same name.
458  *
459  * @param cls closure (internal context for the plugin)
460  * @param zone_key public key of the zone
461  * @param expire when does the corresponding block in the DHT expire (until
462  *               when should we never do a DHT lookup for the same name again)?
463  * @param name name that is being mapped (at most 255 characters long)
464  * @param rd_count number of entries in 'rd' array
465  * @param rd array of records with data to store
466  * @param signature signature of the record block, NULL if signature is unavailable (i.e. 
467  *        because the user queried for a particular record type only)
468  * @return GNUNET_OK on success, else GNUNET_SYSERR
469  */
470 static int 
471 namestore_sqlite_put_records (void *cls, 
472                               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
473                               struct GNUNET_TIME_Absolute expire,
474                               const char *name,
475                               unsigned int rd_count,
476                               const struct GNUNET_NAMESTORE_RecordData *rd,
477                               const struct GNUNET_CRYPTO_RsaSignature *signature)
478 {
479   struct Plugin *plugin = cls;
480   int n;
481   GNUNET_HashCode zone;
482   GNUNET_HashCode nh;
483   size_t name_len;
484   uint64_t rvalue;
485   size_t data_size;
486   size_t off;
487   unsigned int i;
488
489   GNUNET_CRYPTO_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone);
490   (void) namestore_sqlite_remove_records (plugin, &zone, name);
491   name_len = strlen (name);
492   GNUNET_CRYPTO_hash (name, name_len, &nh);
493   rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
494   data_size = rd_count * sizeof (struct DbRecord);
495   for (i=0;i<rd_count;i++)  
496     data_size += rd[i].data_size;
497   if (data_size > 64 * 65536)
498   {
499     GNUNET_break (0);
500     return GNUNET_SYSERR;
501   }
502   {
503     char data[data_size];
504     struct DbRecord *rec;
505     
506     rec = (struct DbRecord *) data;
507     off = rd_count * sizeof (struct DbRecord);
508     for (i=0;i<rd_count;i++)  
509     {
510       rec[i].expiration = GNUNET_TIME_absolute_hton (rd[i].expiration);
511       rec[i].data_size = htonl ((uint32_t) rd[i].data_size);
512       rec[i].record_type = htonl (rd[i].record_type);
513       rec[i].flags = htonl (rd[i].flags);
514       memcpy (&data[off],
515               rd[i].data,
516               rd[i].data_size);
517       off += rd[i].data_size;
518     }
519     if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 1, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), SQLITE_STATIC)) ||
520         (SQLITE_OK != sqlite3_bind_text (plugin->put_records, 2, name, -1, SQLITE_STATIC)) ||
521         (SQLITE_OK != sqlite3_bind_int (plugin->put_records, 3, rd_count)) ||
522         (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 4, data, data_size, SQLITE_STATIC)) ||
523         (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 5, expire.abs_value)) ||
524         (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 6, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature), SQLITE_STATIC)) ||
525         (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 7, &zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
526         (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 8, &nh, sizeof (GNUNET_HashCode), SQLITE_STATIC)) ||
527         (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 9, rvalue)) )
528     {
529       LOG_SQLITE (plugin, 
530                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
531                   "sqlite3_bind_XXXX");
532       if (SQLITE_OK != sqlite3_reset (plugin->put_records))
533         LOG_SQLITE (plugin, 
534                     GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
535                     "sqlite3_reset");
536       return GNUNET_SYSERR;
537       
538     }
539     n = sqlite3_step (plugin->put_records);
540     if (SQLITE_OK != sqlite3_reset (plugin->put_records))
541       LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
542                   "sqlite3_reset");
543   }
544   switch (n)
545   {
546   case SQLITE_DONE:
547     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n");
548     return GNUNET_OK;
549   case SQLITE_BUSY:
550     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
551                 "sqlite3_step");
552     return GNUNET_NO;
553   default:
554     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
555                 "sqlite3_step");
556     return GNUNET_SYSERR;  
557   }
558 }
559   
560   
561 /**
562  * Iterate over the results for a particular key and zone in the
563  * datastore.  Will return at most one result to the iterator.
564  *
565  * @param cls closure (internal context for the plugin)
566  * @param zone hash of public key of the zone, NULL to iterate over all zones
567  * @param name_hash hash of name, NULL to iterate over all records of the zone
568  * @param offset offset in the list of all matching records
569  * @param iter function to call with the result
570  * @param iter_cls closure for iter
571  * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error
572  */
573 static int 
574 namestore_sqlite_iterate_records (void *cls, 
575                                   const GNUNET_HashCode *zone,
576                                   const GNUNET_HashCode *name_hash,
577                                   uint64_t offset,
578                                   GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
579 {
580   struct Plugin *plugin = cls;
581   sqlite3_stmt *stmt;
582   unsigned int boff;
583   int ret;
584   int sret;
585
586   if (NULL == zone)
587     if (NULL == name_hash)
588       stmt = plugin->iterate_all;
589     else
590       stmt = plugin->iterate_by_name;
591   else
592     if (NULL == name_hash)
593       stmt = plugin->iterate_by_zone;
594     else
595       stmt = plugin->iterate_records;
596
597   boff = 0;
598   if ( (NULL != zone) &&
599        (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, 
600                                         zone, sizeof (GNUNET_HashCode), 
601                                         SQLITE_STATIC)) )
602   {
603     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
604                 "sqlite3_bind_XXXX");
605     if (SQLITE_OK != sqlite3_reset (stmt))
606       LOG_SQLITE (plugin,
607                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
608                   "sqlite3_reset");
609     return GNUNET_SYSERR;
610   }      
611   if ( (NULL != name_hash) &&
612        (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, 
613                                         name_hash, sizeof (GNUNET_HashCode), 
614                                         SQLITE_STATIC)) )
615   {
616     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
617                 "sqlite3_bind_XXXX");
618     if (SQLITE_OK != sqlite3_reset (stmt))
619       LOG_SQLITE (plugin,
620                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
621                   "sqlite3_reset");
622     return GNUNET_SYSERR;
623   }      
624
625   if (SQLITE_OK != sqlite3_bind_int64 (stmt, ++boff, 
626                                        offset)) 
627   {
628     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
629                 "sqlite3_bind_XXXX");
630     if (SQLITE_OK != sqlite3_reset (stmt))
631       LOG_SQLITE (plugin,
632                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
633                   "sqlite3_reset");
634     return GNUNET_SYSERR;
635   }
636   ret = GNUNET_NO;
637   if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
638   {
639     unsigned int record_count;
640     size_t data_size;
641     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key;
642     const struct GNUNET_CRYPTO_RsaSignature *sig;
643     struct GNUNET_TIME_Absolute expiration;
644     const char *data;
645     const char *name;
646       
647     ret = GNUNET_YES;
648     zone_key =  sqlite3_column_blob (stmt, 0);
649     name = (const char*) sqlite3_column_text (stmt, 1);
650     record_count = sqlite3_column_int (stmt, 2);
651     data_size = sqlite3_column_bytes (stmt, 3);
652     data = sqlite3_column_blob (stmt, 3);
653     expiration.abs_value = (uint64_t) sqlite3_column_int64 (stmt, 4);
654     sig = sqlite3_column_blob (stmt, 5);
655
656     if ( (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != sqlite3_column_bytes (stmt, 0)) ||
657          (sizeof (struct GNUNET_CRYPTO_RsaSignature) != sqlite3_column_bytes (stmt, 5)) ||
658          (sizeof (struct DbRecord) * record_count > data_size) )
659     {
660       GNUNET_break (0);
661       ret = GNUNET_SYSERR;
662     }
663     else
664     {
665       const struct DbRecord *db = (const struct DbRecord*) data;
666       struct GNUNET_NAMESTORE_RecordData rd[record_count];
667       unsigned int i;
668       size_t off;
669
670       off = record_count * sizeof (struct DbRecord);
671       for (i=0;i<record_count;i++)
672       {
673         if (off + ntohl (db[i].data_size) > data_size)
674         {
675           GNUNET_break (0);
676           ret = GNUNET_SYSERR;
677           record_count = i;
678           break;
679         }
680         rd[i].expiration = GNUNET_TIME_absolute_ntoh (db[i].expiration);
681         rd[i].data_size = ntohl (db[i].data_size);
682         rd[i].data = &data[off];
683         rd[i].record_type = ntohl (db[i].record_type);
684         rd[i].flags = ntohl (db[i].flags);
685         off += rd[i].data_size;
686       }     
687       iter (iter_cls, zone_key, expiration, name, 
688             record_count, rd, sig);
689     }
690   }
691   else
692   {
693     if (SQLITE_DONE != sret)
694       LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
695     iter (iter_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL);
696   }
697   if (SQLITE_OK != sqlite3_reset (stmt))
698     LOG_SQLITE (plugin,
699                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
700                 "sqlite3_reset");
701   return ret;
702 }
703
704
705 /**
706  * Delete an entire zone (all records).  Not used in normal operation.
707  *
708  * @param cls closure (internal context for the plugin)
709  * @param zone zone to delete
710  */
711 static void 
712 namestore_sqlite_delete_zone (void *cls,
713                               const GNUNET_HashCode *zone)
714 {
715   struct Plugin *plugin = cls;
716   sqlite3_stmt *stmt = plugin->delete_zone;
717   int n;
718
719   if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC))
720   {
721     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
722                 "sqlite3_bind_XXXX");
723     if (SQLITE_OK != sqlite3_reset (stmt))
724       LOG_SQLITE (plugin,
725                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
726                   "sqlite3_reset");
727     return;
728   }
729   n = sqlite3_step (stmt);
730   if (SQLITE_OK != sqlite3_reset (stmt))
731     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
732                 "sqlite3_reset");
733   switch (n)
734   {
735   case SQLITE_DONE:
736     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Values deleted\n");
737     break;
738   case SQLITE_BUSY:
739     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
740                 "sqlite3_step");
741     break;
742   default:
743     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
744                 "sqlite3_step");
745     break;
746   }
747 }
748
749
750 /**
751  * Entry point for the plugin.
752  *
753  * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
754  * @return NULL on error, othrewise the plugin context
755  */
756 void *
757 libgnunet_plugin_namestore_sqlite_init (void *cls)
758 {
759   static struct Plugin plugin;
760   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
761   struct GNUNET_NAMESTORE_PluginFunctions *api;
762
763   if (NULL != plugin.cfg)
764     return NULL;                /* can only initialize once! */
765   memset (&plugin, 0, sizeof (struct Plugin));
766   plugin.cfg = cfg;  
767   if (GNUNET_OK != database_setup (&plugin))
768   {
769     database_shutdown (&plugin);
770     return NULL;
771   }
772   api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions));
773   api->cls = &plugin;
774   api->put_records = &namestore_sqlite_put_records;
775   api->remove_records = &namestore_sqlite_remove_records;
776   api->iterate_records = &namestore_sqlite_iterate_records;
777   api->delete_zone = &namestore_sqlite_delete_zone;
778   LOG (GNUNET_ERROR_TYPE_INFO, 
779        _("Sqlite database running\n"));
780   return api;
781 }
782
783
784 /**
785  * Exit point from the plugin.
786  *
787  * @param cls the plugin context (as returned by "init")
788  * @return always NULL
789  */
790 void *
791 libgnunet_plugin_namestore_sqlite_done (void *cls)
792 {
793   struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
794   struct Plugin *plugin = api->cls;
795
796   LOG (GNUNET_ERROR_TYPE_DEBUG, 
797        "sqlite plugin is done\n");
798   database_shutdown (plugin);
799   plugin->cfg = NULL;
800   GNUNET_free (api);
801   LOG (GNUNET_ERROR_TYPE_DEBUG, 
802        "sqlite plugin is finished\n");
803   return NULL;
804 }
805
806 /* end of plugin_namestore_sqlite.c */