[Top][All Lists]
[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 */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r8328 - in GNUnet/src/applications: . dv_dht dv_dht/module dv_dht/tools,
gnunet <=