[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r30230 - in gnunet/src: . include namecache,
gnunet <=