gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r8328 - in GNUnet/src/applications: . dv_dht dv_dht/module


From: gnunet
Subject: [GNUnet-SVN] r8328 - in GNUnet/src/applications: . dv_dht dv_dht/module dv_dht/tools
Date: Wed, 11 Mar 2009 16:00:19 -0600

Author: nevans
Date: 2009-03-11 16:00:19 -0600 (Wed, 11 Mar 2009)
New Revision: 8328

Added:
   GNUnet/src/applications/dv_dht/
   GNUnet/src/applications/dv_dht/Makefile.am
   GNUnet/src/applications/dv_dht/module/
   GNUnet/src/applications/dv_dht/module/Makefile.am
   GNUnet/src/applications/dv_dht/module/cs.c
   GNUnet/src/applications/dv_dht/module/routing.c
   GNUnet/src/applications/dv_dht/module/routing.h
   GNUnet/src/applications/dv_dht/module/service.c
   GNUnet/src/applications/dv_dht/module/service.h
   GNUnet/src/applications/dv_dht/module/table.c
   GNUnet/src/applications/dv_dht/module/table.h
   GNUnet/src/applications/dv_dht/tools/
   GNUnet/src/applications/dv_dht/tools/Makefile.am
   GNUnet/src/applications/dv_dht/tools/dht-query.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_api.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_expiration_test.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_forwarding_test.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_loopback_test.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_multipeer_test.c
   GNUnet/src/applications/dv_dht/tools/dv_dht_twopeer_test.c
Log:


Added: GNUnet/src/applications/dv_dht/Makefile.am
===================================================================
--- GNUnet/src/applications/dv_dht/Makefile.am                          (rev 0)
+++ GNUnet/src/applications/dv_dht/Makefile.am  2009-03-11 22:00:19 UTC (rev 
8328)
@@ -0,0 +1 @@
+SUBDIRS = module tools

Added: GNUnet/src/applications/dv_dht/module/Makefile.am
===================================================================
--- GNUnet/src/applications/dv_dht/module/Makefile.am                           
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/Makefile.am   2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,22 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+  AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+plugindir = $(libdir)/GNUnet
+
+plugin_LTLIBRARIES = \
+  libgnunetmodule_dvdht.la 
+
+libgnunetmodule_dvdht_la_SOURCES = \
+  cs.c \
+  routing.c routing.h \
+  service.c service.h \
+  table.c table.h 
+libgnunetmodule_dvdht_la_LDFLAGS = \
+  $(GN_PLUGIN_LDFLAGS)
+libgnunetmodule_dvdht_la_LIBADD = -lm \
+  $(top_builddir)/src/applications/rpc/libgnunetrpcutil.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL)

Added: GNUnet/src/applications/dv_dht/module/cs.c
===================================================================
--- GNUnet/src/applications/dv_dht/module/cs.c                          (rev 0)
+++ GNUnet/src/applications/dv_dht/module/cs.c  2009-03-11 22:00:19 UTC (rev 
8328)
@@ -0,0 +1,344 @@
+/*
+      This file is part of GNUnet
+      Copyright (C) 2004, 2005, 2006, 2007 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 2, 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 module/cs.c
+ * @brief DHT application protocol using the DHT service.
+ *   This is merely for the dht-client library.  The code
+ *   of this file is mostly converting from and to TCP messages.
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_core.h"
+#include "gnunet_protocols.h"
+#include "dht.h"
+#include "gnunet_dv_dht_service.h"
+#include "service.h"
+
+#define DEBUG_CS GNUNET_NO
+
+/**
+ * Global core API.
+ */
+static GNUNET_CoreAPIForPlugins *coreAPI;
+
+/**
+ * Reference to the DV DHT service API.
+ */
+static GNUNET_DV_DHT_ServiceAPI *dvdhtAPI;
+
+/**
+ * Type of the linked list that is used by CS to
+ * keep track of clients and their pending GET
+ * requests.
+ */
+struct DV_DHT_CLIENT_GET_RECORD
+{
+
+  struct DV_DHT_CLIENT_GET_RECORD *next;
+
+  struct GNUNET_ClientHandle *client;
+
+  struct GNUNET_DV_DHT_GetHandle *get_record;
+
+};
+
+/**
+ * Linked list of active GET requests.
+ */
+static struct DV_DHT_CLIENT_GET_RECORD *getRecords;
+
+/**
+ * Lock.
+ */
+static struct GNUNET_Mutex *lock;
+
+/**
+ * CS handler for inserting <key,value>-pair into DHT-table.
+ */
+static int
+csPut (struct GNUNET_ClientHandle *client,
+       const GNUNET_MessageHeader * message)
+{
+  const CS_dht_request_put_MESSAGE *req;
+  unsigned int size;
+
+  if (ntohs (message->size) < sizeof (CS_dht_request_put_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  req = (const CS_dht_request_put_MESSAGE *) message;
+  size = ntohs (req->header.size) - sizeof (CS_dht_request_put_MESSAGE);
+  GNUNET_GE_ASSERT (NULL, size < GNUNET_MAX_BUFFER_SIZE);
+  dvdhtAPI->put (&req->key, ntohl (req->type), size, (const char *) &req[1]);
+  return coreAPI->cs_send_value (client, GNUNET_OK);
+}
+
+static int
+get_result (const GNUNET_HashCode * key,
+            unsigned int type,
+            unsigned int size, const char *value, void *cls)
+{
+  struct DV_DHT_CLIENT_GET_RECORD *record = cls;
+  CS_dht_request_put_MESSAGE *msg;
+  size_t n;
+
+  n = sizeof (CS_dht_request_put_MESSAGE) + size;
+  if (n > GNUNET_MAX_BUFFER_SIZE)
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  msg = GNUNET_malloc (n);
+  msg->header.size = htons (n);
+  msg->header.type = htons (GNUNET_CS_PROTO_DHT_REQUEST_PUT);
+  msg->type = htonl (type);
+  msg->key = *key;
+  memcpy (&msg[1], value, size);
+  if (GNUNET_OK !=
+      coreAPI->cs_send_message (record->client, &msg->header, GNUNET_YES))
+    {
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_IMMEDIATE | GNUNET_GE_USER,
+                     _("`%s' failed. Terminating connection to client.\n"),
+                     "cs_send_to_client");
+      coreAPI->cs_disconnect_now (record->client);
+    }
+  GNUNET_free (msg);
+  return GNUNET_OK;
+}
+
+/**
+ * CS handler for getting key from DHT.
+ */
+static int
+csGet (struct GNUNET_ClientHandle *client,
+       const GNUNET_MessageHeader * message)
+{
+  const CS_dht_request_get_MESSAGE *get;
+  struct DV_DHT_CLIENT_GET_RECORD *cpc;
+
+  if (ntohs (message->size) != sizeof (CS_dht_request_get_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  get = (const CS_dht_request_get_MESSAGE *) message;
+  cpc = GNUNET_malloc (sizeof (struct DV_DHT_CLIENT_GET_RECORD));
+  cpc->client = client;
+  cpc->get_record = dvdhtAPI->get_start (ntohl (get->type),
+                                       &get->key, &get_result, cpc);
+  GNUNET_mutex_lock (lock);
+  cpc->next = getRecords;
+  getRecords = cpc;
+  GNUNET_mutex_unlock (lock);
+  return GNUNET_OK;
+}
+
+/**
+ * CS handler for stopping existing get from DHT.
+ */
+static int
+csGetEnd (struct GNUNET_ClientHandle *client,
+          const GNUNET_MessageHeader * message)
+{
+  const CS_dht_request_get_MESSAGE *get;
+  struct DV_DHT_CLIENT_GET_RECORD *pos;
+  struct DV_DHT_CLIENT_GET_RECORD *prev;
+
+  if (ntohs (message->size) != sizeof (CS_dht_request_get_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  get = (const CS_dht_request_get_MESSAGE *) message;
+  GNUNET_mutex_lock (lock);
+  pos = getRecords;
+  prev = NULL;
+  while (pos != NULL)
+    {
+      if ((memcmp (pos->client, client, sizeof (client)) == 0) &&
+          (memcmp
+           (&pos->get_record->key, &get->key, sizeof (GNUNET_HashCode)))
+          && (ntohs (get->type) == pos->get_record->type))
+        break;
+      prev = pos;
+      pos = pos->next;
+    }
+  if (pos == NULL)
+    {
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_OK;
+    }
+  if (prev == NULL)
+    getRecords = pos->next;
+  else
+    prev->next = pos->next;
+  GNUNET_mutex_unlock (lock);
+  dvdhtAPI->get_stop (pos->get_record);
+  GNUNET_free (pos);
+
+  return GNUNET_OK;
+}
+
+/**
+ * CS handler for handling exiting client.  Triggers
+ * get_stop for all operations that rely on this client.
+ */
+static void
+csClientExit (struct GNUNET_ClientHandle *client)
+{
+  struct GNUNET_DHT_GetHandle *gr;
+  struct DV_DHT_CLIENT_GET_RECORD *pos;
+  struct DV_DHT_CLIENT_GET_RECORD *prev;
+
+  GNUNET_mutex_lock (lock);
+  pos = getRecords;
+  prev = NULL;
+  while (pos != NULL)
+    {
+      if (pos->client == client)
+        {
+          gr = pos->get_record;
+          if (prev == NULL)
+            getRecords = pos->next;
+          else
+            prev->next = pos->next;
+          GNUNET_mutex_unlock (lock);
+          dvdhtAPI->get_stop (gr);
+          GNUNET_free (pos);
+          GNUNET_mutex_lock (lock);
+          pos = getRecords;
+          continue;
+        }
+      prev = pos;
+      pos = pos->next;
+    }
+  GNUNET_mutex_unlock (lock);
+}
+
+int
+initialize_module_dht (GNUNET_CoreAPIForPlugins * capi)
+{
+  int status;
+
+  dvdhtAPI = capi->service_request ("dv_dht");
+  if (dvdhtAPI == NULL)
+    return GNUNET_SYSERR;
+  coreAPI = capi;
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 _("`%s' registering client handlers: %d %d\n"),
+                 "dht", GNUNET_CS_PROTO_DHT_REQUEST_PUT,
+                 GNUNET_CS_PROTO_DHT_REQUEST_GET);
+  status = GNUNET_OK;
+  lock = GNUNET_mutex_create (GNUNET_NO);
+  if (GNUNET_SYSERR ==
+      capi->cs_handler_register (GNUNET_CS_PROTO_DV_DHT_REQUEST_PUT, &csPut))
+    status = GNUNET_SYSERR;
+  if (GNUNET_SYSERR ==
+      capi->cs_handler_register (GNUNET_CS_PROTO_DV_DHT_REQUEST_GET, &csGet))
+    status = GNUNET_SYSERR;
+  if (GNUNET_SYSERR ==
+      capi->cs_handler_register (GNUNET_CS_PROTO_DV_DHT_REQUEST_GET_END,
+                                 &csGetEnd))
+    status = GNUNET_SYSERR;
+  if (GNUNET_SYSERR == capi->cs_disconnect_handler_register (&csClientExit))
+    status = GNUNET_SYSERR;
+  GNUNET_GE_ASSERT (capi->ectx,
+                    0 == GNUNET_GC_set_configuration_value_string (capi->cfg,
+                                                                   capi->ectx,
+                                                                   "ABOUT",
+                                                                   "dht",
+                                                                   gettext_noop
+                                                                   ("Enables 
efficient non-anonymous routing")));
+  return status;
+}
+
+/**
+ * Find the record, remove it from the linked list
+ * and cancel the operation with the DHT API.
+ */
+static void
+kill_record (void *cls)
+{
+  struct DV_DHT_CLIENT_GET_RECORD *record = cls;
+  struct DV_DHT_CLIENT_GET_RECORD *pos;
+  struct DV_DHT_CLIENT_GET_RECORD *prev;
+
+  GNUNET_mutex_lock (lock);
+  pos = getRecords;
+  prev = NULL;
+  while (pos != NULL)
+    {
+      if (pos == record)
+        break;
+      prev = pos;
+      pos = pos->next;
+    }
+  if (pos == NULL)
+    {
+      GNUNET_mutex_unlock (lock);
+      return;
+    }
+  if (prev == NULL)
+    getRecords = pos->next;
+  else
+    prev->next = pos->next;
+  GNUNET_mutex_unlock (lock);
+  dvdhtAPI->get_stop (record->get_record);
+  GNUNET_free (record);
+}
+
+/**
+ * Unregisters handlers, cleans memory structures etc when node exits.
+ */
+int
+done_module_dht ()
+{
+  int status;
+
+  status = GNUNET_OK;
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "DHT: shutdown\n");
+  if (GNUNET_OK !=
+      coreAPI->cs_handler_unregister (GNUNET_CS_PROTO_DV_DHT_REQUEST_PUT,
+                                      &csPut))
+    status = GNUNET_SYSERR;
+  if (GNUNET_OK !=
+      coreAPI->cs_handler_unregister (GNUNET_CS_PROTO_DV_DHT_REQUEST_GET,
+                                      &csGet))
+    status = GNUNET_SYSERR;
+  if (GNUNET_OK != coreAPI->cs_disconnect_handler_unregister (&csClientExit))
+    status = GNUNET_SYSERR;
+
+  while (getRecords != NULL)
+    kill_record (getRecords);
+  coreAPI->service_release (dvdhtAPI);
+  dvdhtAPI = NULL;
+  coreAPI = NULL;
+  GNUNET_mutex_destroy (lock);
+  return status;
+}
+
+/* end of cs.c */

Added: GNUnet/src/applications/dv_dht/module/routing.c
===================================================================
--- GNUnet/src/applications/dv_dht/module/routing.c                             
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/routing.c     2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,953 @@
+/*
+      This file is part of GNUnet
+      (C) 2006, 2007 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 2, 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 module/routing.c
+ * @brief state for active DV_DHT routing operations
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - implement extra_get_callback
+ * - use "network_size" field to improve our network size estimate(s)
+ */
+
+#include "platform.h"
+#include "routing.h"
+#include "table.h"
+#include "gnunet_protocols.h"
+#include "gnunet_core.h"
+#include "gnunet_stats_service.h"
+#include "gnunet_dv_service.h"
+
+#define DEBUG_ROUTING GNUNET_NO
+
+/**
+ * What is the request priority for DV_DHT operations?
+ */
+#define DV_DHT_PRIORITY 0
+
+/**
+ * What is the estimated per-hop delay for DV_DHT operations
+ * (this is how much we will request from the GNUnet core);
+ * Must not be zero!
+ */
+#define DV_DHT_DELAY (500 * GNUNET_CRON_MILLISECONDS)
+
+/**
+ * What is the maximum number of results returned by any DV_DHT
+ * operation?
+ */
+#define MAX_RESULTS 64
+
+/**
+ * How many peers should a DV_DHT GET request reach on averge?
+ *
+ * Larger factors will result in more aggressive routing of GET
+ * operations (each peer will either forward to GET_TRIES peers that
+ * are closer to the key).
+ */
+#define GET_TRIES 7
+
+/**
+ * At how many peers should a DV_DHT PUT request be replicated
+ * on average?
+ *
+ * Larger factors will result in more replication and
+ * more aggressive routing of PUT operations (each
+ * peer will either forward to PUT_TRIES peers that
+ * are closer to the key, or replicate the content).
+ */
+#define PUT_TRIES 3
+
+/**
+ * How long do we keep content after receiving a PUT request for it?
+ */
+#define CONTENT_LIFETIME (12 * GNUNET_CRON_HOURS)
+
+/**
+ * @brief record used for sending response back
+ */
+typedef struct DV_DHT_Source_Route
+{
+
+  /**
+   * This is a linked list.
+   */
+  struct DV_DHT_Source_Route *next;
+
+  /**
+   * Source of the request.  Replies should be forwarded to
+   * this peer.
+   */
+  GNUNET_PeerIdentity source;
+
+  /**
+   * If local peer is NOT interested in results, this callback
+   * will be NULL.
+   */
+  GNUNET_ResultProcessor receiver;
+
+  void *receiver_closure;
+
+  /**
+   * At what time will this record automatically
+   * expire?
+   */
+  GNUNET_CronTime expire;
+
+} DV_DHT_Source_Route;
+
+/**
+ * @brief message send for DV_DHT get, put or result.
+ *        PUT and RESULT messages are followed by
+ *        the content.  "header.type" distinguishes
+ *        the three types of messages.
+ */
+typedef struct
+{
+
+  GNUNET_MessageHeader header;
+
+  /**
+   * Type of the requested content (NBO)
+   */
+  unsigned int type;
+
+  /**
+   * Number of hops this message has passed (NBO)
+   */
+  unsigned int hop_count;
+
+  /**
+   * Network size estimate -- sum of the logs of the
+   * network size estimates of all hops this message
+   * has passed so far.
+   */
+  unsigned int network_size;
+
+  /**
+   * Search key.
+   */
+  GNUNET_HashCode key;
+
+} DV_DHT_MESSAGE;
+
+/**
+ * Entry in the DV_DHT routing table.
+ */
+typedef struct DV_DHTQueryRecord
+{
+
+  /**
+   * When does this record expire?  Should be the max
+   * of the individual source records.
+   */
+  GNUNET_CronTime expire;
+
+  /**
+   * Information about where to send the results back to.
+   */
+  DV_DHT_Source_Route *sources;
+
+  /**
+   * GET message of this record (what we are forwarding).
+   */
+  DV_DHT_MESSAGE get;
+
+  /**
+   * Hashcodes of the results that we have send back
+   * so far.
+   */
+  GNUNET_HashCode *results;
+
+  /**
+   * Number of entries in results.
+   */
+  unsigned int result_count;
+
+} DV_DHTQueryRecord;
+
+/**
+ * Linked list of active records.
+ */
+static DV_DHTQueryRecord *records;
+
+/**
+ * Size of records
+ */
+static unsigned int rt_size;
+
+/**
+ * Statistics service.
+ */
+static GNUNET_Stats_ServiceAPI *stats;
+
+static GNUNET_Dstore_ServiceAPI *dstore;
+
+static GNUNET_DV_ServiceAPI *dvapi;
+
+static struct GNUNET_Mutex *lock;
+
+static GNUNET_CoreAPIForPlugins *coreAPI;
+
+static unsigned int stat_replies_routed;
+
+static unsigned int stat_results_received;
+
+static unsigned int stat_requests_routed;
+
+static unsigned int stat_get_requests_received;
+
+static unsigned int stat_put_requests_received;
+
+
+/**
+ * To how many peers should we (on average)
+ * forward the request to obtain the desired
+ * target_replication count (on average).
+ */
+static unsigned int
+get_forward_count (unsigned int hop_count, double target_replication)
+{
+  double target_count;
+  unsigned int target_value;
+  unsigned int diameter;
+
+  diameter = GNUNET_DV_DHT_estimate_network_diameter ();
+  if (hop_count > (diameter + 1) * 2)
+    return 0;
+  target_count =
+    target_replication / (target_replication * (hop_count + 1) + diameter);
+  target_value = 0;
+  while (target_value < target_count)
+    target_value++;
+#define LARGE_INT 0xFFFFFF
+  if ((target_count + 1 - target_value) >
+      GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK,
+                         LARGE_INT) / ((double) LARGE_INT))
+    target_value++;
+  return target_value;
+}
+
+
+/**
+ * Given a result, lookup in the routing table
+ * where to send it next.
+ */
+static int
+route_result (const GNUNET_HashCode * key,
+              unsigned int type,
+              unsigned int size, const char *data, void *cls)
+{
+  DV_DHTQueryRecord *q;
+  unsigned int i;
+  unsigned int j;
+  int found;
+  GNUNET_HashCode hc;
+  DV_DHT_MESSAGE *result;
+  unsigned int routed;
+  unsigned int tracked;
+  DV_DHT_Source_Route *pos;
+  DV_DHT_Source_Route *prev;
+  GNUNET_CronTime now;
+#if DEBUG_ROUTING
+  GNUNET_EncName enc;
+#endif
+
+#if DEBUG_ROUTING
+  GNUNET_hash_to_enc (key, &enc);
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "DHT-Routing of result for key `%s'.\n", &enc);
+#endif
+  if (cls != NULL)
+    {
+      result = cls;
+    }
+  else
+    {
+      result = GNUNET_malloc (sizeof (DV_DHT_MESSAGE) + size);
+      result->header.size = htons (sizeof (DV_DHT_MESSAGE) + size);
+      result->header.type = htons (GNUNET_P2P_PROTO_DHT_RESULT);
+      result->type = htonl (type);
+      result->hop_count = htonl (0);
+      result->network_size = htonl (GNUNET_DV_DHT_estimate_network_diameter 
());
+      result->key = *key;
+      memcpy (&result[1], data, size);
+    }
+  GNUNET_hash (data, size, &hc);
+  routed = 0;
+  tracked = 0;
+  GNUNET_mutex_lock (lock);
+  now = GNUNET_get_time ();
+  for (i = 0; i < rt_size; i++)
+    {
+      q = &records[i];
+      tracked++;
+      if ((ntohl (q->get.type) != type) ||
+          (0 != memcmp (key, &q->get.key, sizeof (GNUNET_HashCode))))
+        continue;
+      found = GNUNET_NO;
+      for (j = 0; j < q->result_count; j++)
+        if (0 == memcmp (&hc, &q->results[j], sizeof (GNUNET_HashCode)))
+          {
+            found = GNUNET_YES;
+            break;
+          }
+      if (found == GNUNET_YES)
+        {
+#if DEBUG_ROUTING
+          GNUNET_GE_LOG (coreAPI->ectx,
+                         GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                         GNUNET_GE_DEVELOPER,
+                         "Seen the same result earlier, not routing it 
again.\n");
+#endif
+          break;
+        }
+      routed++;
+      GNUNET_array_grow (q->results, q->result_count, q->result_count + 1);
+      q->results[q->result_count - 1] = hc;
+      pos = q->sources;
+      prev = NULL;
+      while (pos != NULL)
+        {
+          if (pos->expire < now)
+            {
+#if DEBUG_ROUTING
+              GNUNET_hash_to_enc (&pos->source.hashPubKey, &enc);
+              GNUNET_GE_LOG (coreAPI->ectx,
+                             GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                             GNUNET_GE_DEVELOPER,
+                             "Route to peer `%s' has expired (%llu < %llu)\n",
+                             &enc, pos->expire, now);
+#endif
+              if (prev == NULL)
+                q->sources = pos->next;
+              else
+                prev->next = pos->next;
+              GNUNET_free (pos);
+              if (prev == NULL)
+                pos = q->sources;
+              else
+                pos = prev->next;
+              continue;
+            }
+          if (0 != memcmp (&pos->source,
+                           coreAPI->my_identity,
+                           sizeof (GNUNET_PeerIdentity)))
+            {
+#if DEBUG_ROUTING
+              GNUNET_hash_to_enc (&pos->source.hashPubKey, &enc);
+              GNUNET_GE_LOG (coreAPI->ectx,
+                             GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                             GNUNET_GE_DEVELOPER,
+                             "Routing result to `%s'\n", &enc);
+#endif
+              dvapi->dv_send(&pos->source,
+                             &result->header, DV_DHT_PRIORITY,
+                             DV_DHT_DELAY);
+
+              if (stats != NULL)
+                stats->change (stat_replies_routed, 1);
+            }
+          if (pos->receiver != NULL)
+            {
+#if DEBUG_ROUTING
+              GNUNET_GE_LOG (coreAPI->ectx,
+                             GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                             GNUNET_GE_DEVELOPER,
+                             "Routing result to local client\n");
+#endif
+              pos->receiver (key, type, size, data, pos->receiver_closure);
+              if (stats != NULL)
+                stats->change (stat_replies_routed, 1);
+            }
+          pos = pos->next;
+        }
+      if (q->result_count >= MAX_RESULTS)
+        q->expire = 0;
+      break;
+    }
+  GNUNET_mutex_unlock (lock);
+#if DEBUG_ROUTING
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Routed result to %u out of %u pending requests\n",
+                 routed, tracked);
+#endif
+  if (cls == NULL)
+    GNUNET_free (result);
+  return GNUNET_OK;
+}
+
+/**
+ * @return GNUNET_OK if route was added, GNUNET_SYSERR if not
+ */
+static int
+add_route (const GNUNET_PeerIdentity * sender,
+           GNUNET_ResultProcessor handler, void *cls, const DV_DHT_MESSAGE * 
get)
+{
+  DV_DHTQueryRecord *q;
+  unsigned int i;
+  unsigned int rt_pos;
+  unsigned int diameter;
+  GNUNET_CronTime expire;
+  GNUNET_CronTime now;
+  unsigned int hops;
+  struct DV_DHT_Source_Route *pos;
+
+  hops = ntohl (get->hop_count);
+  diameter = GNUNET_DV_DHT_estimate_network_diameter ();
+  if (hops > 2 * diameter)
+    return GNUNET_SYSERR;
+  now = GNUNET_get_time ();
+  expire = now + DV_DHT_DELAY * diameter * 4;
+  GNUNET_mutex_lock (lock);
+  rt_pos = rt_size;
+  for (i = 0; i < rt_size; i++)
+    {
+      q = &records[i];
+      if ((q->expire > now) &&
+          ((0 != memcmp (&q->get.key,
+                         &get->key,
+                         sizeof (GNUNET_HashCode))) ||
+           (q->get.type == get->type)))
+        continue;               /* used and not an identical request */
+      if (q->expire < now)
+        {
+          rt_pos = i;
+          while (q->sources != NULL)
+            {
+              pos = q->sources;
+              q->sources = pos->next;
+              GNUNET_free (pos);
+            }
+          GNUNET_array_grow (q->results, q->result_count, 0);
+          q->expire = 0;
+        }
+      if ((0 == memcmp (&q->get.key,
+                        &get->key,
+                        sizeof (GNUNET_HashCode)) &&
+           (q->get.type == get->type)))
+        {
+          GNUNET_array_grow (q->results, q->result_count, 0);
+          rt_pos = i;
+          break;
+        }
+    }
+  if (rt_pos == rt_size)
+    {
+      /* do not route, no slot available */
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  q = &records[rt_pos];
+  if (q->expire < expire)
+    q->expire = expire;
+  q->get = *get;
+  pos = GNUNET_malloc (sizeof (DV_DHT_Source_Route));
+  pos->next = q->sources;
+  q->sources = pos;
+  if (sender != NULL)
+    pos->source = *sender;
+  else
+    pos->source = *coreAPI->my_identity;
+  pos->expire = expire;
+  pos->receiver = handler;
+  pos->receiver_closure = cls;
+#if DEBUG_ROUTING
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Tracking request in slot %u\n", rt_pos);
+#endif
+  GNUNET_mutex_unlock (lock);
+  if (stats != NULL)
+    stats->change (stat_requests_routed, 1);
+  return GNUNET_OK;
+}
+
+/**
+ * Handle GET message.
+ */
+static int
+handle_get (const GNUNET_PeerIdentity * sender,
+            const GNUNET_MessageHeader * msg)
+{
+  GNUNET_PeerIdentity next[GET_TRIES + 1];
+  const DV_DHT_MESSAGE *get;
+  DV_DHT_MESSAGE aget;
+  unsigned int target_value;
+  unsigned int hop_count;
+  int total;
+  int i;
+  int j;
+#if DEBUG_ROUTING
+  GNUNET_EncName enc;
+  GNUNET_EncName henc;
+#endif
+
+  if (ntohs (msg->size) != sizeof (DV_DHT_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  get = (const DV_DHT_MESSAGE *) msg;
+#if DEBUG_ROUTING
+  GNUNET_hash_to_enc (&get->key, &enc);
+  if (sender != NULL)
+    GNUNET_hash_to_enc (&sender->hashPubKey, &henc);
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Received DV_DHT GET for key `%s' from `%s'.\n", &enc,
+                 sender == NULL ? "me" : (char *) &henc);
+#endif
+  if (stats != NULL)
+    stats->change (stat_get_requests_received, 1);
+  if ((sender != NULL) && (GNUNET_OK != add_route (sender, NULL, NULL, get)))
+    {
+#if DEBUG_ROUTING
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Failed to add entry in routing table for request.\n");
+#endif
+      return GNUNET_OK;         /* could not route */
+    }
+  total = dstore->get (&get->key, ntohl (get->type), &route_result, NULL);
+  if (total > MAX_RESULTS)
+    {
+#if DEBUG_ROUTING
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Found %d results locally, will not route GET any 
further\n",
+                     total);
+#endif
+      return GNUNET_OK;
+    }
+  aget = *get;
+  hop_count = ntohl (get->hop_count);
+  target_value = get_forward_count (hop_count, GET_TRIES);
+  aget.hop_count = htonl (1 + hop_count);
+  aget.network_size =
+    htonl (ntohl (get->network_size) +
+           GNUNET_DV_DHT_estimate_network_diameter ());
+  if (target_value > GET_TRIES)
+    target_value = GET_TRIES;
+  j = 0;
+  if (sender != NULL)
+    next[j++] = *sender;        /* do not send back to sender! */
+  for (i = 0; i < target_value; i++)
+    {
+      if (GNUNET_OK !=
+          GNUNET_DV_DHT_select_peer (&next[j], &get->key, &next[0], j))
+        {
+#if DEBUG_ROUTING
+          GNUNET_GE_LOG (coreAPI->ectx,
+                         GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                         GNUNET_GE_DEVELOPER,
+                         "Failed to select peer for fowarding in round 
%d/%d\n",
+                         i + 1, GET_TRIES);
+#endif
+          break;
+        }
+#if DEBUG_ROUTING
+      GNUNET_hash_to_enc (&next[j].hashPubKey, &enc);
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Forwarding DV_DHT GET request to peer `%s'.\n", &enc);
+#endif
+      dvapi->dv_send(&next[j], &aget.header, DV_DHT_PRIORITY,
+                     DV_DHT_DELAY);
+      j++;
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Handle PUT message.
+ */
+static int
+handle_put (const GNUNET_PeerIdentity * sender,
+            const GNUNET_MessageHeader * msg)
+{
+  GNUNET_PeerIdentity next[PUT_TRIES + 1];
+  const DV_DHT_MESSAGE *put;
+  DV_DHT_MESSAGE *aput;
+  GNUNET_CronTime now;
+  unsigned int hop_count;
+  unsigned int target_value;
+  int store;
+  int i;
+  unsigned int j;
+#if DEBUG_ROUTING
+  GNUNET_EncName enc;
+#endif
+
+  if (ntohs (msg->size) < sizeof (DV_DHT_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  if (stats != NULL)
+    stats->change (stat_put_requests_received, 1);
+  put = (const DV_DHT_MESSAGE *) msg;
+#if DEBUG_ROUTING
+  GNUNET_hash_to_enc (&put->key, &enc);
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Received DV_DHT PUT for key `%s'.\n", &enc);
+#endif
+  store = 0;
+  hop_count = htons (put->hop_count);
+  target_value = get_forward_count (hop_count, PUT_TRIES);
+  aput = GNUNET_malloc (ntohs (msg->size));
+  memcpy (aput, put, ntohs (msg->size));
+  aput->hop_count = htons (hop_count + 1);
+  aput->network_size =
+    htonl (ntohl (put->network_size) +
+           GNUNET_DV_DHT_estimate_network_diameter ());
+  if (target_value > PUT_TRIES)
+    target_value = PUT_TRIES;
+  j = 0;
+  if (sender != NULL)
+    next[j++] = *sender;        /* do not send back to sender! */
+  for (i = 0; i < target_value; i++)
+    {
+      if (GNUNET_OK !=
+          GNUNET_DV_DHT_select_peer (&next[j], &put->key, &next[0], j))
+        {
+#if DEBUG_ROUTING
+          GNUNET_GE_LOG (coreAPI->ectx,
+                         GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                         GNUNET_GE_DEVELOPER,
+                         "Failed to select peer for PUT fowarding in round 
%d/%d\n",
+                         i + 1, PUT_TRIES);
+#endif
+          store = 1;
+          continue;
+        }
+      if (1 == GNUNET_hash_xorcmp (&next[j].hashPubKey,
+                                   &coreAPI->my_identity->hashPubKey,
+                                   &put->key))
+        store = 1;              /* we're closer than the selected target */
+#if DEBUG_ROUTING
+      GNUNET_hash_to_enc (&next[j].hashPubKey, &enc);
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Forwarding DV_DHT PUT request to peer `%s'.\n", &enc);
+#endif
+      dvapi->dv_send (&next[j], &aput->header, DV_DHT_PRIORITY,
+                                DV_DHT_DELAY);
+      j++;
+    }
+  GNUNET_free (aput);
+  if (store != 0)
+    {
+      now = GNUNET_get_time ();
+#if DEBUG_ROUTING
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Decided to cache data `%.*s' locally until %llu (for 
%llu ms)\n",
+                     ntohs (put->header.size) - sizeof (DV_DHT_MESSAGE),
+                     &put[1], CONTENT_LIFETIME + now, CONTENT_LIFETIME);
+#endif
+      dstore->put (&put->key,
+                   ntohl (put->type),
+                   CONTENT_LIFETIME + now,
+                   ntohs (put->header.size) - sizeof (DV_DHT_MESSAGE),
+                   (const char *) &put[1]);
+    }
+  else
+    {
+#if DEBUG_ROUTING
+      GNUNET_GE_LOG (coreAPI->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                     GNUNET_GE_DEVELOPER,
+                     "Decided NOT to cache data `%.*s' locally\n",
+                     ntohs (put->header.size) - sizeof (DHT_MESSAGE),
+                     &put[1]);
+#endif
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Handle RESULT message.
+ */
+static int
+handle_result (const GNUNET_PeerIdentity * sender,
+               const GNUNET_MessageHeader * msg)
+{
+  const DV_DHT_MESSAGE *result;
+#if DEBUG_ROUTING
+  GNUNET_EncName enc;
+#endif
+
+  if (ntohs (msg->size) < sizeof (DV_DHT_MESSAGE))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  if (stats != NULL)
+    stats->change (stat_results_received, 1);
+  result = (const DV_DHT_MESSAGE *) msg;
+#if DEBUG_ROUTING
+  GNUNET_hash_to_enc (&result->key, &enc);
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Received REMOTE DV_DHT RESULT for key `%s'.\n", &enc);
+#endif
+  route_result (&result->key,
+                ntohl (result->type),
+                ntohs (result->header.size) - sizeof (DV_DHT_MESSAGE),
+                (const char *) &result[1], (void *) msg);
+  return GNUNET_OK;
+}
+
+/**
+ * Start a DV_DHT get operation.
+ */
+int
+GNUNET_DV_DHT_get_start (const GNUNET_HashCode * key,
+                      unsigned int type, GNUNET_ResultProcessor handler,
+                      void *cls)
+{
+  DV_DHT_MESSAGE get;
+#if DEBUG_ROUTING
+  GNUNET_EncName enc;
+#endif
+
+  get.header.size = htons (sizeof (DV_DHT_MESSAGE));
+  get.header.type = htons (GNUNET_P2P_PROTO_DHT_GET);
+  get.type = htonl (type);
+  get.hop_count = htonl (0);
+  get.network_size = htonl (GNUNET_DV_DHT_estimate_network_diameter ());
+  get.key = *key;
+#if DEBUG_ROUTING
+  GNUNET_hash_to_enc (&get.key, &enc);
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER,
+                 "Initiating DV_DHT GET (based on local request) for key 
`%s'.\n",
+                 &enc);
+#endif
+  if (GNUNET_OK != add_route (NULL, handler, cls, &get))
+    return GNUNET_SYSERR;
+  handle_get (NULL, &get.header);
+  return GNUNET_OK;
+}
+
+/**
+ * Stop a DV_DHT get operation (prevents calls to
+ * the given iterator).
+ */
+int
+GNUNET_DV_DHT_get_stop (const GNUNET_HashCode * key,
+                     unsigned int type, GNUNET_ResultProcessor handler,
+                     void *cls)
+{
+  unsigned int i;
+  struct DV_DHT_Source_Route *pos;
+  struct DV_DHT_Source_Route *prev;
+  int done;
+
+  done = GNUNET_NO;
+  GNUNET_mutex_lock (lock);
+  for (i = 0; i < rt_size; i++)
+    {
+      prev = NULL;
+      pos = records[i].sources;
+      while (pos != NULL)
+        {
+          if ((pos->receiver == handler) &&
+              (pos->receiver_closure == cls) &&
+              (0 == memcmp (key,
+                            &records[i].get.key, sizeof (GNUNET_HashCode))))
+            {
+              if (prev == NULL)
+                records[i].sources = pos->next;
+              else
+                prev->next = pos->next;
+              GNUNET_free (pos);
+              done = GNUNET_YES;
+              break;
+            }
+          prev = pos;
+          pos = prev->next;
+        }
+      if (records[i].sources == NULL)
+        {
+          GNUNET_array_grow (records[i].results, records[i].result_count, 0);
+          records[i].expire = 0;
+        }
+      if (done == GNUNET_YES)
+        break;
+    }
+  GNUNET_mutex_unlock (lock);
+  if (done != GNUNET_YES)
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+/**
+ * Perform a DV_DHT put operation.  Note that PUT operations always
+ * expire after a period of time and the client is responsible for
+ * doing periodic refreshs.  The given expiration time is ONLY used to
+ * ensure that the datum is certainly deleted by that time (it maybe
+ * deleted earlier).
+ *
+ * @param expiration_time absolute expiration time
+ */
+int
+GNUNET_DV_DHT_put (const GNUNET_HashCode * key,
+                unsigned int type, unsigned int size, const char *data)
+{
+  DV_DHT_MESSAGE *put;
+
+  put = GNUNET_malloc (sizeof (DV_DHT_MESSAGE) + size);
+  put->header.size = htons (sizeof (DV_DHT_MESSAGE) + size);
+  put->header.type = htons (GNUNET_P2P_PROTO_DHT_PUT);
+  put->key = *key;
+  put->type = htonl (type);
+  put->hop_count = htonl (0);
+  put->network_size = htonl (GNUNET_DV_DHT_estimate_network_diameter ());
+  memcpy (&put[1], data, size);
+  handle_put (NULL, &put->header);
+  GNUNET_free (put);
+  return GNUNET_OK;
+}
+
+/**
+ * We have additional "free" bandwidth available.
+ * Possibly find a good query to add to the message
+ * to the given receiver.
+ *
+ * @param padding maximum number of bytes available
+ * @return number of bytes added at position
+ */
+static unsigned int
+extra_get_callback (const GNUNET_PeerIdentity * receiver,
+                    void *position, unsigned int padding)
+{
+  /* FIXME */
+  return 0;
+}
+
+/**
+ * Initialize routing DV_DHT component.
+ *
+ * @param capi the core API
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_DV_DHT_init_routing (GNUNET_CoreAPIForPlugins * capi)
+{
+  unsigned long long rts;
+
+  coreAPI = capi;
+  rts = 65536;
+  GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
+                                            "DHT",
+                                            "TABLESIZE",
+                                            128, 1024 * 1024, 1024, &rts);
+  dstore = coreAPI->service_request ("dstore");
+  if (dstore == NULL)
+    return GNUNET_SYSERR;
+  dvapi = coreAPI->service_request ("dv");
+  if (dvapi == NULL)
+    return GNUNET_SYSERR;
+  GNUNET_array_grow (records, rt_size, rts);
+
+  lock = GNUNET_mutex_create (GNUNET_NO);
+  stats = capi->service_request ("stats");
+  if (stats != NULL)
+    {
+      stat_replies_routed =
+        stats->create (gettext_noop ("# dv_dht replies routed"));
+      stat_requests_routed =
+        stats->create (gettext_noop ("# dv_dht requests routed"));
+      stat_get_requests_received =
+        stats->create (gettext_noop ("# dv_dht get requests received"));
+      stat_put_requests_received =
+        stats->create (gettext_noop ("# dv_dht put requests received"));
+      stat_results_received =
+        stats->create (gettext_noop ("# dv_dht results received"));
+    }
+
+  GNUNET_GE_LOG (coreAPI->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 _("`%s' registering p2p handlers: %d %d %d\n"),
+                 "dv_dht", GNUNET_P2P_PROTO_DHT_GET, GNUNET_P2P_PROTO_DHT_PUT,
+                 GNUNET_P2P_PROTO_DHT_RESULT);
+  coreAPI->p2p_ciphertext_handler_register (GNUNET_P2P_PROTO_DHT_GET,
+                                            &handle_get);
+  coreAPI->p2p_ciphertext_handler_register (GNUNET_P2P_PROTO_DHT_PUT,
+                                            &handle_put);
+  coreAPI->p2p_ciphertext_handler_register (GNUNET_P2P_PROTO_DHT_RESULT,
+                                            &handle_result);
+  coreAPI->send_callback_register (sizeof (DV_DHT_MESSAGE), 0,
+                                   &extra_get_callback);
+  return GNUNET_OK;
+}
+
+/**
+ * Shutdown routing DV_DHT component.
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_DV_DHT_done_routing ()
+{
+  unsigned int i;
+  struct DV_DHT_Source_Route *pos;
+
+  coreAPI->send_callback_unregister (sizeof (DV_DHT_MESSAGE),
+                                     &extra_get_callback);
+  coreAPI->p2p_ciphertext_handler_unregister (GNUNET_P2P_PROTO_DHT_GET,
+                                              &handle_get);
+  coreAPI->p2p_ciphertext_handler_unregister (GNUNET_P2P_PROTO_DHT_PUT,
+                                              &handle_put);
+  coreAPI->p2p_ciphertext_handler_unregister (GNUNET_P2P_PROTO_DHT_RESULT,
+                                              &handle_result);
+  if (stats != NULL)
+    {
+      coreAPI->service_release (stats);
+      stats = NULL;
+    }
+  GNUNET_mutex_destroy (lock);
+  for (i = 0; i < rt_size; i++)
+    {
+      while (records[i].sources != NULL)
+        {
+          pos = records[i].sources;
+          records[i].sources = pos->next;
+          GNUNET_free (pos);
+        }
+      GNUNET_array_grow (records[i].results, records[i].result_count, 0);
+    }
+  GNUNET_array_grow (records, rt_size, 0);
+  coreAPI->service_release (dstore);
+  return GNUNET_OK;
+}
+
+/* end of routing.c */

Added: GNUnet/src/applications/dv_dht/module/routing.h
===================================================================
--- GNUnet/src/applications/dv_dht/module/routing.h                             
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/routing.h     2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,74 @@
+/*
+      This file is part of GNUnet
+      (C) 2006 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 2, 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 module/routing.h
+ * @brief state for active DV_DHT routing operations
+ * @author Christian Grothoff
+ */
+
+#ifndef DV_DHT_ROUTING_H
+#define DV_DHT_ROUTING_H
+
+#include "gnunet_util.h"
+#include "gnunet_core.h"
+#include "gnunet_dstore_service.h"
+
+/**
+ * Start a DV_DHT get operation.
+ */
+int GNUNET_DV_DHT_get_start (const GNUNET_HashCode * key,
+                          unsigned int type, GNUNET_ResultProcessor handler,
+                          void *cls);
+
+/**
+ * Stop a DV_DHT get operation (prevents calls to
+ * the given iterator).
+ */
+int GNUNET_DV_DHT_get_stop (const GNUNET_HashCode * key,
+                         unsigned int type, GNUNET_ResultProcessor handler,
+                         void *cls);
+
+/**
+ * Perform a DV_DHT put operation.  Note that PUT operations always
+ * expire after a period of time and the client is responsible for
+ * doing periodic refreshs.
+ *
+ * @param expiration_time absolute expiration time
+ */
+int GNUNET_DV_DHT_put (const GNUNET_HashCode * key,
+                    unsigned int type, unsigned int size, const char *data);
+
+/**
+ * Initialize routing DV_DHT component.
+ *
+ * @param capi the core API
+ * @return GNUNET_OK on success
+ */
+int GNUNET_DV_DHT_init_routing (GNUNET_CoreAPIForPlugins * capi);
+
+/**
+ * Shutdown routing DV_DHT component.
+ *
+ * @return GNUNET_OK on success
+ */
+int GNUNET_DV_DHT_done_routing (void);
+
+#endif

Added: GNUnet/src/applications/dv_dht/module/service.c
===================================================================
--- GNUnet/src/applications/dv_dht/module/service.c                             
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/service.c     2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,126 @@
+/*
+      This file is part of GNUnet
+      (C) 2006, 2007 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 2, 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 module/service.c
+ * @brief internal GNUnet DV_DHT service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "table.h"
+#include "routing.h"
+#include "gnunet_dv_dht_service.h"
+#include "service.h"
+
+/**
+ * Global core API.
+ */
+static GNUNET_CoreAPIForPlugins *coreAPI;
+
+/**
+ * Perform an asynchronous GET operation on the DV_DHT identified by
+ * 'table' using 'key' as the key.  The peer does not have to be part
+ * of the table (if so, we will attempt to locate a peer that is!).
+ *
+ * Even in the case of a time-out (once completion callback has been
+ * invoked), clients will still call the "stop" function explicitly.
+ *
+ * @param table table to use for the lookup
+ * @param key the key to look up
+ * @param timeout how long to wait until this operation should
+ *        automatically time-out
+ * @param callback function to call on each result
+ * @param cls extra argument to callback
+ * @return handle to stop the async get
+ */
+static struct GNUNET_DV_DHT_GetHandle *
+dv_dht_get_async_start (unsigned int type,
+                     const GNUNET_HashCode * key,
+                     GNUNET_ResultProcessor callback, void *cls)
+{
+  struct GNUNET_DV_DHT_GetHandle *ret;
+
+  ret = GNUNET_malloc (sizeof (struct GNUNET_DV_DHT_GetHandle));
+  ret->key = *key;
+  ret->callback = callback;
+  ret->cls = cls;
+  ret->type = type;
+  if (GNUNET_OK != GNUNET_DV_DHT_get_start (key, type, callback, cls))
+    {
+      GNUNET_free (ret);
+      return NULL;
+    }
+  return ret;
+}
+
+/**
+ * Stop async DV_DHT-get.  Frees associated resources.
+ */
+static int
+dv_dht_get_async_stop (struct GNUNET_DV_DHT_GetHandle *record)
+{
+  GNUNET_DV_DHT_get_stop (&record->key, record->type, record->callback,
+                       record->cls);
+  GNUNET_free (record);
+  return GNUNET_OK;
+}
+
+/**
+ * Provide the DV DV_DHT service.  The DV DV_DHT service depends on the
+ * RPC and DV services.
+ *
+ * @param capi the core API
+ * @return NULL on errors, DV_DHT_API otherwise
+ */
+GNUNET_DV_DHT_ServiceAPI *
+provide_module_dv_dht (GNUNET_CoreAPIForPlugins * capi)
+{
+  static GNUNET_DV_DHT_ServiceAPI api;
+
+  if (GNUNET_OK != GNUNET_DV_DHT_table_init (capi))
+    {
+      GNUNET_GE_BREAK (capi->ectx, 0);
+      return NULL;
+    }
+  if (GNUNET_OK != GNUNET_DV_DHT_init_routing (capi))
+    {
+      GNUNET_GE_BREAK (capi->ectx, 0);
+      GNUNET_DV_DHT_table_done ();
+      return NULL;
+    }
+  coreAPI = capi;
+  api.get_start = &dv_dht_get_async_start;
+  api.get_stop = &dv_dht_get_async_stop;
+  api.put = &GNUNET_DV_DHT_put;
+  return &api;
+}
+
+/**
+ * Shutdown DV_DHT service.
+ */
+int
+release_module_dv_dht ()
+{
+  GNUNET_DV_DHT_done_routing ();
+  GNUNET_DV_DHT_table_done ();
+  return GNUNET_OK;
+}
+
+/* end of service.c */

Added: GNUnet/src/applications/dv_dht/module/service.h
===================================================================
--- GNUnet/src/applications/dv_dht/module/service.h                             
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/service.h     2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,57 @@
+/*
+      This file is part of GNUnet
+      (C) 2006, 2007 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 2, 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 module/service.h
+ * @brief internal GNUnet DV DHT service
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+
+/**
+ * Handle used to track GET activity.
+ */
+struct GNUNET_DV_DHT_GetHandle
+{
+  /**
+   * Key that we are looking for.
+   */
+  GNUNET_HashCode key;
+
+  /**
+   * Function to call for each result.
+   */
+  GNUNET_ResultProcessor callback;
+
+  /**
+   * Extra argument to callback.
+   */
+  void *cls;
+
+  /**
+   * Type of the content that we are looking for.
+   */
+  unsigned int type;
+
+};
+
+/* end of service.h */

Added: GNUnet/src/applications/dv_dht/module/table.c
===================================================================
--- GNUnet/src/applications/dv_dht/module/table.c                               
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/table.c       2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,852 @@
+/*
+      This file is part of GNUnet
+      (C) 2006, 2007 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 2, 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 module/table.c
+ * @brief maintains table of DV_DHT connections of this peer
+ * @author Christian Grothoff
+ *
+ * New DV_DHT infrastructure plan:
+ * - no RPC, pure async messaging
+ * - stateful routing; needed for retry and reply routing
+ * - no per-table storage; instead global,
+ *   SQL database-based storage for entire peer
+ * - no delete operation, just get/put + expiration
+ * - no "put" confirmation, try a get to confirm important put!
+ * - modules:
+ *   + table.c: DV_DHT-peer table, peer discovery cron jobs;
+ *     code tries to fill table "as much as possible" over time;
+ *     TODO: expose and improve reliabily metrics (to be added later)???
+ *     TODO: better randomized neighbor selection in DV_DHT_select_peer???
+ *     TODO: add callback for discovery-message padding (use core callback
+ *           for extra-available bandwidth)
+ *     TODO: add LAN tunnels for increased connectivity choices
+ *   + routing.c: tracking of get/put operations, retry, reply handling
+ *     code tries best-match routing among entries in table
+ *   + service.c: provide DV_DHT services to rest of GNUnet process
+ *     (i.e. register datastore with shared data, get/put operations)
+ *   + cs.c: services to out-of-process DV_DHT clients (via dv_dht-lib)
+ */
+
+#include "platform.h"
+#include <math.h>
+#include "table.h"
+#include "gnunet_protocols.h"
+#include "gnunet_util.h"
+#include "gnunet_dv_dht_service.h"
+#include "gnunet_stats_service.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_pingpong_service.h"
+#include "gnunet_dv_service.h"
+
+
+/**
+ * How often should the cron job for maintaining the DV_DHT
+ * run?
+ */
+#define MAINTAIN_FREQUENCY 1500 * GNUNET_CRON_MILLISECONDS
+
+/**
+ * What is the chance (1 in XXX) that we send DISCOVERY messages
+ * to another peer?
+ */
+#define MAINTAIN_CHANCE (10 + 100 * total_peers)
+
+/**
+ * How long can a peer be inactive before we time it out?
+ */
+#define MAINTAIN_PEER_TIMEOUT MAINTAIN_FREQUENCY * MAINTAIN_CHANCE * 4
+
+/**
+ * What is the maximum number of known DV_DHT-enabled peers
+ * advertised for each DISCOVERY message?
+ */
+#define MAINTAIN_ADV_CAP 8
+
+/**
+ * Target number of peers per bucket
+ */
+#define MAINTAIN_BUCKET_SIZE 4
+
+
+/**
+ * Per-peer information.
+ */
+typedef struct
+{
+
+  /**
+   * What was the last time we received a message from this peer?
+   */
+  GNUNET_CronTime lastActivity;
+
+  /**
+   * What was the last time we send a PING to this peer?
+   */
+  GNUNET_CronTime lastTimePingSend;
+
+  /**
+   * What is the average latency for replies received?
+   */
+  GNUNET_CronTime expected_latency;
+
+  /**
+   * Number of responses received
+   */
+  unsigned long long response_count;
+
+  /**
+   * Number of requests sent
+   */
+  unsigned long long request_count;
+
+  /**
+   * What is the identity of the peer?
+   */
+  GNUNET_PeerIdentity id;
+
+} PeerInfo;
+
+/**
+ * Peers are grouped into buckets.
+ */
+typedef struct
+{
+
+  /**
+   * Peers in this bucket.  NULL is used if no peer is known.
+   */
+  PeerInfo **peers;
+
+  /**
+   * Peers in this bucket fall into the distance-range
+   * (2^bstart to 2^bend].
+   */
+  unsigned int bstart;
+
+  /**
+   * Peers in this bucket fall into the distance-range
+   * (2^bstart to 2^bend].
+   */
+  unsigned int bend;
+
+  unsigned int peers_size;
+
+} PeerBucket;
+
+/**
+ * Global core API.
+ */
+static GNUNET_CoreAPIForPlugins *coreAPI;
+
+static GNUNET_DV_ServiceAPI *dvapi;
+
+/**
+ * The buckets (Kademlia style routing table).
+ */
+static PeerBucket *buckets;
+
+/**
+ * Total number of active buckets.
+ */
+static unsigned int bucketCount;
+
+/**
+ * Total number of peers in routing table.
+ */
+static unsigned int total_peers;
+
+/**
+ * Mutex to synchronize access to tables.
+ */
+static struct GNUNET_Mutex *lock;
+
+/**
+ * Identity service.
+ */
+static GNUNET_Identity_ServiceAPI *identity;
+
+/**
+ * Statistics service.
+ */
+static GNUNET_Stats_ServiceAPI *stats;
+
+/**
+ * Pingpong service.
+ */
+static GNUNET_Pingpong_ServiceAPI *pingpong;
+
+static int stat_dht_total_peers;
+
+static int stat_dht_discoveries;
+
+static int stat_dht_route_looks;
+
+static int stat_dht_advertisements;
+
+/**
+ * The struct is followed by zero or more
+ * PeerIdentities that the sender knows to
+ * be participating in the DV_DHT.
+ */
+typedef struct
+{
+
+  GNUNET_MessageHeader header;
+
+  unsigned int space_available;
+
+} P2P_DV_DHT_Discovery;
+
+/**
+ * Request for a HELLO for another peer that is participating in the
+ * DV_DHT.  Receiver is expected to send back a HELLO for the peer that
+ * is being requested.
+ */
+typedef struct
+{
+
+  GNUNET_MessageHeader header;
+
+  unsigned int reserved;
+
+  GNUNET_PeerIdentity peer;
+
+} P2P_DV_DHT_ASK_HELLO;
+
+/**
+ * Compute a (rough) estimate of the networks diameter.
+ *
+ * @return estimated network diameter
+ */
+unsigned int
+GNUNET_DV_DHT_estimate_network_diameter ()
+{
+  unsigned int i;
+  for (i = bucketCount - 1; i > 0; i--)
+    {
+      if (buckets[i].peers_size > 0)
+        break;
+    }
+  return i + 1;
+}
+
+/**
+ * Get the index of the lowest bit of the two GNUNET_hash codes that
+ * differs.
+ */
+static unsigned int
+get_bit_distance (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2)
+{
+  unsigned int i;
+  int diff;
+
+  for (i = 0; i < sizeof (GNUNET_HashCode) * 8; i++)
+    {
+      diff = GNUNET_hash_get_bit (h1, i) - GNUNET_hash_get_bit (h2, i);
+      if (diff != 0)
+        return i;
+    }
+  return sizeof (GNUNET_HashCode) * 8;
+}
+
+/**
+ * @return NULL if peer is the current host
+ */
+static PeerBucket *
+findBucketFor (const GNUNET_PeerIdentity * peer)
+{
+  unsigned int index;
+  int i;
+
+  if (0 == memcmp (peer, coreAPI->my_identity, sizeof (GNUNET_PeerIdentity)))
+    return NULL;                /* myself! */
+  index = get_bit_distance (&peer->hashPubKey,
+                            &coreAPI->my_identity->hashPubKey);
+  i = bucketCount - 1;
+  while ((buckets[i].bstart >= index) && (i > 0))
+    i--;
+  if ((buckets[i].bstart <= index) && (buckets[i].bend >= index))
+    return &buckets[i];
+  GNUNET_GE_BREAK (NULL, 0);
+  return NULL;
+}
+
+/**
+ * Find the PeerInfo for the given peer. Returns NULL if peer is not
+ * in our DV_DHT routing table.
+ */
+static PeerInfo *
+findPeerEntryInBucket (PeerBucket * bucket, const GNUNET_PeerIdentity * peer)
+{
+  unsigned int i;
+
+  if (bucket == NULL)
+    return NULL;
+  for (i = 0; i < bucket->peers_size; i++)
+    if (0 ==
+        memcmp (peer, &bucket->peers[i]->id, sizeof (GNUNET_PeerIdentity)))
+      return bucket->peers[i];
+  return NULL;
+}
+
+/**
+ * Find the PeerInfo for the given peer. Returns NULL if peer is not
+ * in our DV_DHT routing table.
+ */
+static PeerInfo *
+findPeerEntry (const GNUNET_PeerIdentity * peer)
+{
+  return findPeerEntryInBucket (findBucketFor (peer), peer);
+}
+
+/**
+ * Return a number that is the larger the closer the
+ * "have" GNUNET_hash code is to the "target".  The basic
+ * idea is that if "have" would be in the n-th lowest
+ * bucket of "target", the returned value should be
+ * 2^n.  However, the largest number we can return
+ * is 2^31, so this number may have to be scaled.
+ *
+ * @return inverse distance metric, non-zero.
+ */
+static unsigned int
+inverse_distance (const GNUNET_HashCode * target,
+                  const GNUNET_HashCode * have)
+{
+  unsigned int bucket;
+  double d;
+
+  bucket = get_bit_distance (target, have);
+  d = bucket * 32;
+  d = exp2 (d / (sizeof (GNUNET_HashCode) * 8));
+  if (d > ((unsigned int) -1))
+    return -1;
+  return (unsigned int) d;
+}
+
+/**
+ * Select a peer from the routing table that would be a good routing
+ * destination for sending a message for "target".  The resulting peer
+ * must not be in the set of blocked peers.<p>
+ *
+ * Note that we should not ALWAYS select the closest peer to the
+ * target, peers further away from the target should be chosen with
+ * exponentially declining probability (this function is also used for
+ * populating the target's routing table).
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_DV_DHT_select_peer (GNUNET_PeerIdentity * set,
+                        const GNUNET_HashCode * target,
+                        const GNUNET_PeerIdentity * blocked,
+                        unsigned int blocked_size)
+{
+  unsigned long long total_distance;
+  unsigned long long selected;
+  unsigned int distance;
+  unsigned int bc;
+  unsigned int ec;
+  unsigned int i;
+  int match;
+  const PeerBucket *bucket;
+  const PeerInfo *pi;
+
+  GNUNET_mutex_lock (lock);
+  if (stats != NULL)
+    stats->change (stat_dht_route_looks, 1);
+  total_distance = 0;
+  for (bc = 0; bc < bucketCount; bc++)
+    {
+      bucket = &buckets[bc];
+      for (ec = 0; ec < bucket->peers_size; ec++)
+        {
+          pi = bucket->peers[ec];
+          match = GNUNET_NO;
+          for (i = 0; i < blocked_size; i++)
+            {
+              if (0 ==
+                  memcmp (&pi->id, &blocked[i], sizeof (GNUNET_PeerIdentity)))
+                {
+                  match = GNUNET_YES;
+                  break;
+                }
+            }
+          if (match == GNUNET_YES)
+            continue;
+          total_distance += inverse_distance (target, &pi->id.hashPubKey);
+        }
+    }
+  if (total_distance == 0)
+    {
+      GNUNET_mutex_unlock (lock);
+      return GNUNET_SYSERR;
+    }
+  selected = GNUNET_random_u64 (GNUNET_RANDOM_QUALITY_WEAK, total_distance);
+  for (bc = 0; bc < bucketCount; bc++)
+    {
+      bucket = &buckets[bc];
+      for (ec = 0; ec < bucket->peers_size; ec++)
+        {
+          pi = bucket->peers[ec];
+          match = GNUNET_NO;
+          for (i = 0; i < blocked_size; i++)
+            {
+              if (0 ==
+                  memcmp (&pi->id, &blocked[i], sizeof (GNUNET_PeerIdentity)))
+                {
+                  match = GNUNET_YES;
+                  break;
+                }
+            }
+          if (match == GNUNET_YES)
+            continue;
+          distance = inverse_distance (target, &pi->id.hashPubKey);
+          if (distance > selected)
+            {
+              *set = pi->id;
+              GNUNET_mutex_unlock (lock);
+              return GNUNET_OK;
+            }
+          selected -= distance;
+        }
+    }
+  GNUNET_GE_BREAK (NULL, 0);
+  GNUNET_mutex_unlock (lock);
+  return GNUNET_SYSERR;
+}
+
+/**
+ * Send a discovery message to the other peer.
+ *
+ * @param cls NULL or pre-built discovery message
+ */
+static void
+broadcast_dht_discovery (const GNUNET_PeerIdentity * other, void *cls)
+{
+  P2P_DV_DHT_Discovery *disco = cls;
+  unsigned int pc;
+  unsigned int i;
+  GNUNET_PeerIdentity *pos;
+
+  if (stats != NULL)
+    stats->change (stat_dht_advertisements, 1);
+  if (disco != NULL)
+    {
+      dvapi->dv_send (other,
+                                &disco->header,
+                                GNUNET_EXTREME_PRIORITY / 4,
+                                MAINTAIN_FREQUENCY * MAINTAIN_CHANCE / 2);
+      return;
+    }
+  pc = total_peers;
+  if (pc > MAINTAIN_ADV_CAP)
+    pc = MAINTAIN_ADV_CAP;
+  if (pc == 0)
+    pc = 1;
+  disco =
+    GNUNET_malloc (pc * sizeof (GNUNET_PeerIdentity) +
+                   sizeof (P2P_DV_DHT_Discovery));
+  disco->header.type = htons (GNUNET_P2P_PROTO_DHT_DISCOVERY);
+  disco->space_available = -1;  /* FIXME */
+  pos = (GNUNET_PeerIdentity *) & disco[1];
+  i = 0;
+  if (total_peers == 0)
+    {
+      /* put in our own identity (otherwise we get into a
+         storm of empty discovery messages) */
+      pos[0] = *coreAPI->my_identity;
+      i = 1;
+    }
+  while (i < pc)
+    {
+      if (GNUNET_OK !=
+          GNUNET_DV_DHT_select_peer (&pos[i], &other->hashPubKey, pos, i))
+        pc--;
+      else
+        i++;
+    }
+  disco->header.size =
+    htons (pc * sizeof (GNUNET_PeerIdentity) + sizeof (P2P_DV_DHT_Discovery));
+  dvapi->dv_send (other, &disco->header, 0,
+                            MAINTAIN_FREQUENCY * MAINTAIN_CHANCE / 2);
+  GNUNET_free (disco);
+}
+
+static void
+broadcast_dht_discovery_prob (const GNUNET_PeerIdentity * other, void *cls)
+{
+  if (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, MAINTAIN_CHANCE) != 0)
+    return;
+  broadcast_dht_discovery (other, cls);
+}
+
+/**
+ * Cron job to maintain DV_DHT routing table.
+ */
+static void
+maintain_dht_job (void *unused)
+{
+  P2P_DV_DHT_Discovery disc;
+
+  if (total_peers == 0)
+    {
+      disc.header.size = htons (sizeof (P2P_DV_DHT_Discovery));
+      disc.header.type = htons (GNUNET_P2P_PROTO_DHT_DISCOVERY);
+      disc.space_available = -1;        /* FIXME */
+      dvapi->dv_connections_iterate(&broadcast_dht_discovery_prob, &disc);
+      /*coreAPI->p2p_connections_iterate (&broadcast_dht_discovery_prob, 
&disc);*/
+    }
+  else
+    {
+      dvapi->dv_connections_iterate(&broadcast_dht_discovery_prob, NULL);
+      /*coreAPI->p2p_connections_iterate (&broadcast_dht_discovery_prob, 
NULL);*/
+    }
+}
+
+/**
+ * We have received a pong from a peer and know it is still
+ * there.
+ */
+static void
+pongNotify (void *cls)
+{
+  GNUNET_PeerIdentity *peer = cls;
+  PeerInfo *pi;
+
+  pi = findPeerEntry (peer);
+  if (pi != NULL)
+    {
+      pi->lastActivity = GNUNET_get_time ();
+      pi->expected_latency = pi->lastActivity - pi->lastTimePingSend;
+      pi->response_count++;
+    }
+  GNUNET_free (peer);
+}
+
+/**
+ * Send a ping to the given peer to check if it is still
+ * running.
+ */
+static void
+pingPeer (PeerInfo * pi)
+{
+  GNUNET_PeerIdentity *p;
+
+  p = GNUNET_malloc (sizeof (GNUNET_PeerIdentity));
+  *p = pi->id;
+  if (GNUNET_OK == pingpong->ping (p, &pongNotify, p, GNUNET_NO, rand ()))
+    {
+      pi->lastTimePingSend = GNUNET_get_time ();
+      pi->request_count++;
+    }
+}
+
+/**
+ * Check if pi is still up and running.  May also try
+ * to confirm that the peer is still live.
+ *
+ * @return GNUNET_YES if the peer should be removed from the DV_DHT table
+ */
+static int
+checkExpired (PeerInfo * pi)
+{
+  GNUNET_CronTime now;
+
+  now = GNUNET_get_time ();
+  if (pi->lastActivity >= now)
+    return GNUNET_NO;
+  if (now - pi->lastActivity > MAINTAIN_PEER_TIMEOUT)
+    return GNUNET_YES;
+  if (now - pi->lastActivity > MAINTAIN_PEER_TIMEOUT / 2)
+    pingPeer (pi);
+  return GNUNET_NO;
+}
+
+/**
+ * Check for expired peers in the given bucket.
+ */
+static void
+checkExpiration (PeerBucket * bucket)
+{
+  unsigned int i;
+  PeerInfo *peer;
+
+  for (i = 0; i < bucket->peers_size; i++)
+    {
+      peer = bucket->peers[i];
+      if (checkExpired (peer) == GNUNET_YES)
+        {
+          total_peers--;
+          if (stats != NULL)
+            stats->change (stat_dht_total_peers, -1);
+          GNUNET_free (peer);
+          bucket->peers[i] = bucket->peers[bucket->peers_size - 1];
+          GNUNET_array_grow (bucket->peers, bucket->peers_size,
+                             bucket->peers_size - 1);
+          i--;
+        }
+    }
+}
+
+/**
+ * Consider adding the given peer to the DV_DHT.
+ */
+static void
+considerPeer (const GNUNET_PeerIdentity * sender,
+              const GNUNET_PeerIdentity * peer)
+{
+  PeerInfo *pi;
+  PeerBucket *bucket;
+  P2P_DV_DHT_ASK_HELLO ask;
+  GNUNET_MessageHello *hello;
+
+  bucket = findBucketFor (peer);
+  if (bucket == NULL)
+    return;                     /* peers[i] == self */
+  if (bucket->peers_size >= MAINTAIN_BUCKET_SIZE)
+    checkExpiration (bucket);
+  if (bucket->peers_size >= MAINTAIN_BUCKET_SIZE)
+    return;                     /* do not care */
+  if (NULL != findPeerEntryInBucket (bucket, peer))
+    return;                     /* already have this peer in buckets */
+  /* do we know how to contact this peer? */
+  hello =
+    identity->identity2Hello (peer, GNUNET_TRANSPORT_PROTOCOL_NUMBER_ANY,
+                              GNUNET_NO);
+  if (hello == NULL)
+    {
+      /* if identity not known, ask sender for HELLO of other peer */
+      ask.header.size = htons (sizeof (P2P_DV_DHT_ASK_HELLO));
+      ask.header.type = htons (sizeof (GNUNET_P2P_PROTO_DHT_ASK_HELLO));
+      ask.reserved = 0;
+      ask.peer = *peer;
+      dvapi->dv_send (sender, &ask.header, 0, /* FIXME: priority */
+                                5 * GNUNET_CRON_SECONDS);
+      return;
+    }
+  GNUNET_free (hello);
+  /* check if connected, if not, send discovery */
+  if (GNUNET_OK != coreAPI->p2p_connection_status_check (peer, NULL, NULL))
+    {
+      /* not yet connected; connect sending DISCOVERY */
+      broadcast_dht_discovery (peer, NULL);
+      return;
+    }
+  /* we are connected (in core), add to bucket */
+  pi = GNUNET_malloc (sizeof (PeerInfo));
+  memset (pi, 0, sizeof (PeerInfo));
+  pi->id = *peer;
+  pingPeer (pi);
+  GNUNET_array_grow (bucket->peers, bucket->peers_size,
+                     bucket->peers_size + 1);
+  bucket->peers[bucket->peers_size - 1] = pi;
+  total_peers++;
+  if (stats != NULL)
+    stats->change (stat_dht_total_peers, 1);
+}
+
+/**
+ * Handle discovery message.
+ */
+static int
+handleDiscovery (const GNUNET_PeerIdentity * sender,
+                 const GNUNET_MessageHeader * msg)
+{
+  unsigned int pc;
+  unsigned int i;
+  const P2P_DV_DHT_Discovery *disco;
+  const GNUNET_PeerIdentity *peers;
+
+  pc =
+    (ntohs (msg->size) -
+     sizeof (P2P_DV_DHT_Discovery)) / sizeof (GNUNET_PeerIdentity);
+  if (pc > MAINTAIN_ADV_CAP * 8)
+    {
+      GNUNET_GE_BREAK_OP (coreAPI->ectx, 0);
+      return GNUNET_SYSERR;     /* far too big */
+    }
+  if (ntohs (msg->size) !=
+      sizeof (P2P_DV_DHT_Discovery) + pc * sizeof (GNUNET_PeerIdentity))
+    {
+      GNUNET_GE_BREAK_OP (coreAPI->ectx, 0);
+      return GNUNET_SYSERR;     /* malformed */
+    }
+  disco = (const P2P_DV_DHT_Discovery *) msg;
+  if (stats != NULL)
+    stats->change (stat_dht_discoveries, 1);
+  if (pc == 0)
+    {
+      /* if peer has 0 connections, be sure to send discovery back */
+      broadcast_dht_discovery (sender, NULL);
+    }
+  GNUNET_mutex_lock (lock);
+  considerPeer (sender, sender);
+  peers = (const GNUNET_PeerIdentity *) &disco[1];
+  for (i = 0; i < pc; i++)
+    considerPeer (sender, &peers[i]);
+  GNUNET_mutex_unlock (lock);
+  return GNUNET_OK;
+}
+
+/**
+ * Handle ask hello message.
+ */
+static int
+handleAskHello (const GNUNET_PeerIdentity * sender,
+                const GNUNET_MessageHeader * msg)
+{
+  const P2P_DV_DHT_ASK_HELLO *ask;
+  GNUNET_MessageHello *hello;
+
+  if (ntohs (msg->size) != sizeof (P2P_DV_DHT_ASK_HELLO))
+    {
+      GNUNET_GE_BREAK_OP (coreAPI->ectx, 0);
+      return GNUNET_SYSERR;
+    }
+  ask = (const P2P_DV_DHT_ASK_HELLO *) msg;
+  if (NULL == findBucketFor (&ask->peer))
+    return GNUNET_OK;
+  hello =
+    identity->identity2Hello (&ask->peer,
+                              GNUNET_TRANSPORT_PROTOCOL_NUMBER_ANY,
+                              GNUNET_NO);
+  if (hello == NULL)
+    return GNUNET_OK;
+  dvapi->dv_send (sender, &hello->header, 0,
+                            5 * GNUNET_CRON_SECONDS);
+  GNUNET_free (hello);
+  return GNUNET_OK;
+}
+
+static void
+peer_disconnect_handler (const GNUNET_PeerIdentity * peer, void *unused)
+{
+  PeerBucket *bucket;
+  PeerInfo *info;
+
+  GNUNET_mutex_lock (lock);
+  bucket = findBucketFor (peer);
+  if (bucket != NULL)
+    {
+      info = findPeerEntryInBucket (bucket, peer);
+      if (info != NULL)
+        {
+          info->lastActivity = 0;
+          checkExpiration (bucket);
+        }
+    }
+  GNUNET_mutex_unlock (lock);
+}
+
+/**
+ * Initialize table DV_DHT component.
+ *
+ * @param capi the core API
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_DV_DHT_table_init (GNUNET_CoreAPIForPlugins * capi)
+{
+  unsigned long long i;
+
+  coreAPI = capi;
+  /* use less than 50% of peer's ideal number of
+     connections for DV_DHT table size */
+  i = coreAPI->core_slots_count () / MAINTAIN_BUCKET_SIZE / 2;
+  if (i < 4)
+    i = 4;
+  GNUNET_array_grow (buckets, bucketCount, i);
+  for (i = 0; i < bucketCount; i++)
+    {
+      buckets[i].bstart = 512 * i / bucketCount;
+      buckets[i].bend = 512 * (i + 1) / bucketCount;
+    }
+  lock = capi->global_lock_get ();
+  stats = capi->service_request ("stats");
+  dvapi = capi->service_request ("dv");
+  GNUNET_GE_ASSERT (coreAPI->ectx, dvapi != NULL);
+  if (stats != NULL)
+    {
+      stat_dht_total_peers =
+        stats->create (gettext_noop ("# dv_dht connections"));
+      stat_dht_discoveries =
+        stats->create (gettext_noop ("# dv_dht discovery messages received"));
+      stat_dht_route_looks =
+        stats->create (gettext_noop ("# dv_dht route host lookups performed"));
+      stat_dht_advertisements =
+        stats->create (gettext_noop ("# dv_dht discovery messages sent"));
+    }
+  identity = coreAPI->service_request ("identity");
+  GNUNET_GE_ASSERT (coreAPI->ectx, identity != NULL);
+  pingpong = coreAPI->service_request ("pingpong");
+  GNUNET_GE_ASSERT (coreAPI->ectx, pingpong != NULL);
+  capi->p2p_ciphertext_handler_register (GNUNET_P2P_PROTO_DHT_DISCOVERY,
+                                         &handleDiscovery);
+  capi->p2p_ciphertext_handler_register (GNUNET_P2P_PROTO_DHT_ASK_HELLO,
+                                         &handleAskHello);
+  capi->peer_disconnect_notification_register (&peer_disconnect_handler,
+                                               NULL);
+  GNUNET_cron_add_job (coreAPI->cron, &maintain_dht_job, MAINTAIN_FREQUENCY,
+                       MAINTAIN_FREQUENCY, NULL);
+  return GNUNET_OK;
+}
+
+/**
+ * Shutdown table DV_DHT component.
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_DV_DHT_table_done ()
+{
+  unsigned int i;
+  unsigned int j;
+
+  coreAPI->peer_disconnect_notification_unregister (&peer_disconnect_handler,
+                                                    NULL);
+  coreAPI->p2p_ciphertext_handler_unregister (GNUNET_P2P_PROTO_DHT_DISCOVERY,
+                                              &handleDiscovery);
+  coreAPI->p2p_ciphertext_handler_unregister (GNUNET_P2P_PROTO_DHT_ASK_HELLO,
+                                              &handleAskHello);
+  GNUNET_cron_del_job (coreAPI->cron, &maintain_dht_job, MAINTAIN_FREQUENCY,
+                       NULL);
+  if (stats != NULL)
+    {
+      coreAPI->service_release (stats);
+      stats = NULL;
+    }
+  coreAPI->service_release (identity);
+  identity = NULL;
+  coreAPI->service_release (pingpong);
+  pingpong = NULL;
+  for (i = 0; i < bucketCount; i++)
+    {
+      for (j = 0; j < buckets[i].peers_size; j++)
+        GNUNET_free (buckets[i].peers[j]);
+      GNUNET_array_grow (buckets[i].peers, buckets[i].peers_size, 0);
+    }
+  GNUNET_array_grow (buckets, bucketCount, 0);
+  lock = NULL;
+  return GNUNET_OK;
+}
+
+/* end of table.c */

Added: GNUnet/src/applications/dv_dht/module/table.h
===================================================================
--- GNUnet/src/applications/dv_dht/module/table.h                               
(rev 0)
+++ GNUnet/src/applications/dv_dht/module/table.h       2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,73 @@
+/*
+      This file is part of GNUnet
+      (C) 2006 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 2, 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 module/table.h
+ * @brief DV DHT connection table internal API
+ * @author Nathan Evans
+ * @author Christian Grothoff
+ */
+
+#ifndef DV_DHT_TABLE_H
+#define DV_DHT_TABLE_H
+
+#include "gnunet_util.h"
+#include "gnunet_core.h"
+
+/**
+ * Select a peer from the routing table that would be a good routing
+ * destination for sending a message for "target".  The resulting peer
+ * must not be in the set of blocked peers.<p>
+ *
+ * Note that we should not ALWAYS select the closest peer to the
+ * target, peers further away from the target should be chosen with
+ * exponentially declining probability (this function is also used for
+ * populating the target's routing table).
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int GNUNET_DV_DHT_select_peer (GNUNET_PeerIdentity * set,
+                            const GNUNET_HashCode * target,
+                            const GNUNET_PeerIdentity * blocked,
+                            unsigned int blocked_size);
+
+/**
+ * Compute a (rough) estimate of the networks diameter.
+ *
+ * @return estimated network diameter
+ */
+unsigned int GNUNET_DV_DHT_estimate_network_diameter (void);
+
+/**
+ * Initialize table DV DHT component.
+ *
+ * @param capi the core API
+ * @return GNUNET_OK on success
+ */
+int GNUNET_DV_DHT_table_init (GNUNET_CoreAPIForPlugins * capi);
+
+/**
+ * Shutdown table DV DHT component.
+ *
+ * @return GNUNET_OK on success
+ */
+int GNUNET_DV_DHT_table_done (void);
+
+#endif

Added: GNUnet/src/applications/dv_dht/tools/Makefile.am
===================================================================
--- GNUnet/src/applications/dv_dht/tools/Makefile.am                            
(rev 0)
+++ GNUnet/src/applications/dv_dht/tools/Makefile.am    2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,64 @@
+INCLUDES = -I$(top_srcdir)/src/include 
+
+if USE_COVERAGE
+  AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+lib_LTLIBRARIES = \
+  libgnunetdvdhtapi.la 
+
+noinst_PROGRAMS = \
+  gnunet-dvdht-query 
+
+libgnunetdvdhtapi_la_SOURCES = \
+  dv_dht_api.c
+libgnunetdvdhtapi_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS)
+libgnunetdvdhtapi_la_LIBADD = \
+  $(top_builddir)/src/applications/stats/libgnunetstatsapi.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL)
+
+gnunet_dvdht_query_SOURCES = \
+  dht-query.c
+gnunet_dvdht_query_LDADD =  \
+  $(top_builddir)/src/applications/dv_dht/tools/libgnunetdvdhtapi.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL)
+
+
+
+
+check_PROGRAMS = \
+  dv_dht_loopback_test \
+  dv_dht_twopeer_test \
+  dv_dht_multipeer_test 
+
+TESTS = $(check_PROGRAMS)
+
+dv_dht_loopback_test_SOURCES = \
+  dv_dht_loopback_test.c 
+dv_dht_loopback_test_LDADD = \
+  $(top_builddir)/src/applications/stats/libgnunetstatsapi.la \
+  $(top_builddir)/src/applications/testing/libgnunettestingapi.la \
+  $(top_builddir)/src/applications/dv_dht/tools/libgnunetdvdhtapi.la \
+  $(top_builddir)/src/util/libgnunetutil.la 
+
+dv_dht_twopeer_test_SOURCES = \
+  dv_dht_twopeer_test.c 
+dv_dht_twopeer_test_LDADD = \
+  $(top_builddir)/src/applications/stats/libgnunetstatsapi.la \
+  $(top_builddir)/src/applications/testing/libgnunettestingapi.la \
+  $(top_builddir)/src/applications/dv_dht/tools/libgnunetdvdhtapi.la \
+  $(top_builddir)/src/util/libgnunetutil.la 
+
+dv_dht_multipeer_test_SOURCES = \
+  dv_dht_multipeer_test.c 
+dv_dht_multipeer_test_LDADD = \
+  $(top_builddir)/src/applications/stats/libgnunetstatsapi.la \
+  $(top_builddir)/src/applications/testing/libgnunettestingapi.la \
+  $(top_builddir)/src/applications/dv_dht/tools/libgnunetdvdhtapi.la \
+  $(top_builddir)/src/util/libgnunetutil.la 
+
+EXTRA_DIST = \
+  check.conf 

Added: GNUnet/src/applications/dv_dht/tools/dht-query.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dht-query.c                            
(rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dht-query.c    2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,191 @@
+/*
+      This file is part of GNUnet
+      (C) 2004, 2005, 2006 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 2, 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 dvdht-query.c
+ * @brief perform DHT operations (insert, lookup)
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_directories.h"
+#include "gnunet_protocols.h"
+#include "gnunet_util.h"
+#include "gnunet_dv_dht_lib.h"
+
+#define DEBUG_DHT_QUERY GNUNET_NO
+
+/**
+ * How long should a "GET" run (or how long should
+ * content last on the network).
+ */
+static GNUNET_CronTime timeout = 30 * GNUNET_CRON_SECONDS;
+
+static struct GNUNET_GE_Context *ectx;
+
+static struct GNUNET_GC_Configuration *cfg;
+
+static char *cfgFilename = GNUNET_DEFAULT_CLIENT_CONFIG_FILE;
+
+struct GNUNET_DV_DHT_Context *ctx;
+
+/**
+ * All gnunet-dht-query command line options
+ */
+static struct GNUNET_CommandLineOption gnunetqueryOptions[] = {
+  GNUNET_COMMAND_LINE_OPTION_CFG_FILE (&cfgFilename),   /* -c */
+  GNUNET_COMMAND_LINE_OPTION_HELP (gettext_noop ("Query (get KEY, put KEY 
VALUE) DHT table.")), /* -h */
+  GNUNET_COMMAND_LINE_OPTION_HOSTNAME,  /* -H */
+  GNUNET_COMMAND_LINE_OPTION_LOGGING,   /* -L */
+  {'T', "timeout", "TIME",
+   gettext_noop ("allow TIME ms to process a GET command"),
+   1, &GNUNET_getopt_configure_set_ulong, &timeout},
+  GNUNET_COMMAND_LINE_OPTION_VERSION (PACKAGE_VERSION), /* -v */
+  GNUNET_COMMAND_LINE_OPTION_VERBOSE,
+  GNUNET_COMMAND_LINE_OPTION_END,
+};
+
+static int
+printCallback (const GNUNET_HashCode * hash,
+               unsigned int type,
+               unsigned int size, const char *data, void *unused)
+{
+  printf ("%s: `%.*s'\n", "get", size, data);
+  return GNUNET_OK;
+}
+
+static void
+do_get (struct GNUNET_ClientServerConnection *sock, const char *key)
+{
+  struct GNUNET_DV_DHT_GetRequest *ret;
+  GNUNET_HashCode hc;
+
+  GNUNET_hash (key, strlen (key), &hc);
+#if DEBUG_DHT_QUERY
+  GNUNET_GE_LOG (ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "Issuing `%s(%s)' command.\n", "get", key);
+#endif
+  ret = GNUNET_DV_DHT_get_start (ctx, GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                              &hc);
+  if (ret == NULL)
+    {
+      printf ("`%s(%s)' failed.\n", "get", key);
+      return;
+    }
+  GNUNET_thread_sleep (timeout);
+  GNUNET_DV_DHT_get_stop (ctx, ret);
+}
+
+static void
+do_put (struct GNUNET_ClientServerConnection *sock,
+        const char *key, const char *value)
+{
+  GNUNET_HashCode hc;
+
+  GNUNET_hash (key, strlen (key), &hc);
+#if DEBUG_DHT_QUERY
+  GNUNET_GE_LOG (ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 _("Issuing `%s(%s,%s)' command.\n"), "put", key, value);
+#endif
+  if (GNUNET_OK ==
+      GNUNET_DV_DHT_put (cfg, ectx, &hc, 
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                      strlen (value), value))
+    {
+      printf ("`%s(%s,%s)' succeeded\n", "put", key, value);
+    }
+  else
+    {
+      printf ("`%s(%s,%s)' failed.\n", "put", key, value);
+    }
+}
+
+int
+main (int argc, char *const *argv)
+{
+  int i;
+  struct GNUNET_ClientServerConnection *handle;
+
+  i = GNUNET_init (argc,
+                   argv,
+                   "gnunet-dht-query",
+                   &cfgFilename, gnunetqueryOptions, &ectx, &cfg);
+  if (i == -1)
+    {
+      GNUNET_fini (ectx, cfg);
+      return -1;
+    }
+
+  handle = GNUNET_client_connection_create (ectx, cfg);
+
+  ctx = GNUNET_DV_DHT_context_create (cfg, ectx, &printCallback, NULL);
+  if (handle == NULL)
+    {
+      fprintf (stderr, _("Failed to connect to gnunetd.\n"));
+      GNUNET_GC_free (cfg);
+      GNUNET_GE_free_context (ectx);
+      return 1;
+    }
+
+  while (i < argc)
+    {
+      if (0 == strcmp ("get", argv[i]))
+        {
+          if (i + 2 > argc)
+            {
+              fprintf (stderr,
+                       _("Command `%s' requires an argument (`%s').\n"),
+                       "get", "key");
+              break;
+            }
+          else
+            {
+              do_get (handle, argv[i + 1]);
+              i += 2;
+            }
+          continue;
+        }
+      if (0 == strcmp ("put", argv[i]))
+        {
+          if (i + 3 > argc)
+            {
+              fprintf (stderr,
+                       _
+                       ("Command `%s' requires two arguments (`%s' and 
`%s').\n"),
+                       "put", "key", "value");
+              break;
+            }
+          else
+            {
+              do_put (handle, argv[i + 1], argv[i + 2]);
+              i += 3;
+            }
+          continue;
+        }
+      fprintf (stderr, _("Unsupported command `%s'.  Aborting.\n"), argv[i]);
+      break;
+    }
+  GNUNET_client_connection_destroy (handle);
+  GNUNET_fini (ectx, cfg);
+  return 0;
+}
+
+/* end of dht-query.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_api.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_api.c                           
(rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_api.c   2009-03-11 22:00:19 UTC 
(rev 8328)
@@ -0,0 +1,357 @@
+/*
+      This file is part of GNUnet
+      (C) 2004, 2005, 2006, 2007, 2008 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 2, 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 dv_dht/tools/dht_api.c
+ * @brief DV_DHT-module's core API's implementation.
+ * @author Tomi Tukiainen, Christian Grothoff, Nathan Evans
+ */
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "dht.h"
+#include "gnunet_dv_dht_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+#define DEBUG_DV_DHT_API GNUNET_NO
+
+/**
+ * Doubly-linked list of get requests.
+ */
+struct GNUNET_DV_DHT_GetRequest
+{
+  struct GNUNET_DV_DHT_GetRequest *prev;
+
+  struct GNUNET_DV_DHT_GetRequest *next;
+
+  CS_dht_request_get_MESSAGE request;
+};
+
+/**
+ * Data exchanged between main thread and GET thread.
+ */
+struct GNUNET_DV_DHT_Context
+{
+
+  /**
+   * Connection with gnunetd.
+   */
+  struct GNUNET_ClientServerConnection *sock;
+
+  /**
+   * Lock for head and tail fields.
+   */
+  struct GNUNET_Mutex *lock;
+
+  /**
+   * Callback to call for each result.
+   */
+  GNUNET_ResultProcessor processor;
+
+  /**
+   * Extra argument for processor.
+   */
+  void *closure;
+
+  /**
+   * Thread polling for replies from gnunetd.
+   */
+  struct GNUNET_ThreadHandle *poll_thread;
+
+  /**
+   * Head of our pending requests.
+   */
+  struct GNUNET_DV_DHT_GetRequest *head;
+
+  /**
+   * Tail of our pending requests.
+   */
+  struct GNUNET_DV_DHT_GetRequest *tail;
+
+  /**
+   * Are we done (for whichever reason)?
+   */
+  int aborted;
+
+  /**
+   * Set to YES if we had a write error and need to
+   * resubmit all of our requests.
+   */
+  int restart;
+
+};
+
+/**
+ * Main loop of the poll thread.
+ *
+ * @param cls the DV_DHT context
+ * @return NULL (always)
+ */
+static void *
+poll_thread (void *cls)
+{
+  struct GNUNET_DV_DHT_Context *info = cls;
+  GNUNET_MessageHeader *reply;
+  CS_dht_request_put_MESSAGE *put;
+  struct GNUNET_DV_DHT_GetRequest *get;
+  unsigned int size;
+
+  while (info->aborted == GNUNET_NO)
+    {
+      reply = NULL;
+      if ((info->restart == GNUNET_YES) ||
+          (GNUNET_OK != GNUNET_client_connection_read (info->sock, &reply)))
+        {
+          info->restart = GNUNET_NO;
+          while ((info->aborted == GNUNET_NO) &&
+                 (GNUNET_OK !=
+                  GNUNET_client_connection_ensure_connected (info->sock)))
+            GNUNET_thread_sleep (100 * GNUNET_CRON_MILLISECONDS);
+          if (info->aborted != GNUNET_NO)
+            break;
+          GNUNET_mutex_lock (info->lock);
+          get = info->head;
+          while ((get != NULL) &&
+                 (info->restart == GNUNET_NO) && (info->aborted == GNUNET_NO))
+            {
+              if (GNUNET_OK !=
+                  GNUNET_client_connection_write (info->sock,
+                                                  &get->request.header))
+                info->restart = GNUNET_YES;
+              get = get->next;
+            }
+          GNUNET_mutex_unlock (info->lock);
+          continue;
+        }
+      if ((sizeof (CS_dht_request_put_MESSAGE) > ntohs (reply->size)) ||
+          (GNUNET_CS_PROTO_DV_DHT_REQUEST_PUT != ntohs (reply->type)))
+        {
+          fprintf (stderr,
+                   "Received message of type %u and size %u\n",
+                   ntohs (reply->type), ntohs (reply->size));
+          GNUNET_GE_BREAK (NULL, 0);
+          GNUNET_free (reply);
+          break;                /*  invalid reply */
+        }
+      size = ntohs (reply->size) - sizeof (CS_dht_request_put_MESSAGE);
+      put = (CS_dht_request_put_MESSAGE *) reply;
+      if ((info->processor != NULL) &&
+          (GNUNET_OK != info->processor (&put->key,
+                                         ntohl (put->type),
+                                         size,
+                                         (const char *) &put[1],
+                                         info->closure)))
+        info->aborted = GNUNET_YES;
+      GNUNET_free (reply);
+    }
+  info->aborted = GNUNET_YES;
+  return NULL;
+}
+
+/**
+ * Set up a context for performing asynchronous DV_DHT operations.
+ *
+ * @param resultCallback function to call for results,
+ *        the operation also aborts if the callback returns
+ *        GNUNET_SYSERR
+ * @return NULL on error
+ */
+struct GNUNET_DV_DHT_Context *
+GNUNET_DV_DHT_context_create (struct GNUNET_GC_Configuration
+                           *cfg,
+                           struct GNUNET_GE_Context
+                           *ectx,
+                           GNUNET_ResultProcessor
+                           resultCallback, void *resCallbackClosure)
+{
+  struct GNUNET_DV_DHT_Context *ctx;
+  struct GNUNET_ClientServerConnection *sock;
+
+  sock = GNUNET_client_connection_create (ectx, cfg);
+  if (sock == NULL)
+    return NULL;
+  ctx = GNUNET_malloc (sizeof (struct GNUNET_DV_DHT_Context));
+  ctx->lock = GNUNET_mutex_create (GNUNET_NO);
+  ctx->sock = sock;
+  ctx->processor = resultCallback;
+  ctx->closure = resCallbackClosure;
+  ctx->poll_thread = GNUNET_thread_create (&poll_thread, ctx, 1024 * 8);
+  if (ctx->poll_thread == NULL)
+    {
+      GNUNET_client_connection_destroy (sock);
+      GNUNET_mutex_destroy (ctx->lock);
+      GNUNET_free (ctx);
+      return NULL;
+    }
+  return ctx;
+}
+
+
+/**
+ * Start an asynchronous GET operation on the DV_DHT looking for
+ * key.
+ *
+ * @param type the type of key to look up
+ * @param key the key to look up
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+struct GNUNET_DV_DHT_GetRequest *
+GNUNET_DV_DHT_get_start (struct GNUNET_DV_DHT_Context *ctx,
+                      unsigned int type, const GNUNET_HashCode * key)
+{
+  struct GNUNET_DV_DHT_GetRequest *req;
+
+  req = GNUNET_malloc (sizeof (struct GNUNET_DV_DHT_GetRequest));
+  req->request.header.size = htons (sizeof (CS_dht_request_get_MESSAGE));
+  req->request.header.type = htons (GNUNET_CS_PROTO_DV_DHT_REQUEST_GET);
+  req->request.type = htonl (type);
+  req->request.key = *key;
+  GNUNET_mutex_lock (ctx->lock);
+  GNUNET_DLL_insert (ctx->head, ctx->tail, req);
+  GNUNET_mutex_unlock (ctx->lock);
+  if (GNUNET_OK !=
+      GNUNET_client_connection_write (ctx->sock, &req->request.header))
+    ctx->restart = GNUNET_YES;
+  return req;
+}
+
+
+/**
+ * Stop an asynchronous GET operation on the DV_DHT looking for
+ * key.
+ *
+ * @param req request to stop
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_DV_DHT_get_stop (struct GNUNET_DV_DHT_Context *ctx,
+                     struct GNUNET_DV_DHT_GetRequest *req)
+{
+  CS_dht_request_get_MESSAGE creq;
+
+  creq.header.size = htons (sizeof (CS_dht_request_get_MESSAGE));
+  creq.header.type = htons (GNUNET_CS_PROTO_DV_DHT_REQUEST_GET_END);
+  creq.type = req->request.type;
+  creq.key = req->request.key;
+  GNUNET_mutex_lock (ctx->lock);
+  GNUNET_DLL_remove (ctx->head, ctx->tail, req);
+  GNUNET_mutex_unlock (ctx->lock);
+  if (GNUNET_OK != GNUNET_client_connection_write (ctx->sock, &creq.header))
+    ctx->restart = GNUNET_YES;
+  GNUNET_free (req);
+  return GNUNET_OK;
+}
+
+/**
+ * Destroy a previously created context for DV_DHT operations.
+ *
+ * @param ctx context to destroy
+ * @return GNUNET_SYSERR on error
+ */
+int
+GNUNET_DV_DHT_context_destroy (struct GNUNET_DV_DHT_Context *ctx)
+{
+  void *unused;
+
+  GNUNET_GE_ASSERT (NULL, ctx->head == NULL);
+  GNUNET_GE_ASSERT (NULL, ctx->tail == NULL);
+  ctx->aborted = GNUNET_YES;
+  GNUNET_client_connection_close_forever (ctx->sock);
+  GNUNET_thread_stop_sleep (ctx->poll_thread);
+  GNUNET_thread_join (ctx->poll_thread, &unused);
+  GNUNET_client_connection_destroy (ctx->sock);
+  GNUNET_mutex_destroy (ctx->lock);
+  GNUNET_free (ctx);
+  return GNUNET_OK;
+}
+
+/**
+ * Perform a synchronous put operation.   The peer does not have
+ * to be part of the table!
+ *
+ * @param table table to use for the lookup
+ * @param key the key to store
+ * @param value what to store
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_DV_DHT_put (struct GNUNET_GC_Configuration *cfg,
+                struct GNUNET_GE_Context *ectx,
+                const GNUNET_HashCode * key,
+                unsigned int type, unsigned int size, const char *value)
+{
+  struct GNUNET_ClientServerConnection *sock;
+  CS_dht_request_put_MESSAGE *req;
+  int ret;
+  int ret2;
+
+#if DEBUG_DV_DHT_API
+  GNUNET_GE_LOG (ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "DV_DHT_LIB_put called with value '%.*s'\n", size, value);
+#endif
+  sock = GNUNET_client_connection_create (ectx, cfg);
+  if (sock == NULL)
+    return GNUNET_SYSERR;
+  req = GNUNET_malloc (sizeof (CS_dht_request_put_MESSAGE) + size);
+  req->header.size = htons (sizeof (CS_dht_request_put_MESSAGE) + size);
+  req->header.type = htons (GNUNET_CS_PROTO_DV_DHT_REQUEST_PUT);
+  req->key = *key;
+  req->type = htonl (type);
+  memcpy (&req[1], value, size);
+  ret = GNUNET_client_connection_write (sock, &req->header);
+  if ((GNUNET_OK != GNUNET_client_connection_read_result (sock, &ret2)) ||
+      (ret2 != GNUNET_OK))
+    ret = GNUNET_SYSERR;
+  GNUNET_client_connection_destroy (sock);
+  GNUNET_free (req);
+  return ret;
+}
+
+static int
+waitForConnect (const char *name, unsigned long long value, void *cls)
+{
+  unsigned long long *ok = cls;
+  if ((value > 0) && (0 == strcmp (_("# dv_dht connections"), name)))
+    {
+      *ok = value;
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Check if this peer has DV_DHT connections to
+ * any other peer.
+ *
+ * @param sock connection to gnunetd
+ * @return number of connections
+ */
+unsigned long long
+GNUNET_DV_DHT_test_connected (struct GNUNET_ClientServerConnection *sock)
+{
+  unsigned long long ret;
+
+  GNUNET_STATS_get_statistics (NULL, sock, &waitForConnect, &ret);
+  return ret;
+}
+
+
+/* end of dv_dht_api.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_expiration_test.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_expiration_test.c               
                (rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_expiration_test.c       
2009-03-11 22:00:19 UTC (rev 8328)
@@ -0,0 +1,122 @@
+/*
+     This file is part of GNUnet.
+     (C) 2005, 2006, 2007, 2008 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 2, 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 applications/dht/tools/dht_expiration_test.c
+ * @brief DV_DHT testcase using only a single peer
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dht_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+
+#define START_PEERS 1
+
+static int err;
+
+static int
+result_callback (const GNUNET_HashCode * key,
+                 unsigned int type,
+                 unsigned int size, const char *data, void *cls)
+{
+  fprintf (stderr, "Got %u %u `%.*s'\n", type, size, size, data);
+  err = 1;
+  return GNUNET_SYSERR;
+}
+
+#define CHECK(a) do { if (!(a)) { ret = 1; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; } } while(0)
+
+/**
+ * Testcase to test DV_DHT routing (2 peers only).
+ * @return 0: ok, -1: error
+ */
+int
+main (int argc, const char **argv)
+{
+#if START_PEERS
+  struct GNUNET_TESTING_DaemonContext *peers;
+#endif
+  int ret = 0;
+  GNUNET_HashCode key;
+  char *value;
+  struct GNUNET_GE_Context *ectx;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_DV_DHT_Context *ctx;
+  void *unused_cls = NULL;
+
+
+  ectx = NULL;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_PEERS
+  peers = GNUNET_TESTING_start_daemons ("nat",
+                                        "advertising dv dv_dht stats",
+                                        "/tmp/gnunet-dv-dht-loopback-test",
+                                        2087, 10000, 1);
+  if (peers == NULL)
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#endif
+  GNUNET_GC_set_configuration_value_string (cfg,
+                                            ectx,
+                                            "NETWORK", "HOST",
+                                            "localhost:2087");
+  ctx = GNUNET_DV_DHT_context_create (cfg, ectx, &result_callback, unused_cls);
+  CHECK (ctx != NULL);
+  /* actual test code */
+  GNUNET_hash ("expired_key", 4, &key);
+  value = GNUNET_malloc (8);
+  memset (value, 'A', 8);
+  CHECK (GNUNET_OK == GNUNET_DV_DHT_put (cfg,
+                                      ectx,
+                                      &key,
+                                      
GNUNET_ECRS_BLOCKTYP_DV_DHT_STRING2STRING,
+                                      8, value));
+  /* FIXME: this value has to be >> than the expiration
+     time (which is currently fixed to 12h, so we can not
+     really do this test in practice... */
+  GNUNET_thread_sleep (60 * GNUNET_CRON_SECONDS);
+  CHECK (1 == GNUNET_DV_DHT_get_start (ctx,
+                                    GNUNET_ECRS_BLOCKTYP_DV_DHT_STRING2STRING,
+                                    &key));
+  GNUNET_thread_sleep (15 * GNUNET_CRON_SECONDS);
+  GNUNET_DV_DHT_context_destroy (ctx);
+
+FAILURE:
+#if START_PEERS
+  GNUNET_TESTING_stop_daemons (peers);
+#endif
+  GNUNET_GC_free (cfg);
+  return err;
+}
+
+/* end of dv_dht_expiration_test.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_forwarding_test.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_forwarding_test.c               
                (rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_forwarding_test.c       
2009-03-11 22:00:19 UTC (rev 8328)
@@ -0,0 +1,274 @@
+/*
+     This file is part of GNUnet.
+     (C) 2007, 2008 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 2, 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 applications/dht/tools/dht_multipeer_test.c
+ * @brief DV_DHT testcase
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dv_dht_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+/**
+ * How many peers should the testcase run?  Note that
+ * we create a clique topology so the cost is quadratic!
+ */
+#define NUM_PEERS 8
+
+/**
+ * How many times will we try the DV_DHT-GET operation before
+ * giving up for good?
+ */
+#define NUM_ROUNDS 20
+
+/**
+ * How often do we iterate the put-get loop?
+ */
+#define NUM_REPEAT 5
+
+static int ok;
+static int found;
+
+static int
+result_callback (const GNUNET_HashCode * key,
+                 unsigned int type,
+                 unsigned int size, const char *data, void *cls)
+{
+  int *i = cls;
+  char expect[8];
+
+  memset (expect, (*i), sizeof (expect));
+#if 0
+  fprintf (stderr, "Got %u %u `%.*s' (want `%.*s')\n", type, size, size, data,
+           sizeof (expect), expect);
+#endif
+  if ((8 != size) ||
+      (0 != memcmp (expect, data, size)) ||
+      (type != GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING))
+    return GNUNET_SYSERR;
+  found++;
+  return GNUNET_OK;
+}
+
+
+static int
+waitForConnect (const char *name, unsigned long long value, void *cls)
+{
+  if ((value > 0) && (0 == strcmp (_("# dv_dht connections"), name)))
+    {
+      ok = 1;
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_OK;
+}
+
+#define CHECK(a) do { if (!(a)) { ret = 1; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; } } while(0)
+
+/**
+ * Testcase to test DV_DHT routing (many peers).
+ * @return 0: ok, -1: error
+ */
+int
+main (int argc, const char **argv)
+{
+  struct GNUNET_TESTING_DaemonContext *peers;
+  int ret = 0;
+  GNUNET_HashCode key;
+  char value[8];
+  struct GNUNET_GE_Context *ectx;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_ClientServerConnection *sock;
+  struct GNUNET_DV_DHT_Context *dctx;
+  struct GNUNET_DV_DHT_GetRequest *get1;
+  int left;
+  int i;
+  int j;
+  int k;
+  int c;
+  int r;
+  int last;
+  char buf[128];
+
+  ectx = NULL;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  printf ("Starting %u peers...\n", NUM_PEERS);
+  peers = GNUNET_TESTING_start_daemons ("tcp",
+                                        "advertising dv dv_dht stats",
+                                        "/tmp/gnunet-dv-dht-multi-test",
+                                        2087, 10, NUM_PEERS);
+  if (peers == NULL)
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  for (i = 0; i < NUM_PEERS; i++)
+    {
+      for (j = 0; j < i; j++)
+        {
+          if (GNUNET_OK != GNUNET_TESTING_connect_daemons (2087 + 10 * i,
+                                                           2087 + 10 * j))
+            {
+              GNUNET_TESTING_stop_daemons (peers);
+              fprintf (stderr, "Failed to connect the peers!\n");
+              GNUNET_GC_free (cfg);
+              return -1;
+            }
+        }
+    }
+  found = 0;
+  for (r = 0; r < NUM_REPEAT; r++)
+    {
+      if (r > 0)
+        {
+          printf ("Found %u out of %u attempts.\n", found,
+                  NUM_PEERS * NUM_PEERS * r);
+          if (found >= NUM_PEERS * NUM_PEERS * r / 2)
+            break;              /* good enough */
+        }
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+      /* put loop */
+      printf ("Waiting for DV_DHT connections of peer");
+      for (i = 0; i < NUM_PEERS; i++)
+        {
+          if (GNUNET_shutdown_test () == GNUNET_YES)
+            break;
+          ok = 0;
+          printf (" %d", i);
+          fflush (stdout);
+          GNUNET_snprintf (buf, sizeof (buf), "localhost:%u", 2087 + i * 10);
+          GNUNET_GC_set_configuration_value_string (cfg, ectx, "NETWORK",
+                                                    "HOST", buf);
+          /* wait for some DV_DHT's to find each other! */
+          sock = GNUNET_client_connection_create (NULL, cfg);
+          left = 30;            /* how many iterations should we wait? */
+          while (GNUNET_OK ==
+                 GNUNET_STATS_get_statistics (NULL, sock, &waitForConnect,
+                                              NULL))
+            {
+              if (GNUNET_shutdown_test () == GNUNET_YES)
+                break;
+              if (9 == left % 10)
+                printf (".");
+              fflush (stdout);
+              GNUNET_thread_sleep (2 * GNUNET_CRON_SECONDS);
+              left--;
+              if (left == 0)
+                break;
+            }
+          GNUNET_client_connection_destroy (sock);
+          if (ok == 0)
+            {
+              printf ("ERROR!\n");
+              fflush (stdout);
+              GNUNET_TESTING_stop_daemons (peers);
+              fprintf (stderr, "Peers' DV_DHTs failed to DV_DHT-connect!\n");
+              GNUNET_GC_free (cfg);
+              return -1;
+            }
+          GNUNET_hash (buf, strlen (buf), &key);
+          memset (value, 'A' + i, sizeof (value));
+          CHECK (GNUNET_OK == GNUNET_DV_DHT_put (cfg,
+                                              ectx,
+                                              &key,
+                                              
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                              sizeof (value), value));
+        }
+      printf ("\n");
+      /* get loop */
+      for (i = 0; i < NUM_PEERS; i++)
+        {
+          if (GNUNET_shutdown_test () == GNUNET_YES)
+            break;
+          GNUNET_snprintf (buf, sizeof (buf), "localhost:%u", 2087 + i * 10);
+          GNUNET_GC_set_configuration_value_string (cfg,
+                                                    ectx, "NETWORK", "HOST",
+                                                    buf);
+          dctx = GNUNET_DV_DHT_context_create (cfg, ectx, &result_callback, 
&c);
+          printf ("Peer %d gets key", i);
+          fflush (stdout);
+          for (j = 0; j < NUM_PEERS; j++)
+            {
+              if (GNUNET_shutdown_test () == GNUNET_YES)
+                break;
+              c = 'A' + j;
+              GNUNET_snprintf (buf, sizeof (buf), "localhost:%u",
+                               2087 + j * 10);
+              GNUNET_hash (buf, strlen (buf), &key);
+              printf (" %d", j);
+              fflush (stdout);
+              last = found;
+              get1 = GNUNET_DV_DHT_get_start (dctx,
+                                           
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                           &key);
+              GNUNET_GE_ASSERT (NULL, get1 != NULL);
+              for (k = 0; k < NUM_ROUNDS; k++)
+                {
+                  if (GNUNET_shutdown_test () == GNUNET_YES)
+                    break;
+                  if (9 == (k % 10))
+                    {
+                      printf (".");
+                      fflush (stdout);
+                    }
+                  fflush (stdout);
+                  GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+                  if (last < found)
+                    break;
+                }
+              GNUNET_DV_DHT_get_stop (dctx, get1);
+              if (k == NUM_ROUNDS)
+                {
+                  printf ("?");
+                  fflush (stdout);
+                }
+            }
+          GNUNET_DV_DHT_context_destroy (dctx);
+          printf ("\n");
+        }
+    }
+  /* end of actual test code */
+  if (r == NUM_REPEAT)
+    printf ("Found %u out of %u attempts.\n", found,
+            NUM_PEERS * NUM_PEERS * r);
+  if (found < NUM_PEERS * NUM_PEERS * r / 2)
+    {
+      printf
+        ("Not enough results (not even 50%%), marking test as failed!\n");
+      ret = 1;
+    }
+FAILURE:
+  GNUNET_TESTING_stop_daemons (peers);
+  GNUNET_GC_free (cfg);
+  return ret;
+}
+
+/* end of dv_dht_multipeer_test.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_loopback_test.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_loopback_test.c                 
        (rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_loopback_test.c 2009-03-11 
22:00:19 UTC (rev 8328)
@@ -0,0 +1,162 @@
+/*
+     This file is part of GNUnet.
+     (C) 2005, 2006, 2007, 2008 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 2, 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 applications/dv_dht/tools/dv_dht_loopback_test.c
+ * @brief DV_DHT testcase using only a single peer
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dv_dht_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+
+#define START_PEERS 1
+
+static int err;
+
+static int found;
+
+static int
+result_callback (const GNUNET_HashCode * key,
+                 unsigned int type,
+                 unsigned int size, const char *data, void *cls)
+{
+  int *i = cls;
+  char expect[8];
+
+#if 0
+  fprintf (stderr, "Got %u %u `%.*s'\n", type, size, size, data);
+#endif
+  memset (expect, (*i), sizeof (expect));
+  if ((8 != size) ||
+      (0 != memcmp (expect, data, size)) ||
+      (type != GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING))
+    {
+      err = 1;
+      return GNUNET_SYSERR;
+    }
+  found = 1;
+  return GNUNET_OK;
+}
+
+#define CHECK(a) do { if (!(a)) { ret = 1; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; } } while(0)
+
+/**
+ * Testcase to test DV_DHT routing (2 peers only).
+ * @return 0: ok, -1: error
+ */
+int
+main (int argc, const char **argv)
+{
+#if START_PEERS
+  struct GNUNET_TESTING_DaemonContext *peers;
+#endif
+  int ret = 0;
+  GNUNET_HashCode key;
+  char *value;
+  struct GNUNET_GE_Context *ectx;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_DV_DHT_Context *ctx;
+  struct GNUNET_DV_DHT_GetRequest *get1;
+  struct GNUNET_DV_DHT_GetRequest *get2;
+  int left;
+  int i;
+
+  ectx = NULL;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_PEERS
+  peers = GNUNET_TESTING_start_daemons ("nat",
+                                        "advertising dv_dht stats",
+                                        "/tmp/gnunet-dv-dht-loopback-test",
+                                        2087, 10000, 1);
+  if (peers == NULL)
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#endif
+  GNUNET_GC_set_configuration_value_string (cfg,
+                                            ectx,
+                                            "NETWORK", "HOST",
+                                            "localhost:2087");
+  ctx = GNUNET_DV_DHT_context_create (cfg, ectx, &result_callback, &i);
+  CHECK (ctx != NULL);
+  /* actual test code */
+  GNUNET_hash ("key_for_A", 4, &key);
+  value = GNUNET_malloc (8);
+  memset (value, 'A', 8);
+  CHECK (GNUNET_OK == GNUNET_DV_DHT_put (cfg,
+                                      ectx,
+                                      &key,
+                                      GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                      8, value));
+  i = 'A';
+  CHECK (NULL != (get1 = GNUNET_DV_DHT_get_start (ctx,
+                                               
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                               &key)));
+  GNUNET_hash ("key_for_B", 3, &key);
+  value = GNUNET_malloc (8);
+  memset (value, 'B', 8);
+  CHECK (GNUNET_OK == GNUNET_DV_DHT_put (cfg,
+                                      ectx,
+                                      &key,
+                                      GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                      8, value));
+  left = 10;
+  while ((found == 0) && (--left >= 0))
+    GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+  CHECK (err == 0);
+  CHECK (found != 0);
+  found = 0;
+  GNUNET_DV_DHT_get_stop (ctx, get1);
+  i = 'B';
+  CHECK (NULL != (get2 = GNUNET_DV_DHT_get_start (ctx,
+                                               
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                               &key)));
+  left = 10;
+  while ((found == 0) && (--left >= 0))
+    GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+  CHECK (err == 0);
+  CHECK (found != 0);
+  GNUNET_DV_DHT_get_stop (ctx, get2);
+  /* end of actual test code */
+
+  GNUNET_DV_DHT_context_destroy (ctx);
+FAILURE:
+#if START_PEERS
+  GNUNET_TESTING_stop_daemons (peers);
+#endif
+  GNUNET_free (value);
+  GNUNET_GC_free (cfg);
+  return ret;
+}
+
+/* end of dv_dht_loopback_test.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_multipeer_test.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_multipeer_test.c                
                (rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_multipeer_test.c        
2009-03-11 22:00:19 UTC (rev 8328)
@@ -0,0 +1,274 @@
+/*
+     This file is part of GNUnet.
+     (C) 2007, 2008 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 2, 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 applications/dht/tools/dht_multipeer_test.c
+ * @brief DV_DHT testcase
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dv_dht_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+/**
+ * How many peers should the testcase run?  Note that
+ * we create a clique topology so the cost is quadratic!
+ */
+#define NUM_PEERS 8
+
+/**
+ * How many times will we try the DV_DHT-GET operation before
+ * giving up for good?
+ */
+#define NUM_ROUNDS 20
+
+/**
+ * How often do we iterate the put-get loop?
+ */
+#define NUM_REPEAT 5
+
+static int ok;
+static int found;
+
+static int
+result_callback (const GNUNET_HashCode * key,
+                 unsigned int type,
+                 unsigned int size, const char *data, void *cls)
+{
+  int *i = cls;
+  char expect[8];
+
+  memset (expect, (*i), sizeof (expect));
+#if 0
+  fprintf (stderr, "Got %u %u `%.*s' (want `%.*s')\n", type, size, size, data,
+           sizeof (expect), expect);
+#endif
+  if ((8 != size) ||
+      (0 != memcmp (expect, data, size)) ||
+      (type != GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING))
+    return GNUNET_SYSERR;
+  found++;
+  return GNUNET_OK;
+}
+
+
+static int
+waitForConnect (const char *name, unsigned long long value, void *cls)
+{
+  if ((value > 0) && (0 == strcmp (_("# dv_dht connections"), name)))
+    {
+      ok = 1;
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_OK;
+}
+
+#define CHECK(a) do { if (!(a)) { ret = 1; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; } } while(0)
+
+/**
+ * Testcase to test DV_DHT routing (many peers).
+ * @return 0: ok, -1: error
+ */
+int
+main (int argc, const char **argv)
+{
+  struct GNUNET_TESTING_DaemonContext *peers;
+  int ret = 0;
+  GNUNET_HashCode key;
+  char value[8];
+  struct GNUNET_GE_Context *ectx;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_ClientServerConnection *sock;
+  struct GNUNET_DV_DHT_Context *dctx;
+  struct GNUNET_DV_DHT_GetRequest *get1;
+  int left;
+  int i;
+  int j;
+  int k;
+  int c;
+  int r;
+  int last;
+  char buf[128];
+
+  ectx = NULL;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  printf ("Starting %u peers...\n", NUM_PEERS);
+  peers = GNUNET_TESTING_start_daemons ("tcp",
+                                        "advertising dv dv_dht stats",
+                                        "/tmp/gnunet-dv-dht-multi-test",
+                                        2087, 10, NUM_PEERS);
+  if (peers == NULL)
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  for (i = 0; i < NUM_PEERS; i++)
+    {
+      for (j = 0; j < i; j++)
+        {
+          if (GNUNET_OK != GNUNET_TESTING_connect_daemons (2087 + 10 * i,
+                                                           2087 + 10 * j))
+            {
+              GNUNET_TESTING_stop_daemons (peers);
+              fprintf (stderr, "Failed to connect the peers!\n");
+              GNUNET_GC_free (cfg);
+              return -1;
+            }
+        }
+    }
+  found = 0;
+  for (r = 0; r < NUM_REPEAT; r++)
+    {
+      if (r > 0)
+        {
+          printf ("Found %u out of %u attempts.\n", found,
+                  NUM_PEERS * NUM_PEERS * r);
+          if (found >= NUM_PEERS * NUM_PEERS * r / 2)
+            break;              /* good enough */
+        }
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+      /* put loop */
+      printf ("Waiting for DV_DHT connections of peer");
+      for (i = 0; i < NUM_PEERS; i++)
+        {
+          if (GNUNET_shutdown_test () == GNUNET_YES)
+            break;
+          ok = 0;
+          printf (" %d", i);
+          fflush (stdout);
+          GNUNET_snprintf (buf, sizeof (buf), "localhost:%u", 2087 + i * 10);
+          GNUNET_GC_set_configuration_value_string (cfg, ectx, "NETWORK",
+                                                    "HOST", buf);
+          /* wait for some DV_DHT's to find each other! */
+          sock = GNUNET_client_connection_create (NULL, cfg);
+          left = 30;            /* how many iterations should we wait? */
+          while (GNUNET_OK ==
+                 GNUNET_STATS_get_statistics (NULL, sock, &waitForConnect,
+                                              NULL))
+            {
+              if (GNUNET_shutdown_test () == GNUNET_YES)
+                break;
+              if (9 == left % 10)
+                printf (".");
+              fflush (stdout);
+              GNUNET_thread_sleep (2 * GNUNET_CRON_SECONDS);
+              left--;
+              if (left == 0)
+                break;
+            }
+          GNUNET_client_connection_destroy (sock);
+          if (ok == 0)
+            {
+              printf ("ERROR!\n");
+              fflush (stdout);
+              GNUNET_TESTING_stop_daemons (peers);
+              fprintf (stderr, "Peers' DV_DHTs failed to DV_DHT-connect!\n");
+              GNUNET_GC_free (cfg);
+              return -1;
+            }
+          GNUNET_hash (buf, strlen (buf), &key);
+          memset (value, 'A' + i, sizeof (value));
+          CHECK (GNUNET_OK == GNUNET_DV_DHT_put (cfg,
+                                              ectx,
+                                              &key,
+                                              
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                              sizeof (value), value));
+        }
+      printf ("\n");
+      /* get loop */
+      for (i = 0; i < NUM_PEERS; i++)
+        {
+          if (GNUNET_shutdown_test () == GNUNET_YES)
+            break;
+          GNUNET_snprintf (buf, sizeof (buf), "localhost:%u", 2087 + i * 10);
+          GNUNET_GC_set_configuration_value_string (cfg,
+                                                    ectx, "NETWORK", "HOST",
+                                                    buf);
+          dctx = GNUNET_DV_DHT_context_create (cfg, ectx, &result_callback, 
&c);
+          printf ("Peer %d gets key", i);
+          fflush (stdout);
+          for (j = 0; j < NUM_PEERS; j++)
+            {
+              if (GNUNET_shutdown_test () == GNUNET_YES)
+                break;
+              c = 'A' + j;
+              GNUNET_snprintf (buf, sizeof (buf), "localhost:%u",
+                               2087 + j * 10);
+              GNUNET_hash (buf, strlen (buf), &key);
+              printf (" %d", j);
+              fflush (stdout);
+              last = found;
+              get1 = GNUNET_DV_DHT_get_start (dctx,
+                                           
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                           &key);
+              GNUNET_GE_ASSERT (NULL, get1 != NULL);
+              for (k = 0; k < NUM_ROUNDS; k++)
+                {
+                  if (GNUNET_shutdown_test () == GNUNET_YES)
+                    break;
+                  if (9 == (k % 10))
+                    {
+                      printf (".");
+                      fflush (stdout);
+                    }
+                  fflush (stdout);
+                  GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+                  if (last < found)
+                    break;
+                }
+              GNUNET_DV_DHT_get_stop (dctx, get1);
+              if (k == NUM_ROUNDS)
+                {
+                  printf ("?");
+                  fflush (stdout);
+                }
+            }
+          GNUNET_DV_DHT_context_destroy (dctx);
+          printf ("\n");
+        }
+    }
+  /* end of actual test code */
+  if (r == NUM_REPEAT)
+    printf ("Found %u out of %u attempts.\n", found,
+            NUM_PEERS * NUM_PEERS * r);
+  if (found < NUM_PEERS * NUM_PEERS * r / 2)
+    {
+      printf
+        ("Not enough results (not even 50%%), marking test as failed!\n");
+      ret = 1;
+    }
+FAILURE:
+  GNUNET_TESTING_stop_daemons (peers);
+  GNUNET_GC_free (cfg);
+  return ret;
+}
+
+/* end of dv_dht_multipeer_test.c */

Added: GNUnet/src/applications/dv_dht/tools/dv_dht_twopeer_test.c
===================================================================
--- GNUnet/src/applications/dv_dht/tools/dv_dht_twopeer_test.c                  
        (rev 0)
+++ GNUnet/src/applications/dv_dht/tools/dv_dht_twopeer_test.c  2009-03-11 
22:00:19 UTC (rev 8328)
@@ -0,0 +1,225 @@
+/*
+     This file is part of GNUnet.
+     (C) 2005, 2006, 2007 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 2, 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 applications/dht/tools/dht_twopeer_test.c
+ * @brief DV_DHT testcase
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_dv_dht_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_stats_lib.h"
+#include "gnunet_util.h"
+
+
+#define START_PEERS 1
+
+#define NUM_ROUNDS 100
+
+#define CHECK(a) do { if (!(a)) { ret = 1; GNUNET_GE_BREAK(NULL, 0); goto 
FAILURE; } } while(0)
+
+struct PeerData
+{
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_DV_DHT_Context *ctx_peer;
+  struct GNUNET_ClientServerConnection *sock;
+  int peercount;
+  int expect_i;
+};
+
+static int
+test_connected (struct GNUNET_ClientServerConnection *sock)
+{
+  int left = 50;
+  unsigned long long have;
+  while (0 == (have = GNUNET_DV_DHT_test_connected (sock)))
+    {
+      printf (".");
+      fflush (stdout);
+      sleep (2);
+      left--;
+      if (left == 0)
+        break;
+    }
+  printf ((have > 0) ? " OK!\n" : "?\n");
+  return have > 0;
+}
+
+static int
+result_callback (const GNUNET_HashCode * key,
+                 unsigned int type,
+                 unsigned int size, const char *data, void *cls)
+{
+  struct PeerData *pd = cls;
+  char expect[8];
+
+#if 0
+  fprintf (stderr, "Got %u %u `%.*s'\n", type, size, size, data);
+#endif
+  memset (expect, pd->expect_i, sizeof (expect));
+  if ((8 != size) ||
+      (0 != memcmp (expect, data, size)) ||
+      (type != GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING))
+    return GNUNET_SYSERR;
+  pd->peercount--;
+  return GNUNET_OK;
+}
+
+static int
+setup_peer (struct PeerData *pd, const char *pstr)
+{
+  int ret = 0;
+  pd->cfg = GNUNET_GC_create ();
+  CHECK (-1 != GNUNET_GC_parse_configuration (pd->cfg, "check.conf"));
+  GNUNET_GC_set_configuration_value_string (pd->cfg,
+                                            NULL,
+                                            "NETWORK", "HOST",
+                                            "localhost:22087");
+  pd->sock = GNUNET_client_connection_create (NULL, pd->cfg);
+  pd->ctx_peer =
+    GNUNET_DV_DHT_context_create (pd->cfg, NULL, &result_callback, pd);
+FAILURE:
+  return ret;
+}
+
+static void
+free_peer (struct PeerData *pd)
+{
+  if (NULL != pd->ctx_peer)
+    GNUNET_DV_DHT_context_destroy (pd->ctx_peer);
+  if (NULL != pd->sock)
+    GNUNET_client_connection_destroy (pd->sock);
+  if (NULL != pd->cfg)
+    GNUNET_GC_free (pd->cfg);
+}
+
+static int
+put_at_peer (struct PeerData *pd, const char *keys, int val)
+{
+  int ret = 0;
+  char value[8];
+  GNUNET_HashCode key;
+
+  GNUNET_hash (keys, 5, &key);
+  memset (value, val, sizeof (value));
+  CHECK (GNUNET_OK == GNUNET_DV_DHT_put (pd->cfg,
+                                      NULL,
+                                      &key,
+                                      GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                      sizeof (value), value));
+FAILURE:
+  return ret;
+}
+
+static int
+get_at_peer (struct PeerData *pd, const char *keys, int want)
+{
+  int ret = 0;
+  GNUNET_HashCode key;
+  struct GNUNET_DV_DHT_GetRequest *get;
+  int k;
+
+  GNUNET_hash (keys, 5, &key);
+  pd->peercount = 10;
+  pd->expect_i = want;
+  CHECK (NULL != (get = GNUNET_DV_DHT_get_start (pd->ctx_peer,
+                                              
GNUNET_ECRS_BLOCKTYPE_DHT_STRING2STRING,
+                                              &key)));
+  for (k = 0; k < NUM_ROUNDS; k++)
+    {
+      if (0 == (k % 10))
+        printf (".");
+      fflush (stdout);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (pd->peercount < 10)
+        break;
+    }
+  CHECK (GNUNET_OK == GNUNET_DV_DHT_get_stop (pd->ctx_peer, get));
+  printf (pd->peercount < 10 ? " OK!\n" : "?\n");
+  CHECK (pd->peercount < 10);
+FAILURE:
+  return ret;
+}
+
+
+/**
+ * Testcase to test DV_DHT routing (2 peers only).
+ * @return 0: ok, -1: error
+ */
+int
+main (int argc, const char **argv)
+{
+#if START_PEERS
+  struct GNUNET_TESTING_DaemonContext *peers;
+#endif
+  int ret = 0;
+  struct PeerData p1;
+  struct PeerData p2;
+
+  memset (&p1, 0, sizeof (struct PeerData));
+  memset (&p2, 0, sizeof (struct PeerData));
+#if START_PEERS
+  fprintf (stderr, "Starting peers...\n");
+  peers = GNUNET_TESTING_start_daemons ("tcp",
+                                        "advertising dv dv_dht stats",
+                                        "/tmp/gnunet-dv-dht-two-test",
+                                        22087, 10, 2);
+  CHECK (peers != NULL);
+#endif
+  CHECK (0 == setup_peer (&p1, "localhost:22087"));
+  CHECK (0 == setup_peer (&p2, "localhost:22097"));
+  fprintf (stderr, "Connecting peers...\n");
+  CHECK (GNUNET_OK == GNUNET_TESTING_connect_daemons (22087, 22097));
+
+
+  /* wait for DV_DHT's to find each other! */
+  /* verify that peer2 also sees the other DV_DHT! */
+  printf ("Waiting for peers to DV_DHT-connect (1->2)");
+  CHECK (test_connected (p1.sock));
+  printf ("Waiting for peers to DV_DHT-connect (2->1)");
+  CHECK (test_connected (p2.sock));
+
+  /* actual test code */
+  CHECK (0 == put_at_peer (&p1, "key 1", 'A'));
+  CHECK (0 == put_at_peer (&p2, "key 2", 'B'));
+  printf ("DV_DHT get (1->1)");
+  CHECK (0 == get_at_peer (&p1, "key 1", 'A'));
+  printf ("DV_DHT get (2->2");
+  CHECK (0 == get_at_peer (&p2, "key 2", 'B'));
+  printf ("DV_DHT get (1->2)");
+  CHECK (0 == get_at_peer (&p1, "key 2", 'B'));
+  printf ("DV_DHT get (2->1)");
+  CHECK (0 == get_at_peer (&p2, "key 1", 'A'));
+  /* end of actual test code */
+
+FAILURE:
+#if START_PEERS
+  GNUNET_TESTING_stop_daemons (peers);
+#endif
+  free_peer (&p1);
+  free_peer (&p2);
+  return ret;
+}
+
+/* end of dv_dht_twopeer_test.c */





reply via email to

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