gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r30230 - in gnunet/src: . include namecache


From: gnunet
Subject: [GNUnet-SVN] r30230 - in gnunet/src: . include namecache
Date: Wed, 16 Oct 2013 21:32:52 +0200

Author: grothoff
Date: 2013-10-16 21:32:52 +0200 (Wed, 16 Oct 2013)
New Revision: 30230

Added:
   gnunet/src/include/gnunet_namecache_plugin.h
   gnunet/src/include/gnunet_namecache_service.h
   gnunet/src/namecache/
   gnunet/src/namecache/Makefile.am
   gnunet/src/namecache/gnunet-namecache.c
   gnunet/src/namecache/gnunet-service-namecache.c
   gnunet/src/namecache/namecache.conf.in
   gnunet/src/namecache/namecache.h
   gnunet/src/namecache/namecache_api.c
   gnunet/src/namecache/plugin_namecache_postgres.c
   gnunet/src/namecache/plugin_namecache_sqlite.c
   gnunet/src/namecache/test_namecache_api.conf
   gnunet/src/namecache/test_namecache_api_cache_block.c
   gnunet/src/namecache/test_plugin_namecache.c
   gnunet/src/namecache/test_plugin_namecache_postgres.conf
   gnunet/src/namecache/test_plugin_namecache_sqlite.conf
Modified:
   gnunet/src/include/Makefile.am
   gnunet/src/include/gnunet_protocols.h
Log:
-copied block-related functions from namestore to namecache

Modified: gnunet/src/include/Makefile.am
===================================================================
--- gnunet/src/include/Makefile.am      2013-10-16 18:12:56 UTC (rev 30229)
+++ gnunet/src/include/Makefile.am      2013-10-16 19:32:52 UTC (rev 30230)
@@ -58,6 +58,8 @@
   gnunet_microphone_lib.h \
   gnunet_mq_lib.h \
   gnunet_mysql_lib.h \
+  gnunet_namecache_plugin.h \
+  gnunet_namecache_service.h \
   gnunet_namestore_plugin.h \
   gnunet_namestore_service.h \
   gnunet_nat_lib.h \

Added: gnunet/src/include/gnunet_namecache_plugin.h
===================================================================
--- gnunet/src/include/gnunet_namecache_plugin.h                                
(rev 0)
+++ gnunet/src/include/gnunet_namecache_plugin.h        2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,101 @@
+/*
+     This file is part of GNUnet
+     (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file include/gnunet_namecache_plugin.h
+ * @brief plugin API for the namecache database backend
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_NAMECACHE_PLUGIN_H
+#define GNUNET_NAMECACHE_PLUGIN_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_namestore_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/**
+ * Function called for matching blocks.
+ *
+ * @param cls closure
+ * @param block lookup result
+ */
+typedef void (*GNUNET_NAMECACHE_BlockCallback) (void *cls,
+                                               const struct 
GNUNET_NAMESTORE_Block *block);
+
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct GNUNET_NAMECACHE_PluginFunctions
+{
+
+  /**
+   * Closure to pass to all plugin functions.
+   */
+  void *cls;
+
+  /**
+   * Cache a block in the datastore. Overwrites existing blocks
+   * for the same zone and label.
+   *
+   * @param cls closure (internal context for the plugin)
+   * @param block block to cache
+   * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+   */
+  int (*cache_block) (void *cls,
+                     const struct GNUNET_NAMESTORE_Block *block);
+
+
+  /**
+   * Get the block for a particular zone and label in the
+   * datastore.  Will return at most one result to the iterator.
+   *
+   * @param cls closure (internal context for the plugin)
+   * @param query hash of public key derived from the zone and the label
+   * @param iter function to call with the result
+   * @param iter_cls closure for @a iter
+   * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, 
#GNUNET_SYSERR on error
+   */
+  int (*lookup_block) (void *cls,
+                      const struct GNUNET_HashCode *query,
+                      GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls);
+
+
+};
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* end of gnunet_namecache_plugin.h */
+#endif

Added: gnunet/src/include/gnunet_namecache_service.h
===================================================================
--- gnunet/src/include/gnunet_namecache_service.h                               
(rev 0)
+++ gnunet/src/include/gnunet_namecache_service.h       2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,163 @@
+/*
+     This file is part of GNUnet
+     (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file include/gnunet_namecache_service.h
+ * @brief API that can be used to store naming information on a GNUnet node;
+ *        Naming information can either be records for which this peer/user
+ *        is authoritative, or blocks which are cached, encrypted naming
+ *        data from other peers.
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_NAMECACHE_SERVICE_H
+#define GNUNET_NAMECACHE_SERVICE_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet_block_lib.h"
+#include "gnunet_namestore_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/**
+ * Entry in the queue.
+ */
+struct GNUNET_NAMECACHE_QueueEntry;
+
+/**
+ * Handle to the namecache service.
+ */
+struct GNUNET_NAMECACHE_Handle;
+
+/**
+ * Maximum size of a value that can be stored in the namecache.
+ */
+#define GNUNET_NAMECACHE_MAX_VALUE_SIZE (63 * 1024)
+
+
+/**
+ * Connect to the namecache service.
+ *
+ * @param cfg configuration to use
+ * @return handle to use to access the service
+ */
+struct GNUNET_NAMECACHE_Handle *
+GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Disconnect from the namecache service (and free associated
+ * resources).  Must not be called from within operation callbacks of
+ * the API.
+ *
+ * @param h handle to the namecache
+ */
+void
+GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h);
+
+
+/**
+ * Continuation called to notify client about result of the
+ * operation.
+ *
+ * @param cls closure
+ * @param success #GNUNET_SYSERR on failure (including timeout/queue 
drop/failure to validate)
+ *                #GNUNET_NO if content was already there or not found
+ *                #GNUNET_YES (or other positive value) on success
+ * @param emsg NULL on success, otherwise an error message
+ */
+typedef void (*GNUNET_NAMECACHE_ContinuationWithStatus) (void *cls,
+                                                         int32_t success,
+                                                         const char *emsg);
+
+
+
+/**
+ * Store an item in the namecache.  If the item is already present,
+ * it is replaced with the new record.
+ *
+ * @param h handle to the namecache
+ * @param block block to store
+ * @param cont continuation to call when done
+ * @param cont_cls closure for @a cont
+ * @return handle to abort the request
+ */
+struct GNUNET_NAMECACHE_QueueEntry *
+GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
+                             const struct GNUNET_NAMESTORE_Block *block,
+                             GNUNET_NAMECACHE_ContinuationWithStatus cont,
+                             void *cont_cls);
+
+
+/**
+ * Process a record that was stored in the namecache.
+ *
+ * @param cls closure
+ * @param block block that was stored in the namecache
+ */
+typedef void (*GNUNET_NAMECACHE_BlockProcessor) (void *cls,
+                                                const struct 
GNUNET_NAMESTORE_Block *block);
+
+
+/**
+ * Get a result for a particular key from the namecache.  The processor
+ * will only be called once.
+ *
+ * @param h handle to the namecache
+ * @param derived_hash hash of zone key combined with name to lookup
+ *        then at the end once with NULL
+ * @param proc function to call on the matching block, or with
+ *        NULL if there is no matching block
+ * @param proc_cls closure for @a proc
+ * @return a handle that can be used to cancel
+ */
+struct GNUNET_NAMECACHE_QueueEntry *
+GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
+                              const struct GNUNET_HashCode *derived_hash,
+                              GNUNET_NAMECACHE_BlockProcessor proc, void 
*proc_cls);
+
+
+/**
+ * Cancel a namecache operation.  The final callback from the
+ * operation must not have been done yet.  Must be called on any
+ * namecache operation that has not yet completed prior to calling
+ * #GNUNET_NAMECACHE_disconnect.
+ *
+ * @param qe operation to cancel
+ */
+void
+GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* end of gnunet_namecache_service.h */
+#endif

Modified: gnunet/src/include/gnunet_protocols.h
===================================================================
--- gnunet/src/include/gnunet_protocols.h       2013-10-16 18:12:56 UTC (rev 
30229)
+++ gnunet/src/include/gnunet_protocols.h       2013-10-16 19:32:52 UTC (rev 
30230)
@@ -1350,38 +1350,46 @@
 
 
 
/*******************************************************************************
- * NAMESTORE message types
+ * NAMECACHE message types
  
******************************************************************************/
 
 /**
  * Client to service: lookup block
  */
 #define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK 431
+#define GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK 431
 
 /**
  * Service to client: result of block lookup
  */
 #define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE 432
+#define GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE 432
 
 /**
- * Client to service: store records (as authority)
+ * Client to service: cache a block
  */
-#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE 433
+#define GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE 433
+#define GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE 433
 
 /**
- * Service to client: result of store operation.
+ * Service to client: result of block cache request
  */
-#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE 434
+#define GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE 434
+#define GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE 434
 
+/*******************************************************************************
+ * NAMESTORE message types
+ 
******************************************************************************/
+
 /**
- * Client to service: cache a block
+ * Client to service: store records (as authority)
  */
-#define GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE 435
+#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE 435
 
 /**
- * Service to client: result of block cache request
+ * Service to client: result of store operation.
  */
-#define GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE 436
+#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE 436
 
 /**
  * Client to service: "reverse" lookup for zone name based on zone key

Index: gnunet/src/namecache
===================================================================
--- gnunet/src/namecache        2013-10-16 18:12:56 UTC (rev 30229)
+++ gnunet/src/namecache        2013-10-16 19:32:52 UTC (rev 30230)

Property changes on: gnunet/src/namecache
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,9 ##
+test_plugin_namecache_sqlite
+test_plugin_namecache_postgres
+test_namecache_api_cache_block
+namecache.conf
+Makefile.in
+Makefile
+gnunet-service-namecache
+gnunet-namecache
+.deps
Added: gnunet/src/namecache/Makefile.am
===================================================================
--- gnunet/src/namecache/Makefile.am                            (rev 0)
+++ gnunet/src/namecache/Makefile.am    2013-10-16 19:32:52 UTC (rev 30230)
@@ -0,0 +1,164 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+plugindir = $(libdir)/gnunet
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+   namecache.conf
+
+
+if MINGW
+  WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIBS = -lgcov
+endif
+
+if HAVE_SQLITE
+SQLITE_PLUGIN = libgnunet_plugin_namecache_sqlite.la
+if HAVE_TESTING
+SQLITE_TESTS = test_plugin_namecache_sqlite
+endif
+endif
+
+if HAVE_POSTGRES
+POSTGRES_PLUGIN = libgnunet_plugin_namecache_postgres.la
+if HAVE_TESTING
+POSTGRES_TESTS = test_plugin_namecache_postgres
+endif
+endif
+
+# testcases do not even build yet; thus: experimental!
+if HAVE_TESTING
+TESTING_TESTS = \
+ test_namecache_api_cache_block
+endif
+
+if HAVE_SQLITE
+check_PROGRAMS = \
+ $(SQLITE_TESTS) \
+ $(POSTGRES_TESTS) \
+ $(TESTING_TESTS)
+endif
+
+if ENABLE_TEST_RUN
+TESTS = \
+  $(check_PROGRAMS)
+endif
+
+lib_LTLIBRARIES = \
+  libgnunetnamecache.la
+
+
+libgnunetnamecache_la_SOURCES = \
+  namecache_api.c \
+  namecache.h
+libgnunetnamecache_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL)
+libgnunetnamecache_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+libexec_PROGRAMS = \
+ gnunet-service-namecache
+
+bin_PROGRAMS = \
+ gnunet-namecache
+
+gnunet_namecache_SOURCES = \
+ gnunet-namecache.c
+gnunet_namecache_LDADD = \
+  $(top_builddir)/src/namestore/libgnunetnamestore.la \
+  $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la \
+  $(GN_LIBINTL)
+gnunet_namecache_DEPENDENCIES = \
+  $(top_builddir)/src/identity/libgnunetidentity.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la
+
+
+gnunet_service_namecache_SOURCES = \
+ gnunet-service-namecache.c
+
+gnunet_service_namecache_LDADD = \
+  $(top_builddir)/src/namestore/libgnunetnamestore.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la \
+  $(GN_LIBINTL)
+gnunet_service_namecache_DEPENDENCIES = \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la
+
+
+plugin_LTLIBRARIES = \
+  $(SQLITE_PLUGIN) \
+  $(POSTGRES_PLUGIN)
+
+libgnunet_plugin_namecache_sqlite_la_SOURCES = \
+  plugin_namecache_sqlite.c
+libgnunet_plugin_namecache_sqlite_la_LIBADD = \
+  $(top_builddir)/src/namecache/libgnunetnamecache.la  \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
+  $(LTLIBINTL)
+libgnunet_plugin_namecache_sqlite_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_namecache_sqlite_la_DEPENDENCIES = \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la
+
+
+libgnunet_plugin_namecache_postgres_la_SOURCES = \
+  plugin_namecache_postgres.c
+libgnunet_plugin_namecache_postgres_la_LIBADD = \
+  $(top_builddir)/src/namecache/libgnunetnamecache.la  \
+  $(top_builddir)/src/postgres/libgnunetpostgres.la  \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
+  $(LTLIBINTL)
+libgnunet_plugin_namecache_postgres_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_namecache_postgres_la_DEPENDENCIES = \
+  $(top_builddir)/src/postgres/libgnunetpostgres.la  \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  libgnunetnamecache.la
+
+test_namecache_api_cache_block_SOURCES = \
+ test_namecache_api_cache_block.c
+test_namecache_api_cache_block_LDADD = \
+  $(top_builddir)/src/namestore/libgnunetnamestore.la \
+  $(top_builddir)/src/namecache/libgnunetnamecache.la \
+  $(top_builddir)/src/testing/libgnunettesting.la \
+  $(top_builddir)/src/util/libgnunetutil.la
+
+test_plugin_namecache_sqlite_SOURCES = \
+ test_plugin_namecache.c
+test_plugin_namecache_sqlite_LDADD = \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_plugin_namecache_postgres_SOURCES = \
+ test_plugin_namecache.c
+test_plugin_namecache_postgres_LDADD = \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+EXTRA_DIST = \
+  test_namecache_api.conf \
+  test_plugin_namecache_sqlite.conf \
+  test_plugin_namecache_postgres.conf \
+  test_namecache_defaults.conf
+

Added: gnunet/src/namecache/gnunet-namecache.c
===================================================================
--- gnunet/src/namecache/gnunet-namecache.c                             (rev 0)
+++ gnunet/src/namecache/gnunet-namecache.c     2013-10-16 19:32:52 UTC (rev 
30230)
@@ -0,0 +1,252 @@
+
+/*
+     This file is part of GNUnet.
+     (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file gnunet-namecache.c
+ * @brief command line tool to inspect the name cache
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - test
+ */
+#include "platform.h"
+#include <gnunet_util_lib.h>
+#include <gnunet_dnsparser_lib.h>
+#include <gnunet_identity_service.h>
+#include <gnunet_gnsrecord_lib.h>
+#include <gnunet_namecache_service.h>
+#include <gnunet_namestore_service.h>
+
+
+/**
+ * Handle to the namecache.
+ */
+static struct GNUNET_NAMECACHE_Handle *ns;
+
+/**
+ * Queue entry for the 'query' operation.
+ */
+static struct GNUNET_NAMECACHE_QueueEntry *qe;
+
+/**
+ * Name (label) of the records to list.
+ */
+static char *name;
+
+/**
+ * Public key of the zone to look in.
+ */
+static struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+
+/**
+ * Public key of the zone to look in, in ASCII.
+ */
+static char *pkey;
+
+/**
+ * Global return value
+ */
+static int ret;
+
+
+/**
+ * Task run on shutdown.  Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_shutdown (void *cls,
+            const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  if (NULL != qe)
+  {
+    GNUNET_NAMECACHE_cancel (qe);
+    qe = NULL;
+  }
+  if (NULL != ns)
+  {
+    GNUNET_NAMECACHE_disconnect (ns);
+    ns = NULL;
+  }
+}
+
+
+/**
+ * Process a record that was stored in the namecache in a block.
+ *
+ * @param cls closure, NULL
+ * @param rd_len number of entries in @a rd array
+ * @param rd array of records with data to store
+ */
+static void
+display_records_from_block (void *cls,
+                           unsigned int rd_len,
+                           const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  const char *typestring;
+  char *s;
+  unsigned int i;
+
+  if (0 == rd_len)
+  {
+    FPRINTF (stdout,
+            _("No records found for `%s'"),
+            name);
+    return;
+  }
+  FPRINTF (stdout,
+          "%s:\n",
+          name);
+  for (i=0;i<rd_len;i++)
+  {
+    typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
+    s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+                                         rd[i].data,
+                                         rd[i].data_size);
+    if (NULL == s)
+    {
+      FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
+              (unsigned int) rd[i].record_type);
+      continue;
+    }
+    FPRINTF (stdout,
+            "\t%s: %s\n",
+            typestring,
+            s);
+    GNUNET_free (s);
+  }
+  FPRINTF (stdout, "%s", "\n");
+}
+
+
+/**
+ * Display block obtained from listing (by name).
+ *
+ * @param cls NULL
+ * @param block NULL if not found
+ */
+static void
+handle_block (void *cls,
+             const struct GNUNET_NAMESTORE_Block *block)
+{
+  qe = NULL;
+  if (NULL == block)
+  {
+    fprintf (stderr,
+            "No matching block found\n");
+  }
+  else if (GNUNET_OK !=
+          GNUNET_NAMESTORE_block_decrypt (block,
+                                          &pubkey,
+                                          name,
+                                          &display_records_from_block,
+                                          NULL))
+  {
+    fprintf (stderr,
+            "Failed to decrypt block!\n");
+  }
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_HashCode dhash;
+
+  if (NULL == pkey)
+  {
+    fprintf (stderr,
+            _("You must specify which zone should be accessed\n"));
+    return;
+  }
+
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey,
+                                                  strlen (pkey),
+                                                  &pubkey))
+  {
+    fprintf (stderr,
+             _("Invalid public key for reverse lookup `%s'\n"),
+             pkey);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &do_shutdown,
+                                NULL);
+  GNUNET_NAMESTORE_query_from_public_key (&pubkey,
+                                          name,
+                                          &dhash);
+  qe = GNUNET_NAMECACHE_lookup_block (ns,
+                                      &dhash,
+                                      &handle_block,
+                                      NULL);
+}
+
+
+/**
+ * The main function for gnunet-namecache.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    {'n', "name", "NAME",
+     gettext_noop ("name of the record to add/delete/display"), 1,
+     &GNUNET_GETOPT_set_string, &name},
+    {'z', "zone", "PKEY",
+     gettext_noop ("spezifies the public key of the zone to look in"), 1,
+     &GNUNET_GETOPT_set_string, &pkey},
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+    return 2;
+
+  GNUNET_log_setup ("gnunet-namecache", "WARNING", NULL);
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run (argc, argv, "gnunet-namecache",
+                         _("GNUnet zone manipulation tool"),
+                         options,
+                         &run, NULL))
+  {
+    GNUNET_free ((void*) argv);
+    return 1;
+  }
+  GNUNET_free ((void*) argv);
+  return ret;
+}
+
+/* end of gnunet-namecache.c */

Added: gnunet/src/namecache/gnunet-service-namecache.c
===================================================================
--- gnunet/src/namecache/gnunet-service-namecache.c                             
(rev 0)
+++ gnunet/src/namecache/gnunet-service-namecache.c     2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,429 @@
+/*
+     This file is part of GNUnet.
+     (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file namecache/gnunet-service-namecache.c
+ * @brief namecache for the GNUnet naming system
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dnsparser_lib.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_namecache_plugin.h"
+#include "gnunet_signatures.h"
+#include "namecache.h"
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file 
(kind, "util", syscall, filename)
+
+
+/**
+ * A namecache client
+ */
+struct NamecacheClient;
+
+
+/**
+ * A namecache client
+ */
+struct NamecacheClient
+{
+  /**
+   * Next element in the DLL
+   */
+  struct NamecacheClient *next;
+
+  /**
+   * Previous element in the DLL
+   */
+  struct NamecacheClient *prev;
+
+  /**
+   * The client
+   */
+  struct GNUNET_SERVER_Client *client;
+
+};
+
+
+/**
+ * Configuration handle.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
+
+/**
+ * Database handle
+ */
+static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
+
+/**
+ * Name of the database plugin
+ */
+static char *db_lib_name;
+
+/**
+ * Our notification context.
+ */
+static struct GNUNET_SERVER_NotificationContext *snc;
+
+/**
+ * Head of the Client DLL
+ */
+static struct NamecacheClient *client_head;
+
+/**
+ * Tail of the Client DLL
+ */
+static struct NamecacheClient *client_tail;
+
+/**
+ * Notification context shared by all monitors.
+ */
+static struct GNUNET_SERVER_NotificationContext *monitor_nc;
+
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct NamecacheClient *nc;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Stopping namecache service\n");
+  if (NULL != snc)
+  {
+    GNUNET_SERVER_notification_context_destroy (snc);
+    snc = NULL;
+  }
+  while (NULL != (nc = client_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
+    GNUNET_SERVER_client_set_user_context (nc->client, NULL);
+    GNUNET_free (nc);
+  }
+  GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
+  GNUNET_free (db_lib_name);
+  db_lib_name = NULL;
+  if (NULL != monitor_nc)
+  {
+    GNUNET_SERVER_notification_context_destroy (monitor_nc);
+    monitor_nc = NULL;
+  }
+}
+
+
+/**
+ * Called whenever a client is disconnected.
+ * Frees our resources associated with that client.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+static void
+client_disconnect_notification (void *cls,
+                               struct GNUNET_SERVER_Client *client)
+{
+  struct NamecacheClient *nc;
+
+  if (NULL == client)
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Client %p disconnected\n",
+             client);
+  if (NULL == (nc = GNUNET_SERVER_client_get_user_context (client, struct 
NamecacheClient)))
+    return;
+  GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
+  GNUNET_free (nc);
+}
+
+
+/**
+ * Add a client to our list of active clients, if it is not yet
+ * in there.
+ *
+ * @param client client to add
+ * @return internal namecache client structure for this client
+ */
+static struct NamecacheClient *
+client_lookup (struct GNUNET_SERVER_Client *client)
+{
+  struct NamecacheClient *nc;
+
+  nc = GNUNET_SERVER_client_get_user_context (client, struct NamecacheClient);
+  if (NULL != nc)
+    return nc;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Client %p connected\n",
+             client);
+  nc = GNUNET_new (struct NamecacheClient);
+  nc->client = client;
+  GNUNET_SERVER_notification_context_add (snc, client);
+  GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
+  GNUNET_SERVER_client_set_user_context (client, nc);
+  return nc;
+}
+
+
+/**
+ * Context for name lookups passed from #handle_lookup_block to
+ * #handle_lookup_block_it as closure
+ */
+struct LookupBlockContext
+{
+  /**
+   * The client to send the response to
+   */
+  struct NamecacheClient *nc;
+
+  /**
+   * Operation id for the name lookup
+   */
+  uint32_t request_id;
+
+};
+
+
+/**
+ * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
+ *
+ * @param cls a `struct LookupNameContext *` with information about the request
+ * @param block the block
+ */
+static void
+handle_lookup_block_it (void *cls,
+                       const struct GNUNET_NAMESTORE_Block *block)
+{
+  struct LookupBlockContext *lnc = cls;
+  struct LookupBlockResponseMessage *r;
+  size_t esize;
+
+  esize = ntohl (block->purpose.size)
+    - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
+    - sizeof (struct GNUNET_TIME_AbsoluteNBO);
+  r = GNUNET_malloc (sizeof (struct LookupBlockResponseMessage) + esize);
+  r->gns_header.header.type = htons 
(GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
+  r->gns_header.header.size = htons (sizeof (struct 
LookupBlockResponseMessage) + esize);
+  r->gns_header.r_id = htonl (lnc->request_id);
+  r->expire = block->expiration_time;
+  r->signature = block->signature;
+  r->derived_key = block->derived_key;
+  memcpy (&r[1], &block[1], esize);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Sending `%s' message with expiration time %s\n",
+             "NAMECACHE_LOOKUP_BLOCK_RESPONSE",
+              GNUNET_STRINGS_absolute_time_to_string 
(GNUNET_TIME_absolute_ntoh (r->expire)));
+  GNUNET_SERVER_notification_context_unicast (snc,
+                                             lnc->nc->client,
+                                             &r->gns_header.header,
+                                             GNUNET_NO);
+  GNUNET_free (r);
+}
+
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
+ *
+ * @param cls unused
+ * @param client client sending the message
+ * @param message message of type 'struct LookupNameMessage'
+ */
+static void
+handle_lookup_block (void *cls,
+                    struct GNUNET_SERVER_Client *client,
+                    const struct GNUNET_MessageHeader *message)
+{
+  const struct LookupBlockMessage *ln_msg;
+  struct LookupBlockContext lnc;
+  struct NamecacheClient *nc;
+  struct LookupBlockResponseMessage zir_end;
+  int ret;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message\n",
+             "NAMECACHE_LOOKUP_BLOCK");
+  nc = client_lookup(client);
+  ln_msg = (const struct LookupBlockMessage *) message;
+  lnc.request_id = ntohl (ln_msg->gns_header.r_id);
+  lnc.nc = nc;
+  if (GNUNET_SYSERR ==
+      (ret = GSN_database->lookup_block (GSN_database->cls,
+                                        &ln_msg->query,
+                                        &handle_lookup_block_it, &lnc)))
+  {
+    /* internal error (in database plugin); might be best to just hang up on
+       plugin rather than to signal that there are 'no' results, which
+       might also be false... */
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  if (0 == ret)
+  {
+    /* no records match at all, generate empty response */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Sending empty `%s' message\n",
+               "NAMECACHE_LOOKUP_BLOCK_RESPONSE");
+    memset (&zir_end, 0, sizeof (zir_end));
+    zir_end.gns_header.header.type = htons 
(GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
+    zir_end.gns_header.header.size = htons (sizeof (struct 
LookupBlockResponseMessage));
+    zir_end.gns_header.r_id = ln_msg->gns_header.r_id;
+    GNUNET_SERVER_notification_context_unicast (snc,
+                                               client,
+                                               &zir_end.gns_header.header,
+                                               GNUNET_NO);
+
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
+ *
+ * @param cls unused
+ * @param client client sending the message
+ * @param message message of type 'struct BlockCacheMessage'
+ */
+static void
+handle_block_cache (void *cls,
+                    struct GNUNET_SERVER_Client *client,
+                    const struct GNUNET_MessageHeader *message)
+{
+  struct NamecacheClient *nc;
+  const struct BlockCacheMessage *rp_msg;
+  struct BlockCacheResponseMessage rpr_msg;
+  struct GNUNET_NAMESTORE_Block *block;
+  size_t esize;
+  int res;
+
+  nc = client_lookup (client);
+  if (ntohs (message->size) < sizeof (struct BlockCacheMessage))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  rp_msg = (const struct BlockCacheMessage *) message;
+  esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct 
BlockCacheMessage);
+  block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) + esize);
+  block->signature = rp_msg->signature;
+  block->derived_key = rp_msg->derived_key;
+  block->purpose.size = htonl (sizeof (struct 
GNUNET_CRYPTO_EccSignaturePurpose) +
+                              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+                              esize);
+  block->expiration_time = rp_msg->expire;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message with expiration time %s\n",
+             "NAMECACHE_BLOCK_CACHE",
+              GNUNET_STRINGS_absolute_time_to_string 
(GNUNET_TIME_absolute_ntoh (block->expiration_time)));
+  memcpy (&block[1], &rp_msg[1], esize);
+  res = GSN_database->cache_block (GSN_database->cls,
+                                  block);
+  GNUNET_free (block);
+
+  rpr_msg.gns_header.header.type = htons 
(GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
+  rpr_msg.gns_header.header.size = htons (sizeof (struct 
BlockCacheResponseMessage));
+  rpr_msg.gns_header.r_id = rp_msg->gns_header.r_id;
+  rpr_msg.op_result = htonl (res);
+  GNUNET_SERVER_notification_context_unicast (snc,
+                                             nc->client,
+                                             &rpr_msg.gns_header.header,
+                                             GNUNET_NO);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Process namecache requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&handle_lookup_block, NULL,
+     GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK, sizeof (struct 
LookupBlockMessage)},
+    {&handle_block_cache, NULL,
+    GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE, 0},
+    {NULL, NULL, 0, 0}
+  };
+  char *database;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namecache service\n");
+  GSN_cfg = cfg;
+  monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
+
+  /* Loading database plugin */
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg, "namecache", "database",
+                                             &database))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
+
+  GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namecache_%s", database);
+  GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
+  GNUNET_free (database);
+  if (NULL == GSN_database)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               "Could not load database backend `%s'\n",
+               db_lib_name);
+    GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
+    return;
+  }
+
+  /* Configuring server handles */
+  GNUNET_SERVER_add_handlers (server, handlers);
+  snc = GNUNET_SERVER_notification_context_create (server, 16);
+  GNUNET_SERVER_disconnect_notify (server,
+                                   &client_disconnect_notification,
+                                   NULL);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
+                                NULL);
+}
+
+
+/**
+ * The main function for the template service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  return (GNUNET_OK ==
+          GNUNET_SERVICE_run (argc, argv, "namecache",
+                              GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-namecache.c */
+

Added: gnunet/src/namecache/namecache.conf.in
===================================================================
--- gnunet/src/namecache/namecache.conf.in                              (rev 0)
+++ gnunet/src/namecache/namecache.conf.in      2013-10-16 19:32:52 UTC (rev 
30230)
@@ -0,0 +1,22 @@
+[namecache]
+AUTOSTART = YES
+USER_SERVICE = YES
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-namecache.sock
+UNIX_MATCH_UID = NO
+UNIX_MATCH_GID = YES
address@hidden@ PORT = 2099
+HOSTNAME = localhost
+BINARY = gnunet-service-namecache
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+DATABASE = sqlite
+
+[namecache-sqlite]
+FILENAME = $GNUNET_DATA_HOME/namecache/sqlite.db
+
+[namecache-postgres]
+CONFIG = connect_timeout=10; dbname=gnunet
+TEMPORARY_TABLE = NO
+
+
+

Added: gnunet/src/namecache/namecache.h
===================================================================
--- gnunet/src/namecache/namecache.h                            (rev 0)
+++ gnunet/src/namecache/namecache.h    2013-10-16 19:32:52 UTC (rev 30230)
@@ -0,0 +1,152 @@
+/*
+     This file is part of GNUnet.
+     (C) 2011-2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file namecache/namecache.h
+ * @brief common internal definitions for namecache service
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#ifndef NAMECACHE_H
+#define NAMECACHE_H
+
+/**
+ * Maximum length of any name, including 0-termination.
+ */
+#define MAX_NAME_LEN 256
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Generic namecache message with op id
+ */
+struct GNUNET_NAMECACHE_Header
+{
+  /**
+   * header.type will be GNUNET_MESSAGE_TYPE_NAMECACHE_*
+   * header.size will be message size
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Request ID in NBO
+   */
+  uint32_t r_id GNUNET_PACKED;
+};
+
+
+/**
+ * Lookup a block in the namecache
+ */
+struct LookupBlockMessage
+{
+  /**
+   * Type will be #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK
+   */
+  struct GNUNET_NAMECACHE_Header gns_header;
+
+  /**
+   * The query.
+   */
+  struct GNUNET_HashCode query GNUNET_PACKED;
+
+};
+
+
+/**
+ * Lookup response
+ */
+struct LookupBlockResponseMessage
+{
+  /**
+   * Type will be #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE
+   */
+  struct GNUNET_NAMECACHE_Header gns_header;
+
+  /**
+   * Expiration time
+   */
+  struct GNUNET_TIME_AbsoluteNBO expire;
+
+  /**
+   * Signature.
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+  /**
+   * Derived public key.
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
+
+  /* follwed by encrypted block data */
+};
+
+
+/**
+ * Cache a record in the namecache.
+ */
+struct BlockCacheMessage
+{
+  /**
+   * Type will be #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE
+   */
+  struct GNUNET_NAMECACHE_Header gns_header;
+
+  /**
+   * Expiration time
+   */
+  struct GNUNET_TIME_AbsoluteNBO expire;
+
+  /**
+   * Signature.
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+  /**
+   * Derived public key.
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
+
+  /* follwed by encrypted block data */
+};
+
+
+/**
+ * Response to a request to cache a block.
+ */
+struct BlockCacheResponseMessage
+{
+  /**
+   * Type will be #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
+   */
+  struct GNUNET_NAMECACHE_Header gns_header;
+
+  /**
+   * #GNUNET_OK on success, #GNUNET_SYSERR error
+   */
+  int32_t op_result GNUNET_PACKED;
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/* end of namecache.h */
+#endif

Added: gnunet/src/namecache/namecache_api.c
===================================================================
--- gnunet/src/namecache/namecache_api.c                                (rev 0)
+++ gnunet/src/namecache/namecache_api.c        2013-10-16 19:32:52 UTC (rev 
30230)
@@ -0,0 +1,738 @@
+/*
+     This file is part of GNUnet.
+     (C) 2010-2013 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file namecache/namecache_api.c
+ * @brief API to access the NAMECACHE service
+ * @author Martin Schanzenbach
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_dnsparser_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_signatures.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_namestore_service.h"
+#include "namecache.h"
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
+
+
+/**
+ * An QueueEntry used to store information for a pending
+ * NAMECACHE record operation
+ */
+struct GNUNET_NAMECACHE_QueueEntry
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct GNUNET_NAMECACHE_QueueEntry *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct GNUNET_NAMECACHE_QueueEntry *prev;
+
+  /**
+   * Main handle to access the namecache.
+   */
+  struct GNUNET_NAMECACHE_Handle *nsh;
+
+  /**
+   * Continuation to call
+   */
+  GNUNET_NAMECACHE_ContinuationWithStatus cont;
+
+  /**
+   * Closure for @e cont.
+   */
+  void *cont_cls;
+
+  /**
+   * Function to call with the blocks we get back; or NULL.
+   */
+  GNUNET_NAMESTORE_BlockProcessor block_proc;
+
+  /**
+   * Closure for @e block_proc.
+   */
+  void *block_proc_cls;
+
+  /**
+   * The operation id this zone iteration operation has
+   */
+  uint32_t op_id;
+
+};
+
+
+/**
+ * Message in linked list we should send to the service.  The
+ * actual binary message follows this struct.
+ */
+struct PendingMessage
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct PendingMessage *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct PendingMessage *prev;
+
+  /**
+   * Size of the message.
+   */
+  size_t size;
+
+};
+
+
+/**
+ * Connection to the NAMECACHE service.
+ */
+struct GNUNET_NAMECACHE_Handle
+{
+
+  /**
+   * Configuration to use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Socket (if available).
+   */
+  struct GNUNET_CLIENT_Connection *client;
+
+  /**
+   * Currently pending transmission request (or NULL).
+   */
+  struct GNUNET_CLIENT_TransmitHandle *th;
+
+  /**
+   * Head of linked list of pending messages to send to the service
+   */
+  struct PendingMessage *pending_head;
+
+  /**
+   * Tail of linked list of pending messages to send to the service
+   */
+  struct PendingMessage *pending_tail;
+
+  /**
+   * Head of pending namecache queue entries
+   */
+  struct GNUNET_NAMECACHE_QueueEntry *op_head;
+
+  /**
+   * Tail of pending namecache queue entries
+   */
+  struct GNUNET_NAMECACHE_QueueEntry *op_tail;
+
+  /**
+   * Reconnect task
+   */
+  GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+  /**
+   * Delay introduced before we reconnect.
+   */
+  struct GNUNET_TIME_Relative reconnect_delay;
+
+  /**
+   * Should we reconnect to service due to some serious error?
+   */
+  int reconnect;
+
+  /**
+   * Did we start to receive yet?
+   */
+  int is_receiving;
+
+  /**
+   * The last operation id used for a NAMECACHE operation
+   */
+  uint32_t last_op_id_used;
+
+};
+
+
+/**
+ * Disconnect from service and then reconnect.
+ *
+ * @param h our handle
+ */
+static void
+force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
+
+
+/**
+ * Handle an incoming message of type
+ * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
+ *
+ * @param qe the respective entry in the message queue
+ * @param msg the message we received
+ * @param size the message size
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT 
notify the client
+ */
+static int
+handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
+                             const struct LookupBlockResponseMessage *msg,
+                             size_t size)
+{
+  struct GNUNET_NAMESTORE_Block *block;
+  char buf[size + sizeof (struct GNUNET_NAMESTORE_Block)
+          - sizeof (struct LookupBlockResponseMessage)];
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received `%s'\n",
+       "LOOKUP_BLOCK_RESPONSE");
+  if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
+  {
+    /* no match found */
+    if (NULL != qe->block_proc)
+      qe->block_proc (qe->block_proc_cls, NULL);
+    return GNUNET_OK;
+  }
+
+  block = (struct GNUNET_NAMESTORE_Block *) buf;
+  block->signature = msg->signature;
+  block->derived_key = msg->derived_key;
+  block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
+  block->purpose.size = htonl (size - sizeof (struct 
LookupBlockResponseMessage) +
+                              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+                              sizeof (struct 
GNUNET_CRYPTO_EccSignaturePurpose));
+  block->expiration_time = msg->expire;
+  memcpy (&block[1],
+         &msg[1],
+         size - sizeof (struct LookupBlockResponseMessage));
+  if (GNUNET_OK !=
+      GNUNET_NAMESTORE_block_verify (block))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (NULL != qe->block_proc)
+    qe->block_proc (qe->block_proc_cls, block);
+  else
+    GNUNET_break (0);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle an incoming message of type
+ * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
+ *
+ * @param qe the respective entry in the message queue
+ * @param msg the message we received
+ * @param size the message size
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT 
notify the client
+ */
+static int
+handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
+                           const struct BlockCacheResponseMessage *msg,
+                           size_t size)
+{
+  int res;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received `%s'\n",
+       "BLOCK_CACHE_RESPONSE");
+  res = ntohl (msg->op_result);
+  /* TODO: add actual error message from namecache to response... */
+  if (NULL != qe->cont)
+    qe->cont (qe->cont_cls,
+             res,
+             (GNUNET_OK == res) ?
+             NULL
+             : _("Namecache failed to cache block"));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle incoming messages for record operations
+ *
+ * @param qe the respective zone iteration handle
+ * @param msg the message we received
+ * @param type the message type in host byte order
+ * @param size the message size
+ * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about
+ *         the error, #GNUNET_SYSERR on error and we did NOT notify the client
+ */
+static int
+manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe,
+                          const struct GNUNET_MessageHeader *msg,
+                          uint16_t type,
+                         size_t size)
+{
+  /* handle different message type */
+  switch (type)
+  {
+  case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE:
+    if (size < sizeof (struct LookupBlockResponseMessage))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    return handle_lookup_block_response (qe, (const struct 
LookupBlockResponseMessage *) msg, size);
+  case GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE:
+    if (size != sizeof (struct BlockCacheResponseMessage))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    return handle_block_cache_response (qe, (const struct 
BlockCacheResponseMessage *) msg, size);
+  default:
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+}
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle`
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+process_namecache_message (void *cls,
+                          const struct GNUNET_MessageHeader *msg)
+{
+  struct GNUNET_NAMECACHE_Handle *h = cls;
+  const struct GNUNET_NAMECACHE_Header *gm;
+  struct GNUNET_NAMECACHE_QueueEntry *qe;
+  uint16_t size;
+  uint16_t type;
+  uint32_t r_id;
+  int ret;
+
+  if (NULL == msg)
+  {
+    force_reconnect (h);
+    return;
+  }
+  size = ntohs (msg->size);
+  type = ntohs (msg->type);
+  if (size < sizeof (struct GNUNET_NAMECACHE_Header))
+  {
+    GNUNET_break_op (0);
+    GNUNET_CLIENT_receive (h->client,
+                          &process_namecache_message, h,
+                           GNUNET_TIME_UNIT_FOREVER_REL);
+    return;
+  }
+  gm = (const struct GNUNET_NAMECACHE_Header *) msg;
+  r_id = ntohl (gm->r_id);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received message type %u size %u op %u\n",
+       (unsigned int) type,
+       (unsigned int) size,
+       (unsigned int) r_id);
+
+  /* Is it a record related operation ? */
+  for (qe = h->op_head; qe != NULL; qe = qe->next)
+    if (qe->op_id == r_id)
+      break;
+  if (NULL != qe)
+  {
+    ret = manage_record_operations (qe, msg, type, size);
+    if (GNUNET_SYSERR == ret)
+    {
+      /* protocol error, need to reconnect */
+      h->reconnect = GNUNET_YES;
+    }
+    else
+    {
+      /* client was notified about success or failure, clean up 'qe' */
+      GNUNET_CONTAINER_DLL_remove (h->op_head,
+                                  h->op_tail,
+                                  qe);
+      GNUNET_free (qe);
+    }
+  }
+  if (GNUNET_YES == h->reconnect)
+  {
+    force_reconnect (h);
+    return;
+  }
+  GNUNET_CLIENT_receive (h->client, &process_namecache_message, h,
+                         GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param h handle to use
+ */
+static void
+do_transmit (struct GNUNET_NAMECACHE_Handle *h);
+
+
+/**
+ * We can now transmit a message to NAMECACHE. Do it.
+ *
+ * @param cls the `struct GNUNET_NAMECACHE_Handle`
+ * @param size number of bytes we can transmit
+ * @param buf where to copy the messages
+ * @return number of bytes copied into @a buf
+ */
+static size_t
+transmit_message_to_namecache (void *cls,
+                              size_t size,
+                              void *buf)
+{
+  struct GNUNET_NAMECACHE_Handle *h = cls;
+  struct PendingMessage *p;
+  size_t ret;
+  char *cbuf;
+
+  h->th = NULL;
+  if ((0 == size) || (NULL == buf))
+  {
+    force_reconnect (h);
+    return 0;
+  }
+  ret = 0;
+  cbuf = buf;
+  while ( (NULL != (p = h->pending_head)) &&
+         (p->size <= size) )
+  {
+    memcpy (&cbuf[ret], &p[1], p->size);
+    ret += p->size;
+    size -= p->size;
+    GNUNET_CONTAINER_DLL_remove (h->pending_head,
+                                h->pending_tail,
+                                p);
+    if (GNUNET_NO == h->is_receiving)
+    {
+      h->is_receiving = GNUNET_YES;
+      GNUNET_CLIENT_receive (h->client,
+                            &process_namecache_message, h,
+                             GNUNET_TIME_UNIT_FOREVER_REL);
+    }
+    GNUNET_free (p);
+  }
+  do_transmit (h);
+  return ret;
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param h handle to use
+ */
+static void
+do_transmit (struct GNUNET_NAMECACHE_Handle *h)
+{
+  struct PendingMessage *p;
+
+  if (NULL != h->th)
+    return; /* transmission request already pending */
+  if (NULL == (p = h->pending_head))
+    return; /* transmission queue empty */
+  if (NULL == h->client)
+    return;                     /* currently reconnecting */
+  h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size,
+                                              GNUNET_TIME_UNIT_FOREVER_REL,
+                                              GNUNET_NO, 
&transmit_message_to_namecache,
+                                              h);
+  GNUNET_break (NULL != h->th);
+}
+
+
+/**
+ * Reconnect to namecache service.
+ *
+ * @param h the handle to the NAMECACHE service
+ */
+static void
+reconnect (struct GNUNET_NAMECACHE_Handle *h)
+{
+  GNUNET_assert (NULL == h->client);
+  h->client = GNUNET_CLIENT_connect ("namecache", h->cfg);
+  GNUNET_assert (NULL != h->client);
+  do_transmit (h);
+}
+
+
+/**
+ * Re-establish the connection to the service.
+ *
+ * @param cls handle to use to re-connect.
+ * @param tc scheduler context
+ */
+static void
+reconnect_task (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_NAMECACHE_Handle *h = cls;
+
+  h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+  reconnect (h);
+}
+
+
+/**
+ * Disconnect from service and then reconnect.
+ *
+ * @param h our handle
+ */
+static void
+force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
+{
+  if (NULL != h->th)
+  {
+    GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+    h->th = NULL;
+  }
+  h->reconnect = GNUNET_NO;
+  GNUNET_CLIENT_disconnect (h->client);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Reconnecting to namecache\n");
+  h->is_receiving = GNUNET_NO;
+  h->client = NULL;
+  h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
+  h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
+                                                   &reconnect_task,
+                                                   h);
+}
+
+
+/**
+ * Get a fresh operation id to distinguish between namecache requests
+ *
+ * @param h the namecache handle
+ * @return next operation id to use
+ */
+static uint32_t
+get_op_id (struct GNUNET_NAMECACHE_Handle *h)
+{
+  return h->last_op_id_used++;
+}
+
+
+/**
+ * Initialize the connection with the NAMECACHE service.
+ *
+ * @param cfg configuration to use
+ * @return handle to the GNS service, or NULL on error
+ */
+struct GNUNET_NAMECACHE_Handle *
+GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_NAMECACHE_Handle *h;
+
+  h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
+  h->cfg = cfg;
+  h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
+  h->last_op_id_used = 0;
+  return h;
+}
+
+
+/**
+ * Disconnect from the namecache service (and free associated
+ * resources).
+ *
+ * @param h handle to the namecache
+ */
+void
+GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
+{
+  struct PendingMessage *p;
+  struct GNUNET_NAMECACHE_QueueEntry *q;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
+  GNUNET_assert (NULL != h);
+  if (NULL != h->th)
+  {
+    GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+    h->th = NULL;
+  }
+  while (NULL != (p = h->pending_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
+    GNUNET_free (p);
+  }
+  GNUNET_break (NULL == h->op_head);
+  while (NULL != (q = h->op_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
+    GNUNET_free (q);
+  }
+  if (NULL != h->client)
+  {
+    GNUNET_CLIENT_disconnect (h->client);
+    h->client = NULL;
+  }
+  if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (h->reconnect_task);
+    h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  GNUNET_free (h);
+}
+
+
+/**
+ * Store an item in the namecache.  If the item is already present,
+ * it is replaced with the new record.
+ *
+ * @param h handle to the namecache
+ * @param block block to store
+ * @param cont continuation to call when done
+ * @param cont_cls closure for cont
+ * @return handle to abort the request
+ */
+struct GNUNET_NAMECACHE_QueueEntry *
+GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
+                             const struct GNUNET_NAMESTORE_Block *block,
+                             GNUNET_NAMECACHE_ContinuationWithStatus cont,
+                             void *cont_cls)
+{
+  struct GNUNET_NAMECACHE_QueueEntry *qe;
+  struct PendingMessage *pe;
+  struct BlockCacheMessage *msg;
+  uint32_t rid;
+  size_t blen;
+  size_t msg_size;
+
+  GNUNET_assert (NULL != h);
+  blen = ntohl (block->purpose.size)
+    - sizeof (struct GNUNET_TIME_AbsoluteNBO)
+    - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
+  rid = get_op_id (h);
+  qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
+  qe->nsh = h;
+  qe->cont = cont;
+  qe->cont_cls = cont_cls;
+  qe->op_id = rid;
+  GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
+
+  /* setup msg */
+  msg_size = sizeof (struct BlockCacheMessage) + blen;
+  pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
+  pe->size = msg_size;
+  msg = (struct BlockCacheMessage *) &pe[1];
+  msg->gns_header.header.type = htons 
(GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
+  msg->gns_header.header.size = htons (msg_size);
+  msg->gns_header.r_id = htonl (rid);
+  msg->expire = block->expiration_time;
+  msg->signature = block->signature;
+  msg->derived_key = block->derived_key;
+  memcpy (&msg[1], &block[1], blen);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending `%s' message with size %u and expiration %s\n",
+       "NAMECACHE_BLOCK_CACHE",
+       (unsigned int) msg_size,
+       GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh 
(msg->expire)));
+  GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
+  do_transmit (h);
+  return qe;
+}
+
+
+/**
+ * Get a result for a particular key from the namecache.  The processor
+ * will only be called once.
+ *
+ * @param h handle to the namecache
+ * @param derived_hash hash of zone key combined with name to lookup
+ * @param proc function to call on the matching block, or with
+ *        NULL if there is no matching block
+ * @param proc_cls closure for proc
+ * @return a handle that can be used to cancel
+ */
+struct GNUNET_NAMECACHE_QueueEntry *
+GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
+                              const struct GNUNET_HashCode *derived_hash,
+                              GNUNET_NAMESTORE_BlockProcessor proc, void 
*proc_cls)
+{
+  struct GNUNET_NAMECACHE_QueueEntry *qe;
+  struct PendingMessage *pe;
+  struct LookupBlockMessage *msg;
+  size_t msg_size;
+  uint32_t rid;
+
+  GNUNET_assert (NULL != h);
+  GNUNET_assert (NULL != derived_hash);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Looking for block under %s\n",
+       GNUNET_h2s (derived_hash));
+  rid = get_op_id(h);
+  qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
+  qe->nsh = h;
+  qe->block_proc = proc;
+  qe->block_proc_cls = proc_cls;
+  qe->op_id = rid;
+  GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
+
+  msg_size = sizeof (struct LookupBlockMessage);
+  pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
+  pe->size = msg_size;
+  msg = (struct LookupBlockMessage *) &pe[1];
+  msg->gns_header.header.type = htons 
(GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
+  msg->gns_header.header.size = htons (msg_size);
+  msg->gns_header.r_id = htonl (rid);
+  msg->query = *derived_hash;
+  GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
+  do_transmit (h);
+  return qe;
+}
+
+
+/**
+ * Cancel a namecache operation.  The final callback from the
+ * operation must not have been done yet.
+ *
+ * @param qe operation to cancel
+ */
+void
+GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
+{
+  struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
+
+  GNUNET_assert (NULL != qe);
+  GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
+  GNUNET_free(qe);
+}
+
+
+/* end of namecache_api.c */

Added: gnunet/src/namecache/plugin_namecache_postgres.c
===================================================================
--- gnunet/src/namecache/plugin_namecache_postgres.c                            
(rev 0)
+++ gnunet/src/namecache/plugin_namecache_postgres.c    2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,440 @@
+ /*
+  * This file is part of GNUnet
+  * (C) 2009-2013 Christian Grothoff (and other contributing authors)
+  *
+  * GNUnet is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published
+  * by the Free Software Foundation; either version 3, or (at your
+  * option) any later version.
+  *
+  * GNUnet is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with GNUnet; see the file COPYING.  If not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 02111-1307, USA.
+  */
+
+/**
+ * @file namecache/plugin_namecache_postgres.c
+ * @brief postgres-based namecache backend
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_namecache_plugin.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_postgres_lib.h"
+#include "namecache.h"
+
+
+/**
+ * After how many ms "busy" should a DB operation fail for good?
+ * A low value makes sure that we are more responsive to requests
+ * (especially PUTs).  A high value guarantees a higher success
+ * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
+ *
+ * The default value of 1s should ensure that users do not experience
+ * huge latencies while at the same time allowing operations to succeed
+ * with reasonable probability.
+ */
+#define BUSY_TIMEOUT_MS 1000
+
+
+/**
+ * Log an error message at log-level 'level' that indicates
+ * a failure of the command 'cmd' on file 'filename'
+ * with the message given by strerror(errno).
+ */
+#define LOG_POSTGRES(db, level, cmd) do { GNUNET_log_from (level, 
"namecache-postgres", _("`%s' failed at %s:%d with error: %s\n"), cmd, 
__FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
+
+#define LOG(kind,...) GNUNET_log_from (kind, "namecache-postgres", __VA_ARGS__)
+
+
+/**
+ * Context for all functions in this plugin.
+ */
+struct Plugin
+{
+
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Native Postgres database handle.
+   */
+  PGconn *dbh;
+
+};
+
+
+/**
+ * Create our database indices.
+ *
+ * @param dbh handle to the database
+ */
+static void
+create_indices (PGconn * dbh)
+{
+  /* create indices */
+  if ( (GNUNET_OK !=
+       GNUNET_POSTGRES_exec (dbh,
+                              "CREATE INDEX ir_query_hash ON ns096blocks 
(query,expiration_time)")) ||
+       (GNUNET_OK !=
+       GNUNET_POSTGRES_exec (dbh,
+                              "CREATE INDEX ir_block_expiration ON ns096blocks 
(expiration_time)")) )
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+        _("Failed to create indices\n"));
+}
+
+
+/**
+ * Initialize the database connections and associated
+ * data structures (create tables and indices
+ * as needed as well).
+ *
+ * @param plugin the plugin context (state for this module)
+ * @return GNUNET_OK on success
+ */
+static int
+database_setup (struct Plugin *plugin)
+{
+  PGresult *res;
+
+  plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg,
+                                        "namecache-postgres");
+  if (NULL == plugin->dbh)
+    return GNUNET_SYSERR;
+  if (GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
+                                           "namecache-postgres",
+                                           "TEMPORARY_TABLE"))
+  {
+    res =
+      PQexec (plugin->dbh,
+              "CREATE TEMPORARY TABLE ns096blocks ("
+             " query BYTEA NOT NULL DEFAULT '',"
+             " block BYTEA NOT NULL DEFAULT '',"
+             " expiration_time BIGINT NOT NULL DEFAULT 0"
+             ")" "WITH OIDS");
+  }
+  else
+  {
+    res =
+      PQexec (plugin->dbh,
+              "CREATE TABLE ns096blocks ("
+             " query BYTEA NOT NULL DEFAULT '',"
+             " block BYTEA NOT NULL DEFAULT '',"
+             " expiration_time BIGINT NOT NULL DEFAULT 0"
+             ")" "WITH OIDS");
+  }
+  if ( (NULL == res) ||
+       ((PQresultStatus (res) != PGRES_COMMAND_OK) &&
+        (0 != strcmp ("42P07",    /* duplicate table */
+                      PQresultErrorField
+                      (res,
+                       PG_DIAG_SQLSTATE)))))
+  {
+    (void) GNUNET_POSTGRES_check_result (plugin->dbh, res,
+                                         PGRES_COMMAND_OK, "CREATE TABLE",
+                                        "ns096blocks");
+    PQfinish (plugin->dbh);
+    plugin->dbh = NULL;
+    return GNUNET_SYSERR;
+  }
+  if (PQresultStatus (res) == PGRES_COMMAND_OK)
+    create_indices (plugin->dbh);
+  PQclear (res);
+
+  if ((GNUNET_OK !=
+       GNUNET_POSTGRES_prepare (plugin->dbh,
+                               "cache_block",
+                               "INSERT INTO ns096blocks (query, block, 
expiration_time) VALUES "
+                               "($1, $2, $3)", 3)) ||
+      (GNUNET_OK !=
+       GNUNET_POSTGRES_prepare (plugin->dbh,
+                               "expire_blocks",
+                               "DELETE FROM ns096blocks WHERE 
expiration_time<$1", 1)) ||
+      (GNUNET_OK !=
+       GNUNET_POSTGRES_prepare (plugin->dbh,
+                               "delete_block",
+                               "DELETE FROM ns096blocks WHERE query=$1 AND 
expiration_time<=$2", 2)) ||
+      (GNUNET_OK !=
+       GNUNET_POSTGRES_prepare (plugin->dbh,
+                               "lookup_block",
+                               "SELECT block FROM ns096blocks WHERE query=$1"
+                               " ORDER BY expiration_time DESC LIMIT 1", 1)))
+  {
+    PQfinish (plugin->dbh);
+    plugin->dbh = NULL;
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Removes any expired block.
+ *
+ * @param plugin the plugin
+ */
+static void
+namecache_postgres_expire_blocks (struct Plugin *plugin)
+{
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct GNUNET_TIME_AbsoluteNBO now_be = GNUNET_TIME_absolute_hton (now);
+  const char *paramValues[] = {
+    (const char *) &now_be
+  };
+  int paramLengths[] = {
+    sizeof (now_be)
+  };
+  const int paramFormats[] = { 1 };
+  PGresult *res;
+
+  res =
+    PQexecPrepared (plugin->dbh, "expire_blocks", 1,
+                   paramValues, paramLengths, paramFormats, 1);
+  if (GNUNET_OK !=
+      GNUNET_POSTGRES_check_result (plugin->dbh,
+                                    res,
+                                    PGRES_COMMAND_OK,
+                                    "PQexecPrepared",
+                                    "expire_blocks"))
+    return;
+  PQclear (res);
+}
+
+
+/**
+ * Delete older block in the datastore.
+ *
+ * @param the plugin
+ * @param query query for the block
+ * @param expiration time how old does the block have to be for deletion
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static void
+delete_old_block (struct Plugin *plugin,
+                  const struct GNUNET_HashCode *query,
+                  struct GNUNET_TIME_AbsoluteNBO expiration_time)
+{
+  const char *paramValues[] = {
+    (const char *) query,
+    (const char *) &expiration_time
+  };
+  int paramLengths[] = {
+    sizeof (*query),
+    sizeof (expiration_time)
+  };
+  const int paramFormats[] = { 1, 1 };
+  PGresult *res;
+
+  res =
+    PQexecPrepared (plugin->dbh, "delete_block", 2,
+                   paramValues, paramLengths, paramFormats, 1);
+  if (GNUNET_OK !=
+      GNUNET_POSTGRES_check_result (plugin->dbh,
+                                    res,
+                                    PGRES_COMMAND_OK,
+                                    "PQexecPrepared",
+                                    "delete_block"))
+    return;
+  PQclear (res);
+}
+
+
+/**
+ * Cache a block in the datastore.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param block block to cache
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+namecache_postgres_cache_block (void *cls,
+                                const struct GNUNET_NAMESTORE_Block *block)
+{
+  struct Plugin *plugin = cls;
+  struct GNUNET_HashCode query;
+  size_t block_size = ntohl (block->purpose.size) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+  const char *paramValues[] = {
+    (const char *) &query,
+    (const char *) block,
+    (const char *) &block->expiration_time
+  };
+  int paramLengths[] = {
+    sizeof (query),
+    (int) block_size,
+    sizeof (block->expiration_time)
+  };
+  const int paramFormats[] = { 1, 1, 1 };
+  PGresult *res;
+
+  namecache_postgres_expire_blocks (plugin);
+  GNUNET_CRYPTO_hash (&block->derived_key,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+                     &query);
+  if (block_size > 64 * 65536)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  delete_old_block (plugin, &query, block->expiration_time);
+
+  res =
+    PQexecPrepared (plugin->dbh, "cache_block", 3,
+                   paramValues, paramLengths, paramFormats, 1);
+  if (GNUNET_OK !=
+      GNUNET_POSTGRES_check_result (plugin->dbh,
+                                    res,
+                                    PGRES_COMMAND_OK,
+                                    "PQexecPrepared",
+                                    "cache_block"))
+    return GNUNET_SYSERR;
+  PQclear (res);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Get the block for a particular zone and label in the
+ * datastore.  Will return at most one result to the iterator.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param query hash of public key derived from the zone and the label
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, 
#GNUNET_SYSERR on error
+ */
+static int
+namecache_postgres_lookup_block (void *cls,
+                                 const struct GNUNET_HashCode *query,
+                                 GNUNET_NAMECACHE_BlockCallback iter, void 
*iter_cls)
+{
+  struct Plugin *plugin = cls;
+  const char *paramValues[] = {
+    (const char *) query
+  };
+  int paramLengths[] = {
+    sizeof (*query)
+  };
+  const int paramFormats[] = { 1 };
+  PGresult *res;
+  unsigned int cnt;
+  size_t bsize;
+  const struct GNUNET_NAMESTORE_Block *block;
+
+  res = PQexecPrepared (plugin->dbh,
+                        "lookup_block", 1,
+                        paramValues, paramLengths, paramFormats,
+                        1);
+  if (GNUNET_OK !=
+      GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK,
+                                    "PQexecPrepared",
+                                   "lookup_block"))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Failing lookup (postgres error)\n");
+    return GNUNET_SYSERR;
+  }
+  if (0 == (cnt = PQntuples (res)))
+  {
+    /* no result */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Ending iteration (no more results)\n");
+    PQclear (res);
+    return GNUNET_NO;
+  }
+  GNUNET_assert (1 == cnt);
+  GNUNET_assert (1 != PQnfields (res));
+  bsize = PQgetlength (res, 0, 0);
+  block = (const struct GNUNET_NAMESTORE_Block *) PQgetvalue (res, 0, 0);
+  if ( (bsize < sizeof (*block)) ||
+       (bsize != ntohl (block->purpose.size) +
+        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+        sizeof (struct GNUNET_CRYPTO_EcdsaSignature)) )
+  {
+    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Failing lookup (corrupt block)\n");
+    PQclear (res);
+    return GNUNET_SYSERR;
+  }
+  iter (iter_cls, block);
+  PQclear (res);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown database connection and associate data
+ * structures.
+ *
+ * @param plugin the plugin context (state for this module)
+ */
+static void
+database_shutdown (struct Plugin *plugin)
+{
+  PQfinish (plugin->dbh);
+  plugin->dbh = NULL;
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_NAMECACHE_PluginEnvironment*"
+ * @return NULL on error, othrewise the plugin context
+ */
+void *
+libgnunet_plugin_namecache_postgres_init (void *cls)
+{
+  static struct Plugin plugin;
+  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+  struct GNUNET_NAMECACHE_PluginFunctions *api;
+
+  if (NULL != plugin.cfg)
+    return NULL;                /* can only initialize once! */
+  memset (&plugin, 0, sizeof (struct Plugin));
+  plugin.cfg = cfg;
+  if (GNUNET_OK != database_setup (&plugin))
+  {
+    database_shutdown (&plugin);
+    return NULL;
+  }
+  api = GNUNET_new (struct GNUNET_NAMECACHE_PluginFunctions);
+  api->cls = &plugin;
+  api->cache_block = &namecache_postgres_cache_block;
+  api->lookup_block = &namecache_postgres_lookup_block;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       _("Postgres database running\n"));
+  return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_namecache_postgres_done (void *cls)
+{
+  struct GNUNET_NAMECACHE_PluginFunctions *api = cls;
+  struct Plugin *plugin = api->cls;
+
+  database_shutdown (plugin);
+  plugin->cfg = NULL;
+  GNUNET_free (api);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "postgres plugin is finished\n");
+  return NULL;
+}
+
+/* end of plugin_namecache_postgres.c */

Added: gnunet/src/namecache/plugin_namecache_sqlite.c
===================================================================
--- gnunet/src/namecache/plugin_namecache_sqlite.c                              
(rev 0)
+++ gnunet/src/namecache/plugin_namecache_sqlite.c      2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,608 @@
+ /*
+  * This file is part of GNUnet
+  * (C) 2009-2013 Christian Grothoff (and other contributing authors)
+  *
+  * GNUnet is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published
+  * by the Free Software Foundation; either version 3, or (at your
+  * option) any later version.
+  *
+  * GNUnet is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with GNUnet; see the file COPYING.  If not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 02111-1307, USA.
+  */
+
+/**
+ * @file namecache/plugin_namecache_sqlite.c
+ * @brief sqlite-based namecache backend
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_namecache_plugin.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "namecache.h"
+#include <sqlite3.h>
+
+/**
+ * After how many ms "busy" should a DB operation fail for good?  A
+ * low value makes sure that we are more responsive to requests
+ * (especially PUTs).  A high value guarantees a higher success rate
+ * (SELECTs in iterate can take several seconds despite LIMIT=1).
+ *
+ * The default value of 1s should ensure that users do not experience
+ * huge latencies while at the same time allowing operations to
+ * succeed with reasonable probability.
+ */
+#define BUSY_TIMEOUT_MS 1000
+
+
+/**
+ * Log an error message at log-level 'level' that indicates
+ * a failure of the command 'cmd' on file 'filename'
+ * with the message given by strerror(errno).
+ */
+#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, 
"namecache-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, 
__LINE__, sqlite3_errmsg(db->dbh)); } while(0)
+
+#define LOG(kind,...) GNUNET_log_from (kind, "namecache-sqlite", __VA_ARGS__)
+
+
+/**
+ * Context for all functions in this plugin.
+ */
+struct Plugin
+{
+
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Database filename.
+   */
+  char *fn;
+
+  /**
+   * Native SQLite database handle.
+   */
+  sqlite3 *dbh;
+
+  /**
+   * Precompiled SQL for caching a block
+   */
+  sqlite3_stmt *cache_block;
+
+  /**
+   * Precompiled SQL for deleting an older block
+   */
+  sqlite3_stmt *delete_block;
+
+  /**
+   * Precompiled SQL for looking up a block
+   */
+  sqlite3_stmt *lookup_block;
+
+  /**
+   * Precompiled SQL for removing expired blocks
+   */
+  sqlite3_stmt *expire_blocks;
+
+
+};
+
+
+/**
+ * @brief Prepare a SQL statement
+ *
+ * @param dbh handle to the database
+ * @param zSql SQL statement, UTF-8 encoded
+ * @param ppStmt set to the prepared statement
+ * @return 0 on success
+ */
+static int
+sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt)
+{
+  char *dummy;
+  int result;
+
+  result =
+      sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
+                          (const char **) &dummy);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
+  return result;
+}
+
+
+/**
+ * Create our database indices.
+ *
+ * @param dbh handle to the database
+ */
+static void
+create_indices (sqlite3 * dbh)
+{
+  /* create indices */
+  if ( (SQLITE_OK !=
+       sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_query_hash ON 
ns096blocks (query,expiration_time)",
+                     NULL, NULL, NULL)) ||
+       (SQLITE_OK !=
+       sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_block_expiration ON 
ns096blocks (expiration_time)",
+                     NULL, NULL, NULL)) )
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+        "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
+}
+
+
+#if 0
+#define CHECK(a) GNUNET_break(a)
+#define ENULL NULL
+#else
+#define ENULL &e
+#define ENULL_DEFINED 1
+#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); 
sqlite3_free(e); }
+#endif
+
+
+/**
+ * Initialize the database connections and associated
+ * data structures (create tables and indices
+ * as needed as well).
+ *
+ * @param plugin the plugin context (state for this module)
+ * @return #GNUNET_OK on success
+ */
+static int
+database_setup (struct Plugin *plugin)
+{
+  sqlite3_stmt *stmt;
+  char *afsdir;
+#if ENULL_DEFINED
+  char *e;
+#endif
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namecache-sqlite",
+                                               "FILENAME", &afsdir))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                              "namecache-sqlite", "FILENAME");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
+  {
+    if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
+    {
+      GNUNET_break (0);
+      GNUNET_free (afsdir);
+      return GNUNET_SYSERR;
+    }
+  }
+  /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
+  plugin->fn = afsdir;
+
+  /* Open database and precompile statements */
+  if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+        _("Unable to initialize SQLite: %s.\n"),
+        sqlite3_errmsg (plugin->dbh));
+    return GNUNET_SYSERR;
+  }
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA synchronous=NORMAL", NULL, NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, 
NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL,
+                       NULL, ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"", NULL,
+                       NULL, ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, 
NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL,
+                       ENULL));
+
+  CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
+
+
+  /* Create tables */
+  CHECK (SQLITE_OK ==
+         sq_prepare (plugin->dbh,
+                     "SELECT 1 FROM sqlite_master WHERE tbl_name = 
'ns096blocks'",
+                     &stmt));
+  if ((sqlite3_step (stmt) == SQLITE_DONE) &&
+      (sqlite3_exec
+       (plugin->dbh,
+        "CREATE TABLE ns096blocks ("
+        " query BLOB NOT NULL DEFAULT '',"
+        " block BLOB NOT NULL DEFAULT '',"
+        " expiration_time INT8 NOT NULL DEFAULT 0"
+       ")",
+       NULL, NULL, NULL) != SQLITE_OK))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
+    sqlite3_finalize (stmt);
+    return GNUNET_SYSERR;
+  }
+  sqlite3_finalize (stmt);
+  create_indices (plugin->dbh);
+
+  if ((sq_prepare
+       (plugin->dbh,
+        "INSERT INTO ns096blocks (query,block,expiration_time) VALUES (?, ?, 
?)",
+        &plugin->cache_block) != SQLITE_OK) ||
+      (sq_prepare
+       (plugin->dbh,
+        "DELETE FROM ns096blocks WHERE expiration_time<?",
+        &plugin->expire_blocks) != SQLITE_OK) ||
+      (sq_prepare
+       (plugin->dbh,
+        "DELETE FROM ns096blocks WHERE query=? AND expiration_time<=?",
+        &plugin->delete_block) != SQLITE_OK) ||
+      (sq_prepare
+       (plugin->dbh,
+        "SELECT block FROM ns096blocks WHERE query=? ORDER BY expiration_time 
DESC LIMIT 1",
+        &plugin->lookup_block) != SQLITE_OK)
+      )
+  {
+    LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling");
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown database connection and associate data
+ * structures.
+ * @param plugin the plugin context (state for this module)
+ */
+static void
+database_shutdown (struct Plugin *plugin)
+{
+  int result;
+  sqlite3_stmt *stmt;
+
+  if (NULL != plugin->cache_block)
+    sqlite3_finalize (plugin->cache_block);
+  if (NULL != plugin->lookup_block)
+    sqlite3_finalize (plugin->lookup_block);
+  if (NULL != plugin->expire_blocks)
+    sqlite3_finalize (plugin->expire_blocks);
+  if (NULL != plugin->delete_block)
+    sqlite3_finalize (plugin->delete_block);
+  result = sqlite3_close (plugin->dbh);
+  if (result == SQLITE_BUSY)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+        _("Tried to close sqlite without finalizing all prepared 
statements.\n"));
+    stmt = sqlite3_next_stmt (plugin->dbh, NULL);
+    while (stmt != NULL)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+                       "Closing statement %p\n", stmt);
+      result = sqlite3_finalize (stmt);
+      if (result != SQLITE_OK)
+        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
+                         "Failed to close statement %p: %d\n", stmt, result);
+      stmt = sqlite3_next_stmt (plugin->dbh, NULL);
+    }
+    result = sqlite3_close (plugin->dbh);
+  }
+  if (SQLITE_OK != result)
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
+
+  GNUNET_free_non_null (plugin->fn);
+}
+
+
+/**
+ * Removes any expired block.
+ *
+ * @param plugin the plugin
+ */
+static void
+namecache_sqlite_expire_blocks (struct Plugin *plugin)
+{
+  struct GNUNET_TIME_Absolute now;
+  int n;
+
+  now = GNUNET_TIME_absolute_get ();
+  if (SQLITE_OK != sqlite3_bind_int64 (plugin->expire_blocks,
+                                      1, now.abs_value_us))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_bind_XXXX");
+    if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks))
+      LOG_SQLITE (plugin,
+                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                  "sqlite3_reset");
+    return;
+  }
+  n = sqlite3_step (plugin->expire_blocks);
+  if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks))
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_reset");
+  switch (n)
+  {
+  case SQLITE_DONE:
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Records expired\n");
+    return;
+  case SQLITE_BUSY:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+    return;
+  default:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+    return;
+  }
+}
+
+
+/**
+ * Cache a block in the datastore.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param block block to cache
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+namecache_sqlite_cache_block (void *cls,
+                             const struct GNUNET_NAMESTORE_Block *block)
+{
+  struct Plugin *plugin = cls;
+  struct GNUNET_HashCode query;
+  struct GNUNET_TIME_Absolute expiration;
+  int64_t dval;
+  size_t block_size;
+  int n;
+
+  namecache_sqlite_expire_blocks (plugin);
+  GNUNET_CRYPTO_hash (&block->derived_key,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+                     &query);
+  expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time);
+  dval = (int64_t) expiration.abs_value_us;
+  if (dval < 0)
+    dval = INT64_MAX;
+  block_size = ntohl (block->purpose.size) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+  if (block_size > 64 * 65536)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* delete old version of the block */
+  if ( (SQLITE_OK !=
+        sqlite3_bind_blob (plugin->delete_block, 1,
+                           &query, sizeof (struct GNUNET_HashCode),
+                           SQLITE_STATIC)) ||
+       (SQLITE_OK !=
+        sqlite3_bind_int64 (plugin->delete_block,
+                            2, dval)) )
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_bind_XXXX");
+    if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
+      LOG_SQLITE (plugin,
+                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                  "sqlite3_reset");
+    return GNUNET_SYSERR;
+  }
+  n = sqlite3_step (plugin->delete_block);
+  switch (n)
+  {
+  case SQLITE_DONE:
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Old block deleted\n");
+    break;
+  case SQLITE_BUSY:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+    break;
+  default:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+    break;
+  }
+  if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_reset");
+
+  /* insert new version of the block */
+  if ((SQLITE_OK !=
+       sqlite3_bind_blob (plugin->cache_block, 1,
+                         &query, sizeof (struct GNUNET_HashCode),
+                         SQLITE_STATIC)) ||
+      (SQLITE_OK !=
+       sqlite3_bind_blob (plugin->cache_block, 2,
+                         block, block_size,
+                         SQLITE_STATIC)) ||
+      (SQLITE_OK !=
+       sqlite3_bind_int64 (plugin->cache_block, 3,
+                          dval)))
+  {
+    LOG_SQLITE (plugin,
+               GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_bind_XXXX");
+    if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
+      LOG_SQLITE (plugin,
+                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                 "sqlite3_reset");
+    return GNUNET_SYSERR;
+
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Caching block under derived key `%s'\n",
+             GNUNET_h2s_full (&query));
+  n = sqlite3_step (plugin->cache_block);
+  if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_reset");
+  switch (n)
+  {
+  case SQLITE_DONE:
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Record stored\n");
+    return GNUNET_OK;
+  case SQLITE_BUSY:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_step");
+    return GNUNET_NO;
+  default:
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_step");
+    return GNUNET_SYSERR;
+  }
+}
+
+
+/**
+ * Get the block for a particular zone and label in the
+ * datastore.  Will return at most one result to the iterator.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param query hash of public key derived from the zone and the label
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, 
#GNUNET_SYSERR on error
+ */
+static int
+namecache_sqlite_lookup_block (void *cls,
+                              const struct GNUNET_HashCode *query,
+                              GNUNET_NAMECACHE_BlockCallback iter, void 
*iter_cls)
+{
+  struct Plugin *plugin = cls;
+  int ret;
+  int sret;
+  size_t block_size;
+  const struct GNUNET_NAMESTORE_Block *block;
+
+  if (SQLITE_OK != sqlite3_bind_blob (plugin->lookup_block, 1,
+                                     query, sizeof (struct GNUNET_HashCode),
+                                     SQLITE_STATIC))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_bind_XXXX");
+    if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
+      LOG_SQLITE (plugin,
+                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                 "sqlite3_reset");
+    return GNUNET_SYSERR;
+  }
+  ret = GNUNET_NO;
+  if (SQLITE_ROW == (sret = sqlite3_step (plugin->lookup_block)))
+  {
+    block = sqlite3_column_blob (plugin->lookup_block, 0);
+    block_size = sqlite3_column_bytes (plugin->lookup_block, 0);
+    if ( (block_size < sizeof (struct GNUNET_NAMESTORE_Block)) ||
+        (ntohl (block->purpose.size) +
+         sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+         sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
+    {
+      GNUNET_break (0);
+      ret = GNUNET_SYSERR;
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Found block under derived key `%s'\n",
+                 GNUNET_h2s_full (query));
+      iter (iter_cls, block);
+      ret = GNUNET_YES;
+    }
+  }
+  else
+  {
+    if (SQLITE_DONE != sret)
+    {
+      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+      ret = GNUNET_SYSERR;
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "No block found under derived key `%s'\n",
+                 GNUNET_h2s_full (query));
+    }
+  }
+  if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
+    LOG_SQLITE (plugin,
+               GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+               "sqlite3_reset");
+  return ret;
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_NAMECACHE_PluginEnvironment*"
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_namecache_sqlite_init (void *cls)
+{
+  static struct Plugin plugin;
+  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+  struct GNUNET_NAMECACHE_PluginFunctions *api;
+
+  if (NULL != plugin.cfg)
+    return NULL;                /* can only initialize once! */
+  memset (&plugin, 0, sizeof (struct Plugin));
+  plugin.cfg = cfg;
+  if (GNUNET_OK != database_setup (&plugin))
+  {
+    database_shutdown (&plugin);
+    return NULL;
+  }
+  api = GNUNET_new (struct GNUNET_NAMECACHE_PluginFunctions);
+  api->cls = &plugin;
+  api->cache_block = &namecache_sqlite_cache_block;
+  api->lookup_block = &namecache_sqlite_lookup_block;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       _("Sqlite database running\n"));
+  return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_namecache_sqlite_done (void *cls)
+{
+  struct GNUNET_NAMECACHE_PluginFunctions *api = cls;
+  struct Plugin *plugin = api->cls;
+
+  database_shutdown (plugin);
+  plugin->cfg = NULL;
+  GNUNET_free (api);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "sqlite plugin is finished\n");
+  return NULL;
+}
+
+/* end of plugin_namecache_sqlite.c */

Added: gnunet/src/namecache/test_namecache_api.conf
===================================================================
--- gnunet/src/namecache/test_namecache_api.conf                                
(rev 0)
+++ gnunet/src/namecache/test_namecache_api.conf        2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,19 @@
+[PATHS]
+GNUNET_TEST_HOME = /tmp/test-gnunet-namecache/
+
+[arm]
+PORT = 12000
+DEFAULTSERVICES = namecache
+
+[namecache]
+#PREFIX = valgrind
+AUTOSTART = YES
+DATABASE = sqlite
+
+[namecache-sqlite]
+FILENAME = $GNUNET_TEST_HOME/namecache/sqlite_test.db
+
+[namecache-postgres]
+CONFIG = connect_timeout=10; dbname=gnunetcheck
+TEMPORARY_TABLE = YES
+

Added: gnunet/src/namecache/test_namecache_api_cache_block.c
===================================================================
--- gnunet/src/namecache/test_namecache_api_cache_block.c                       
        (rev 0)
+++ gnunet/src/namecache/test_namecache_api_cache_block.c       2013-10-16 
19:32:52 UTC (rev 30230)
@@ -0,0 +1,239 @@
+/*
+     This file is part of GNUnet.
+     (C) 2012 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file namecache/test_namecache_api.c
+ * @brief testcase for namecache_api.c: store a record and perform a lookup
+ */
+#include "platform.h"
+#include "gnunet_namecache_service.h"
+#include "gnunet_testing_lib.h"
+
+#define TEST_RECORD_TYPE 1234
+
+#define TEST_RECORD_DATALEN 123
+
+#define TEST_RECORD_DATA 'a'
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
+
+
+static struct GNUNET_NAMECACHE_Handle *nsh;
+
+static GNUNET_SCHEDULER_TaskIdentifier endbadly_task;
+
+static struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
+
+static struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+
+static int res;
+
+static struct GNUNET_NAMECACHE_QueueEntry *nsqe;
+
+
+static void
+cleanup ()
+{
+  if (NULL != nsh)
+  {
+    GNUNET_NAMECACHE_disconnect (nsh);
+    nsh = NULL;
+  }
+  if (NULL != privkey)
+  {
+    GNUNET_free (privkey);
+    privkey = NULL;
+  }
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Re-establish the connection to the service.
+ *
+ * @param cls handle to use to re-connect.
+ * @param tc scheduler context
+ */
+static void
+endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  if (NULL != nsqe)
+  {
+    GNUNET_NAMECACHE_cancel (nsqe);
+    nsqe = NULL;
+  }
+  cleanup ();
+  res = 1;
+}
+
+
+static void
+end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  cleanup ();
+  res = 0;
+}
+
+
+static void
+rd_decrypt_cb (void *cls,
+               unsigned int rd_count,
+               const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  char rd_cmp_data[TEST_RECORD_DATALEN];
+
+  GNUNET_assert (1 == rd_count);
+  GNUNET_assert (NULL != rd);
+
+  memset (rd_cmp_data, 'a', TEST_RECORD_DATALEN);
+
+  GNUNET_assert (TEST_RECORD_TYPE == rd[0].record_type);
+  GNUNET_assert (TEST_RECORD_DATALEN == rd[0].data_size);
+  GNUNET_assert (0 == memcmp (&rd_cmp_data, rd[0].data, TEST_RECORD_DATALEN));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Block was decrypted successfully \n");
+
+       GNUNET_SCHEDULER_add_now (&end, NULL);
+}
+
+static void
+name_lookup_proc (void *cls,
+                  const struct GNUNET_NAMESTORE_Block *block)
+{
+  const char *name = cls;
+  nsqe = NULL;
+
+  GNUNET_assert (NULL != cls);
+
+  if (endbadly_task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (endbadly_task);
+    endbadly_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+
+  if (NULL == block)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+             _("Namecache returned no block\n"));
+    if (endbadly_task != GNUNET_SCHEDULER_NO_TASK)
+      GNUNET_SCHEDULER_cancel (endbadly_task);
+    endbadly_task =  GNUNET_SCHEDULER_add_now (&endbadly, NULL);
+    return;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Namecache returned block, decrypting \n");
+  GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_block_decrypt(block,
+               &pubkey, name, &rd_decrypt_cb, (void *) name));
+}
+
+static void
+cache_cont (void *cls, int32_t success, const char *emsg)
+{
+  const char *name = cls;
+  struct GNUNET_HashCode derived_hash;
+
+  GNUNET_assert (NULL != cls);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Name store cached record for `%s': %s\n",
+             name,
+             (success == GNUNET_OK) ? "SUCCESS" : "FAIL");
+
+  /* Create derived hash */
+  GNUNET_NAMESTORE_query_from_public_key (&pubkey, name, &derived_hash);
+
+  nsqe = GNUNET_NAMECACHE_lookup_block (nsh, &derived_hash,
+                                        &name_lookup_proc, (void *) name);
+}
+
+
+static void
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *cfg,
+     struct GNUNET_TESTING_Peer *peer)
+{
+  struct GNUNET_NAMESTORE_RecordData rd;
+  struct GNUNET_NAMESTORE_Block *block;
+  char *hostkey_file;
+  const char * name = "dummy.dummy.gnunet";
+
+  endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+                                               &endbadly, NULL);
+  GNUNET_asprintf (&hostkey_file,
+                  "zonefiles%s%s",
+                  DIR_SEPARATOR_STR,
+                  "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", 
hostkey_file);
+  privkey = GNUNET_CRYPTO_ecdsa_key_create_from_file (hostkey_file);
+  GNUNET_free (hostkey_file);
+  GNUNET_assert (privkey != NULL);
+  GNUNET_CRYPTO_ecdsa_key_get_public (privkey, &pubkey);
+
+
+  rd.expiration_time = GNUNET_TIME_absolute_get().abs_value_us;
+  rd.record_type = TEST_RECORD_TYPE;
+  rd.data_size = TEST_RECORD_DATALEN;
+  rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
+  memset ((char *) rd.data, 'a', TEST_RECORD_DATALEN);
+  block = GNUNET_NAMESTORE_block_create (privkey,
+      GNUNET_TIME_UNIT_FOREVER_ABS, name, &rd, 1 );
+  if (NULL == block)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              _("Namecache cannot cache no block\n"));
+  }
+
+  nsh = GNUNET_NAMECACHE_connect (cfg);
+  if (NULL == nsh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              _("Namecache cannot connect to namecache\n"));
+  }
+  GNUNET_break (NULL != nsh);
+
+  nsqe = GNUNET_NAMECACHE_block_cache (nsh, block , &cache_cont, (void *) 
name);
+  if (NULL == nsqe)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+             _("Namecache cannot cache no block\n"));
+  }
+
+  GNUNET_free ((void *)rd.data);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  GNUNET_DISK_directory_remove ("/tmp/test-gnunet-namecache/");
+  res = 1;
+  if (0 !=
+      GNUNET_TESTING_service_run ("test-namecache-api",
+                                 "namecache",
+                                 "test_namecache_api.conf",
+                                 &run,
+                                 NULL))
+    return 1;
+  return res;
+}
+
+
+/* end of test_namecache_api_cache_block.c */

Added: gnunet/src/namecache/test_plugin_namecache.c
===================================================================
--- gnunet/src/namecache/test_plugin_namecache.c                                
(rev 0)
+++ gnunet/src/namecache/test_plugin_namecache.c        2013-10-16 19:32:52 UTC 
(rev 30230)
@@ -0,0 +1,131 @@
+/*
+     This file is part of GNUnet.
+     (C) 2012 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/*
+ * @file namecache/test_plugin_namecache.c
+ * @brief Test for the namecache plugins
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_namecache_plugin.h"
+#include "gnunet_testing_lib.h"
+
+
+static int ok;
+
+/**
+ * Name of plugin under test.
+ */
+static const char *plugin_name;
+
+
+/**
+ * Function called when the service shuts down.  Unloads our namecache
+ * plugin.
+ *
+ * @param api api to unload
+ */
+static void
+unload_plugin (struct GNUNET_NAMECACHE_PluginFunctions *api)
+{
+  char *libname;
+
+  GNUNET_asprintf (&libname, "libgnunet_plugin_namecache_%s", plugin_name);
+  GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
+  GNUNET_free (libname);
+}
+
+
+/**
+ * Load the namecache plugin.
+ *
+ * @param cfg configuration to pass
+ * @return NULL on error
+ */
+static struct GNUNET_NAMECACHE_PluginFunctions *
+load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_NAMECACHE_PluginFunctions *ret;
+  char *libname;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' namecache plugin\n"),
+              plugin_name);
+  GNUNET_asprintf (&libname, "libgnunet_plugin_namecache_%s", plugin_name);
+  if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg)))
+  {
+    FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name);
+    GNUNET_free (libname);
+    return NULL;
+  }
+  GNUNET_free (libname);
+  return ret;
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_NAMECACHE_PluginFunctions *nsp;
+
+  ok = 0;
+  nsp = load_plugin (cfg);
+  if (NULL == nsp)
+  {
+    FPRINTF (stderr,
+             "%s",
+            "Failed to initialize namecache.  Database likely not setup, 
skipping test.\n");
+    return;
+  }
+
+  unload_plugin (nsp);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  char cfg_name[128];
+  char *const xargv[] = {
+    "test-plugin-namecache",
+    "-c",
+    cfg_name,
+    NULL
+  };
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namecache-sqlite");
+  GNUNET_log_setup ("test-plugin-namecache",
+                    "WARNING",
+                    NULL);
+  plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
+  GNUNET_snprintf (cfg_name, sizeof (cfg_name), 
"test_plugin_namecache_%s.conf",
+                   plugin_name);
+  GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
+                      "test-plugin-namecache", "nohelp", options, &run, NULL);
+  if (ok != 0)
+    FPRINTF (stderr, "Missed some testcases: %d\n", ok);
+  GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namecache-sqlite");
+  return ok;
+}
+
+/* end of test_plugin_namecache.c */

Added: gnunet/src/namecache/test_plugin_namecache_postgres.conf
===================================================================
--- gnunet/src/namecache/test_plugin_namecache_postgres.conf                    
        (rev 0)
+++ gnunet/src/namecache/test_plugin_namecache_postgres.conf    2013-10-16 
19:32:52 UTC (rev 30230)
@@ -0,0 +1,3 @@
+[namestore-postgres]
+CONFIG = connect_timeout=10; dbname=gnunetcheck
+TEMPORARY_TABLE = YES

Added: gnunet/src/namecache/test_plugin_namecache_sqlite.conf
===================================================================
--- gnunet/src/namecache/test_plugin_namecache_sqlite.conf                      
        (rev 0)
+++ gnunet/src/namecache/test_plugin_namecache_sqlite.conf      2013-10-16 
19:32:52 UTC (rev 30230)
@@ -0,0 +1,2 @@
+[namestore-sqlite]
+FILENAME = /tmp/gnunet-test-plugin-namestore-sqlite/sqlite.db




reply via email to

[Prev in Thread] Current Thread [Next in Thread]