From: Christian Grothoff Date: Sun, 26 Feb 2017 01:55:46 +0000 (+0100) Subject: get rid of non-working, non-maintained experimental alternative DHTs X-Git-Tag: taler-0.2.1~35 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=02dfcad465db218a19cf55a017aadfadfaf69edc;p=oweals%2Fgnunet.git get rid of non-working, non-maintained experimental alternative DHTs --- diff --git a/src/dht/.gitignore b/src/dht/.gitignore index e7f3c2a86..25b1daf28 100644 --- a/src/dht/.gitignore +++ b/src/dht/.gitignore @@ -1,10 +1,8 @@ -gnunet-service-dht-xvine gnunet-dht-get gnunet-dht-monitor gnunet-dht-profiler gnunet-dht-put gnunet-service-dht -gnunet-service-dht-whanau test_dht_2dtorus test_dht_api test_dht_line diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am index b95083c85..f712890ac 100644 --- a/src/dht/Makefile.am +++ b/src/dht/Makefile.am @@ -50,12 +50,6 @@ libgnunet_plugin_block_dht_la_LDFLAGS = \ libexec_PROGRAMS = \ gnunet-service-dht -if HAVE_EXPERIMENTAL -libexec_PROGRAMS += \ - gnunet-service-dht-xvine \ - gnunet-service-dht-whanau -endif - noinst_PROGRAMS = \ gnunet-dht-monitor \ gnunet-dht-get \ @@ -86,46 +80,6 @@ gnunet_service_dht_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ -lm -gnunet_service_dht_xvine_SOURCES = \ - gnunet-service-xdht.c gnunet-service-dht.h \ - gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ - gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ - gnunet-service-xdht_neighbours.c gnunet-service-xdht_neighbours.h \ - gnunet-service-xdht_routing.c gnunet-service-xdht_routing.h - -gnunet_service_dht_xvine_LDADD = \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/nse/libgnunetnse.la \ - $(top_builddir)/src/ats/libgnunetats.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/block/libgnunetblock.la \ - $(top_builddir)/src/block/libgnunetblockgroup.la \ - $(top_builddir)/src/datacache/libgnunetdatacache.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - -lm - -gnunet_service_dht_whanau_SOURCES = \ - gnunet-service-wdht.c gnunet-service-wdht.h \ - gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ - gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ - gnunet-service-wdht_neighbours.c gnunet-service-dht_neighbours.h -gnunet_service_dht_whanau_LDADD = \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/nse/libgnunetnse.la \ - $(top_builddir)/src/ats/libgnunetats.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/block/libgnunetblock.la \ - $(top_builddir)/src/block/libgnunetblockgroup.la \ - $(top_builddir)/src/datacache/libgnunetdatacache.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - -lm - gnunet_dht_get_SOURCES = \ gnunet-dht-get.c gnunet_dht_get_LDADD = \ diff --git a/src/dht/gnunet-service-wdht.c b/src/dht/gnunet-service-wdht.c deleted file mode 100644 index e1ca1c968..000000000 --- a/src/dht/gnunet-service-wdht.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009, 2010, 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-wdht.c - * @brief GNUnet DHT service - * @author Christian Grothoff - * @author Nathan Evans - */ -#include "platform.h" -#include "gnunet_block_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_hello_lib.h" -#include "gnunet_dht_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet-service-wdht.h" -#include "gnunet-service-dht_datacache.h" -#include "gnunet-service-dht_neighbours.h" -#include "gnunet-service-dht_nse.h" - - -/* Code shared between different DHT implementations */ -#include "gnunet-service-dht_clients.c" - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GDS_NEIGHBOURS_done (); - GDS_DATACACHE_done (); - GDS_NSE_done (); - if (NULL != GDS_block_context) - { - GNUNET_BLOCK_context_destroy (GDS_block_context); - GDS_block_context = NULL; - } - if (NULL != GDS_stats) - { - GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES); - GDS_stats = NULL; - } - GDS_CLIENTS_stop (); -} - - -/** - * Process dht requests. - * - * @param cls closure - * @param c configuration to use - * @param service the initialized service - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *service) -{ - GDS_cfg = c; - GDS_service = service; - GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg); - GDS_stats = GNUNET_STATISTICS_create ("dht", - GDS_cfg); - GDS_NSE_init (); - GDS_DATACACHE_init (); - GDS_CLIENTS_init (); - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, - NULL); - if (GNUNET_OK != GDS_NEIGHBOURS_init ()) - { - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/* Finally, define the main method */ -GDS_DHT_SERVICE_INIT("wdht", &run); - - -/* end of gnunet-service-wdht.c */ diff --git a/src/dht/gnunet-service-wdht.h b/src/dht/gnunet-service-wdht.h deleted file mode 100644 index 5a8e2e21d..000000000 --- a/src/dht/gnunet-service-wdht.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht.h - * @brief GNUnet DHT globals - * @author Christian Grothoff - */ -#ifndef GNUNET_SERVICE_XDHT_H -#define GNUNET_SERVICE_XDHT_H - -#include "gnunet_util_lib.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" - -#define DEBUG_DHT GNUNET_EXTRA_LOGGING - -/** - * Configuration we use. - */ -extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; - -/** - * Our handle to the BLOCK library. - */ -extern struct GNUNET_BLOCK_Context *GDS_block_context; - -/** - * Handle for the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *GDS_stats; - -#endif diff --git a/src/dht/gnunet-service-wdht_clients.c b/src/dht/gnunet-service-wdht_clients.c deleted file mode 100644 index 7ad0d2904..000000000 --- a/src/dht/gnunet-service-wdht_clients.c +++ /dev/null @@ -1,1428 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-wdht_clients.c - * @brief GNUnet DHT service's client management code - * @author Christian Grothoff - * @author Nathan Evans - */ - -#include "platform.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_statistics_service.h" -#include "gnunet-service-wdht.h" -#include "gnunet-service-wdht_clients.h" -#include "gnunet-service-dht_datacache.h" -#include "gnunet-service-wdht_neighbours.h" -#include "dht.h" - - -/** - * Should routing details be logged to stderr (for debugging)? - */ -#define LOG_TRAFFIC(kind,...) GNUNET_log_from (kind, "dht-traffic",__VA_ARGS__) - -#define LOG(kind,...) GNUNET_log_from (kind, "dht-clients",__VA_ARGS__) - -#define DEBUG(...) \ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) - -/** - * Linked list of messages to send to clients. - */ -struct PendingMessage -{ - /** - * Pointer to next item in the list - */ - struct PendingMessage *next; - - /** - * Pointer to previous item in the list - */ - struct PendingMessage *prev; - - /** - * Actual message to be sent, allocated at the end of the struct: - * // msg = (cast) &pm[1]; - * // GNUNET_memcpy (&pm[1], data, len); - */ - const struct GNUNET_MessageHeader *msg; - -}; - - -/** - * Struct containing information about a client, - * handle to connect to it, and any pending messages - * that need to be sent to it. - */ -struct ClientList -{ - /** - * Linked list of active clients - */ - struct ClientList *next; - - /** - * Linked list of active clients - */ - struct ClientList *prev; - - /** - * The handle to this client - */ - struct GNUNET_SERVER_Client *client_handle; - - /** - * Handle to the current transmission request, NULL - * if none pending. - */ - struct GNUNET_SERVER_TransmitHandle *transmit_handle; - - /** - * Linked list of pending messages for this client - */ - struct PendingMessage *pending_head; - - /** - * Tail of linked list of pending messages for this client - */ - struct PendingMessage *pending_tail; - -}; - - -/** - * Entry in the local forwarding map for a client's GET request. - */ -struct ClientQueryRecord -{ - - /** - * The key this request was about - */ - struct GNUNET_HashCode key; - - /** - * Client responsible for the request. - */ - struct ClientList *client; - - /** - * Extended query (see gnunet_block_lib.h), allocated at the end of this struct. - */ - const void *xquery; - - /** - * Replies we have already seen for this request. - */ - struct GNUNET_HashCode *seen_replies; - - /** - * Pointer to this nodes heap location in the retry-heap (for fast removal) - */ - struct GNUNET_CONTAINER_HeapNode *hnode; - - /** - * What's the delay between re-try operations that we currently use for this - * request? - */ - struct GNUNET_TIME_Relative retry_frequency; - - /** - * What's the next time we should re-try this request? - */ - struct GNUNET_TIME_Absolute retry_time; - - /** - * The unique identifier of this request - */ - uint64_t unique_id; - - /** - * Number of bytes in xquery. - */ - size_t xquery_size; - - /** - * Number of entries in @e seen_replies. - */ - unsigned int seen_replies_count; - - /** - * Desired replication level - */ - uint32_t replication; - - /** - * Any message options for this request - */ - uint32_t msg_options; - - /** - * The type for the data for the GET request. - */ - enum GNUNET_BLOCK_Type type; - -}; - - -/** - * Struct containing paremeters of monitoring requests. - */ -struct ClientMonitorRecord -{ - - /** - * Next element in DLL. - */ - struct ClientMonitorRecord *next; - - /** - * Previous element in DLL. - */ - struct ClientMonitorRecord *prev; - - /** - * Type of blocks that are of interest - */ - enum GNUNET_BLOCK_Type type; - - /** - * Key of data of interest, NULL for all. - */ - struct GNUNET_HashCode *key; - - /** - * Flag whether to notify about GET messages. - */ - int16_t get; - - /** - * Flag whether to notify about GET_REPONSE messages. - */ - int16_t get_resp; - - /** - * Flag whether to notify about PUT messages. - */ - uint16_t put; - - /** - * Client to notify of these requests. - */ - struct ClientList *client; -}; - - -/** - * List of active clients. - */ -static struct ClientList *client_head; - -/** - * List of active clients. - */ -static struct ClientList *client_tail; - -/** - * List of active monitoring requests. - */ -static struct ClientMonitorRecord *monitor_head; - -/** - * List of active monitoring requests. - */ -static struct ClientMonitorRecord *monitor_tail; - -/** - * Hashmap for fast key based lookup, maps keys to `struct ClientQueryRecord` entries. - */ -static struct GNUNET_CONTAINER_MultiHashMap *forward_map; - -/** - * Heap with all of our client's request, sorted by retry time (earliest on top). - */ -static struct GNUNET_CONTAINER_Heap *retry_heap; - -/** - * Task that re-transmits requests (using retry_heap). - */ -static struct GNUNET_SCHEDULER_Task * retry_task; - - -/** - * Task run to check for messages that need to be sent to a client. - * - * @param client a ClientList, containing the client and any messages to be sent to it - */ -static void -process_pending_messages (struct ClientList *client); - - -/** - * Callback called as a result of issuing a #GNUNET_SERVER_notify_transmit_ready() - * request. A ClientList is passed as closure, take the head of the list - * and copy it into buf, which has the result of sending the message to the - * client. - * - * @param cls closure to this call - * @param size maximum number of bytes available to send - * @param buf where to copy the actual message to - * - * @return the number of bytes actually copied, 0 indicates failure - */ -static size_t -send_reply_to_client (void *cls, size_t size, void *buf) -{ - struct ClientList *client = cls; - char *cbuf = buf; - struct PendingMessage *reply; - size_t off; - size_t msize; - - client->transmit_handle = NULL; - if (buf == NULL) - { - /* client disconnected */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client %p disconnected, pending messages will be discarded\n", - client->client_handle); - return 0; - } - off = 0; - while ((NULL != (reply = client->pending_head)) && - (size >= off + (msize = ntohs (reply->msg->size)))) - { - GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail, - reply); - GNUNET_memcpy (&cbuf[off], reply->msg, msize); - GNUNET_free (reply); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting %u bytes to client %p\n", - (unsigned int) msize, - client->client_handle); - off += msize; - } - process_pending_messages (client); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitted %u/%u bytes to client %p\n", - (unsigned int) off, - (unsigned int) size, - client->client_handle); - return off; -} - - -/** - * Task run to check for messages that need to be sent to a client. - * - * @param client a ClientList, containing the client and any messages to be sent to it - */ -static void -process_pending_messages (struct ClientList *client) -{ - if ((client->pending_head == NULL) || (client->transmit_handle != NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Not asking for transmission to %p now: %s\n", - client->client_handle, - client->pending_head == - NULL ? "no more messages" : "request already pending"); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asking for transmission of %u bytes to client %p\n", - ntohs (client->pending_head->msg->size), client->client_handle); - client->transmit_handle = - GNUNET_SERVER_notify_transmit_ready (client->client_handle, - ntohs (client->pending_head-> - msg->size), - GNUNET_TIME_UNIT_FOREVER_REL, - &send_reply_to_client, client); -} - - -/** - * Add a PendingMessage to the clients list of messages to be sent - * - * @param client the active client to send the message to - * @param pending_message the actual message to send - */ -static void -add_pending_message (struct ClientList *client, - struct PendingMessage *pending_message) -{ - GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, - pending_message); - process_pending_messages (client); -} - - -/** - * Closure for #forward_reply() - */ -struct ForwardReplyContext -{ - - /** - * Actual message to send to matching clients. - */ - struct PendingMessage *pm; - - /** - * Embedded payload. - */ - const void *data; - - /** - * Type of the data. - */ - enum GNUNET_BLOCK_Type type; - - /** - * Number of bytes in data. - */ - size_t data_size; - - /** - * Do we need to copy @e pm because it was already used? - */ - int do_copy; - -}; - - -/** - * Find a client if it exists, add it otherwise. - * - * @param client the server handle to the client - * - * @return the client if found, a new client otherwise - */ -static struct ClientList * -find_active_client (struct GNUNET_SERVER_Client *client) -{ - struct ClientList *pos = client_head; - struct ClientList *ret; - - while (pos != NULL) - { - if (pos->client_handle == client) - return pos; - pos = pos->next; - } - ret = GNUNET_new (struct ClientList); - ret->client_handle = client; - GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret); - return ret; -} - - -/** - * Iterator over hash map entries that frees all entries - * associated with the given client. - * - * @param cls client to search for in source routes - * @param key current key code (ignored) - * @param value value in the hash map, a ClientQueryRecord - * @return #GNUNET_YES (we should continue to iterate) - */ -static int -remove_client_records (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct ClientList *client = cls; - struct ClientQueryRecord *record = value; - - if (record->client != client) - return GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing client %p's record for key %s\n", client, - GNUNET_h2s (key)); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (forward_map, key, - record)); - if (NULL != record->hnode) - GNUNET_CONTAINER_heap_remove_node (record->hnode); - GNUNET_array_grow (record->seen_replies, record->seen_replies_count, 0); - GNUNET_free (record); - return GNUNET_YES; -} - - -/** - * Iterator over hash map entries that send a given reply to - * each of the matching clients. With some tricky recycling - * of the buffer. - * - * @param cls the `struct ForwardReplyContext` - * @param key current key - * @param value value in the hash map, a ClientQueryRecord - * @return #GNUNET_YES (we should continue to iterate), - * if the result is mal-formed, #GNUNET_NO - */ -static int -forward_reply (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct ForwardReplyContext *frc = cls; - struct ClientQueryRecord *record = value; - struct PendingMessage *pm; - struct GNUNET_DHT_ClientResultMessage *reply; - enum GNUNET_BLOCK_EvaluationResult eval; - int do_free; - struct GNUNET_HashCode ch; - unsigned int i; - - LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, - "XVINE CLIENT-RESULT %s\n", - GNUNET_h2s_full (key)); -#if 0 - if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Record type missmatch, not passing request for key %s to local client\n", - GNUNET_h2s (key)); - - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# Key match, type mismatches in REPLY to CLIENT"), - 1, GNUNET_NO); - return GNUNET_YES; /* type mismatch */ - } -#endif - GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch); - for (i = 0; i < record->seen_replies_count; i++) - if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (struct GNUNET_HashCode))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Duplicate reply, not passing request for key %s to local client\n", - GNUNET_h2s (key)); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# Duplicate REPLIES to CLIENT request dropped"), - 1, GNUNET_NO); - return GNUNET_YES; /* duplicate */ - } - eval = - GNUNET_BLOCK_evaluate (GDS_block_context, - record->type, - GNUNET_BLOCK_EO_NONE, - key, NULL, 0, - record->xquery, - record->xquery_size, - frc->data, - frc->data_size); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Evaluation result is %d for key %s for local client's query\n", - (int) eval, GNUNET_h2s (key)); - switch (eval) - { - case GNUNET_BLOCK_EVALUATION_OK_LAST: - do_free = GNUNET_YES; - break; - case GNUNET_BLOCK_EVALUATION_OK_MORE: - GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch); - do_free = GNUNET_NO; - break; - case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: - /* should be impossible to encounter here */ - GNUNET_break (0); - return GNUNET_YES; - case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: - GNUNET_break_op (0); - return GNUNET_NO; - case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: - GNUNET_break (0); - return GNUNET_NO; - case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: - GNUNET_break (0); - return GNUNET_NO; - case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT: - return GNUNET_YES; - case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Unsupported block type (%u) in request!\n"), record->type); - return GNUNET_NO; - default: - GNUNET_break (0); - return GNUNET_NO; - } - if (GNUNET_NO == frc->do_copy) - { - /* first time, we can use the original data */ - pm = frc->pm; - frc->do_copy = GNUNET_YES; - } - else - { - /* two clients waiting for same reply, must copy for queueing */ - pm = GNUNET_malloc (sizeof (struct PendingMessage) + - ntohs (frc->pm->msg->size)); - GNUNET_memcpy (pm, frc->pm, - sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); - pm->next = pm->prev = NULL; - pm->msg = (struct GNUNET_MessageHeader *) &pm[1]; - } - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# RESULTS queued for clients"), 1, - GNUNET_NO); - reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; - reply->unique_id = record->unique_id; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Queueing reply to query %s for client %p\n", - GNUNET_h2s (key), - record->client->client_handle); - add_pending_message (record->client, pm); - if (GNUNET_YES == do_free) - remove_client_records (record->client, key, record); - return GNUNET_YES; -} - - -/** - * Handle a reply we've received from another peer. If the reply - * matches any of our pending queries, forward it to the respective - * client(s). - * - * @param expiration when will the reply expire - * @param key the query this reply is for - * @param get_path_length number of peers in @a get_path - * @param get_path path the reply took on get - * @param put_path_length number of peers in @a put_path - * @param put_path path the reply took on put - * @param type type of the reply - * @param data_size number of bytes in @a data - * @param data application payload data - */ -void -GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, - const struct GNUNET_HashCode *key, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *get_path, - unsigned int put_path_length, - const struct GNUNET_PeerIdentity *put_path, - enum GNUNET_BLOCK_Type type, size_t data_size, - const void *data) -{ - struct ForwardReplyContext frc; - struct PendingMessage *pm; - struct GNUNET_DHT_ClientResultMessage *reply; - struct GNUNET_PeerIdentity *paths; - size_t msize; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "reply for key %s\n", - GNUNET_h2s (key)); - - if (NULL == GNUNET_CONTAINER_multihashmap_get (forward_map, key)) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# REPLIES ignored for CLIENTS (no match)"), 1, - GNUNET_NO); - return; /* no matching request, fast exit! */ - } - msize = - sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + - (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); - if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Could not pass reply to client, message too big!\n")); - return; - } - DEBUG ("reply FOR DATA_SIZE = %u\n", - (unsigned int) msize); - pm = GNUNET_malloc (msize + sizeof (struct PendingMessage)); - reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; - pm->msg = &reply->header; - reply->header.size = htons ((uint16_t) msize); - reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT); - reply->type = htonl (type); - reply->get_path_length = htonl (get_path_length); - reply->put_path_length = htonl (put_path_length); - reply->unique_id = 0; /* filled in later */ - reply->expiration = GNUNET_TIME_absolute_hton (expiration); - reply->key = *key; - paths = (struct GNUNET_PeerIdentity *) &reply[1]; - GNUNET_memcpy (paths, - put_path, - sizeof (struct GNUNET_PeerIdentity) * put_path_length); - GNUNET_memcpy (&paths[put_path_length], - get_path, - sizeof (struct GNUNET_PeerIdentity) * get_path_length); - GNUNET_memcpy (&paths[get_path_length + put_path_length], - data, - data_size); - frc.do_copy = GNUNET_NO; - frc.pm = pm; - frc.data = data; - frc.data_size = data_size; - frc.type = type; - GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, - key, - &forward_reply, - &frc); - if (GNUNET_NO == frc.do_copy) - { - /* did not match any of the requests, free! */ - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# REPLIES ignored for CLIENTS (no match)"), 1, - GNUNET_NO); - GNUNET_free (pm); - } -} - - -/** - * Check if some client is monitoring GET messages and notify - * them in that case. - * - * @param options Options, for instance RecordRoute, DemultiplexEverywhere. - * @param type The type of data in the request. - * @param hop_count Hop count so far. - * @param path_length number of entries in path (or 0 if not recorded). - * @param path peers on the GET path (or NULL if not recorded). - * @param desired_replication_level Desired replication level. - * @param key Key of the requested data. - */ -void -GDS_CLIENTS_process_get (uint32_t options, - enum GNUNET_BLOCK_Type type, - uint32_t hop_count, - uint32_t desired_replication_level, - unsigned int path_length, - const struct GNUNET_PeerIdentity *path, - const struct GNUNET_HashCode *key) -{ - struct ClientMonitorRecord *m; - struct ClientList **cl; - unsigned int cl_size; - - cl = NULL; - cl_size = 0; - for (m = monitor_head; NULL != m; m = m->next) - { - if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && - (NULL == m->key || - memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0)) - { - struct PendingMessage *pm; - struct GNUNET_DHT_MonitorGetMessage *mmsg; - struct GNUNET_PeerIdentity *msg_path; - size_t msize; - unsigned int i; - - /* Don't send duplicates */ - for (i = 0; i < cl_size; i++) - if (cl[i] == m->client) - break; - if (i < cl_size) - continue; - GNUNET_array_append (cl, cl_size, m->client); - - msize = path_length * sizeof (struct GNUNET_PeerIdentity); - msize += sizeof (struct GNUNET_DHT_MonitorGetMessage); - msize += sizeof (struct PendingMessage); - pm = GNUNET_malloc (msize); - mmsg = (struct GNUNET_DHT_MonitorGetMessage *) &pm[1]; - pm->msg = &mmsg->header; - mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); - mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET); - mmsg->options = htonl(options); - mmsg->type = htonl(type); - mmsg->hop_count = htonl(hop_count); - mmsg->desired_replication_level = htonl(desired_replication_level); - mmsg->get_path_length = htonl(path_length); - GNUNET_memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode)); - msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; - if (path_length > 0) - GNUNET_memcpy (msg_path, path, - path_length * sizeof (struct GNUNET_PeerIdentity)); - add_pending_message (m->client, pm); - } - } - GNUNET_free_non_null (cl); -} - - -/** - * Check if some client is monitoring PUT messages and notify - * them in that case. - * - * @param options options, for instance RecordRoute, DemultiplexEverywhere. - * @param type type of data in the request. - * @param hop_count hop count so far. - * @param path_length number of entries in @a path (or 0 if not recorded). - * @param path peers on the PUT path (or NULL if not recorded). - * @param desired_replication_level desired replication level. - * @param exp expiration time of the data. - * @param key key under which @a data is to be stored. - * @param data pointer to the data carried. - * @param size number of bytes in @a data. - */ -void -GDS_CLIENTS_process_put (uint32_t options, - enum GNUNET_BLOCK_Type type, - uint32_t hop_count, - uint32_t desired_replication_level, - unsigned int path_length, - const struct GNUNET_PeerIdentity *path, - struct GNUNET_TIME_Absolute exp, - const struct GNUNET_HashCode *key, - const void *data, - size_t size) -{ - struct ClientMonitorRecord *m; - struct ClientList **cl; - unsigned int cl_size; - - cl = NULL; - cl_size = 0; - for (m = monitor_head; NULL != m; m = m->next) - { - if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && - (NULL == m->key || - memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0)) - { - struct PendingMessage *pm; - struct GNUNET_DHT_MonitorPutMessage *mmsg; - struct GNUNET_PeerIdentity *msg_path; - size_t msize; - unsigned int i; - - /* Don't send duplicates */ - for (i = 0; i < cl_size; i++) - if (cl[i] == m->client) - break; - if (i < cl_size) - continue; - GNUNET_array_append (cl, cl_size, m->client); - - msize = size; - msize += path_length * sizeof (struct GNUNET_PeerIdentity); - msize += sizeof (struct GNUNET_DHT_MonitorPutMessage); - msize += sizeof (struct PendingMessage); - pm = GNUNET_malloc (msize); - mmsg = (struct GNUNET_DHT_MonitorPutMessage *) &pm[1]; - pm->msg = (struct GNUNET_MessageHeader *) mmsg; - mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); - mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT); - mmsg->options = htonl(options); - mmsg->type = htonl(type); - mmsg->hop_count = htonl(hop_count); - mmsg->desired_replication_level = htonl(desired_replication_level); - mmsg->put_path_length = htonl(path_length); - msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; - if (path_length > 0) - { - GNUNET_memcpy (msg_path, path, - path_length * sizeof (struct GNUNET_PeerIdentity)); - } - mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp); - GNUNET_memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode)); - if (size > 0) - GNUNET_memcpy (&msg_path[path_length], data, size); - add_pending_message (m->client, pm); - } - } - GNUNET_free_non_null (cl); -} - - -/** - * Route the given request via the DHT. - */ -static void -transmit_request (struct ClientQueryRecord *cqr) -{ - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# GET requests from clients injected"), 1, - GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Initiating GET for %s, replication %u, already have %u replies\n", - GNUNET_h2s (&cqr->key), - cqr->replication, - cqr->seen_replies_count); - - GDS_NEIGHBOURS_handle_get (&cqr->key, cqr->type, cqr->msg_options, - cqr->replication); - - /* exponential back-off for retries. - * max GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD (15 min) */ - cqr->retry_frequency = GNUNET_TIME_STD_BACKOFF (cqr->retry_frequency); - cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency); -} - - -/** - * Task that looks at the 'retry_heap' and transmits all of the requests - * on the heap that are ready for transmission. Then re-schedules - * itself (unless the heap is empty). - * - * @param cls unused - */ -static void -transmit_next_request_task (void *cls) -{ - struct ClientQueryRecord *cqr; - struct GNUNET_TIME_Relative delay; - - retry_task = NULL; - while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap))) - { - cqr->hnode = NULL; - delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time); - if (delay.rel_value_us > 0) - { - cqr->hnode = - GNUNET_CONTAINER_heap_insert (retry_heap, cqr, - cqr->retry_time.abs_value_us); - retry_task = - GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task, - NULL); - return; - } - transmit_request (cqr); - cqr->hnode = - GNUNET_CONTAINER_heap_insert (retry_heap, cqr, - cqr->retry_time.abs_value_us); - } -} - - -/** - * Handler for PUT messages. - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - */ -static void -handle_dht_local_put (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_DHT_ClientPutMessage *put_msg; - struct PendingMessage *pm; - struct GNUNET_DHT_ClientPutConfirmationMessage *conf; - uint16_t size; - - size = ntohs (message->size); - if (size < sizeof (struct GNUNET_DHT_ClientPutMessage)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# PUT requests received from clients"), 1, - GNUNET_NO); - put_msg = (const struct GNUNET_DHT_ClientPutMessage *) message; - LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "X-VINE DHT CLIENT-PUT %s\n", - GNUNET_h2s_full (&put_msg->key)); - /* give to local clients */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Handling local PUT of %u-bytes for query %s\n", - size - sizeof (struct GNUNET_DHT_ClientPutMessage), - GNUNET_h2s (&put_msg->key)); - DEBUG("PUT doing put i = %s\n",GNUNET_h2s(&(put_msg->key))); - GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (put_msg->expiration), - &put_msg->key, 0, NULL, 0, NULL, - ntohl (put_msg->type), - size - sizeof (struct GNUNET_DHT_ClientPutMessage), - &put_msg[1]); - - GDS_NEIGHBOURS_handle_put (&put_msg->key, - ntohl (put_msg->type), ntohl (put_msg->options), - ntohl (put_msg->desired_replication_level), - GNUNET_TIME_absolute_ntoh (put_msg->expiration), - &put_msg[1], - size - sizeof (struct GNUNET_DHT_ClientPutMessage)); - pm = GNUNET_malloc (sizeof (struct PendingMessage) + - sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); - conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1]; - conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); - conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK); - conf->reserved = htonl (0); - conf->unique_id = put_msg->unique_id; - pm->msg = &conf->header; - add_pending_message (find_active_client (client), pm); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for DHT GET messages from the client. - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - */ -static void -handle_dht_local_get (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_DHT_ClientGetMessage *get; - struct ClientQueryRecord *cqr; - size_t xquery_size; - const char *xquery; - uint16_t size; - - size = ntohs (message->size); - if (size < sizeof (struct GNUNET_DHT_ClientGetMessage)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage); - get = (const struct GNUNET_DHT_ClientGetMessage *) message; - xquery = (const char *) &get[1]; - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# GET requests received from clients"), 1, - GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received GET request for %s from local client %p, xq: %.*s\n", - GNUNET_h2s (&get->key), client, xquery_size, xquery); - - LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "X-VINE CLIENT-GET %s\n", - GNUNET_h2s_full (&get->key)); - - - cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size); - cqr->key = get->key; - cqr->client = find_active_client (client); - cqr->xquery = (void *) &cqr[1]; - GNUNET_memcpy (&cqr[1], xquery, xquery_size); - cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0); - cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS; - cqr->retry_time = GNUNET_TIME_absolute_get (); - cqr->unique_id = get->unique_id; - cqr->xquery_size = xquery_size; - cqr->replication = ntohl (get->desired_replication_level); - cqr->msg_options = ntohl (get->options); - cqr->type = ntohl (get->type); - - // FIXME use cqr->key, set multihashmap create to GNUNET_YES - GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - struct GNUNET_PeerIdentity my_identity; - my_identity = GDS_NEIGHBOURS_get_my_id(); - GDS_CLIENTS_process_get (ntohl (get->options), - ntohl (get->type), - 0, - ntohl (get->desired_replication_level), - 1, - &my_identity, - &get->key); - /* start remote requests */ - if (NULL != retry_task) - GNUNET_SCHEDULER_cancel (retry_task); - retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Closure for #find_by_unique_id(). - */ -struct FindByUniqueIdContext -{ - /** - * Where to store the result, if found. - */ - struct ClientQueryRecord *cqr; - - /** - * Which ID are we looking for? - */ - uint64_t unique_id; -}; - - -/** - * Function called for each existing DHT record for the given - * query. Checks if it matches the UID given in the closure - * and if so returns the entry as a result. - * - * @param cls the search context - * @param key query for the lookup (not used) - * @param value the `struct ClientQueryRecord` - * @return #GNUNET_YES to continue iteration (result not yet found) - */ -static int -find_by_unique_id (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct FindByUniqueIdContext *fui_ctx = cls; - struct ClientQueryRecord *cqr = value; - - if (cqr->unique_id != fui_ctx->unique_id) - return GNUNET_YES; - fui_ctx->cqr = cqr; - return GNUNET_NO; -} - - -/** - * Handler for "GET result seen" messages from the client. - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - */ -static void -handle_dht_local_get_result_seen (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_DHT_ClientGetResultSeenMessage *seen; - uint16_t size; - unsigned int hash_count; - unsigned int old_count; - const struct GNUNET_HashCode *hc; - struct FindByUniqueIdContext fui_ctx; - struct ClientQueryRecord *cqr; - - size = ntohs (message->size); - if (size < sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - seen = (const struct GNUNET_DHT_ClientGetResultSeenMessage *) message; - hash_count = (size - sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage)) / sizeof (struct GNUNET_HashCode); - if (size != sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage) + hash_count * sizeof (struct GNUNET_HashCode)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - hc = (const struct GNUNET_HashCode*) &seen[1]; - fui_ctx.unique_id = seen->unique_id; - fui_ctx.cqr = NULL; - GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, - &seen->key, - &find_by_unique_id, - &fui_ctx); - if (NULL == (cqr = fui_ctx.cqr)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - /* finally, update 'seen' list */ - old_count = cqr->seen_replies_count; - GNUNET_array_grow (cqr->seen_replies, - cqr->seen_replies_count, - cqr->seen_replies_count + hash_count); - GNUNET_memcpy (&cqr->seen_replies[old_count], - hc, - sizeof (struct GNUNET_HashCode) * hash_count); -} - - -/** - * Closure for #remove_by_unique_id(). - */ -struct RemoveByUniqueIdContext -{ - /** - * Client that issued the removal request. - */ - struct ClientList *client; - - /** - * Unique ID of the request. - */ - uint64_t unique_id; -}; - - -/** - * Iterator over hash map entries that frees all entries - * that match the given client and unique ID. - * - * @param cls unique ID and client to search for in source routes - * @param key current key code - * @param value value in the hash map, a ClientQueryRecord - * @return #GNUNET_YES (we should continue to iterate) - */ -static int -remove_by_unique_id (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - const struct RemoveByUniqueIdContext *ctx = cls; - struct ClientQueryRecord *record = value; - - if (record->unique_id != ctx->unique_id) - return GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing client %p's record for key %s (by unique id)\n", - ctx->client->client_handle, GNUNET_h2s (key)); - return remove_client_records (ctx->client, key, record); -} - - -/** - * Handler for any generic DHT stop messages, calls the appropriate handler - * depending on message type (if processed locally) - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - * - */ -static void -handle_dht_local_get_stop (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg = - (const struct GNUNET_DHT_ClientGetStopMessage *) message; - struct RemoveByUniqueIdContext ctx; - - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# GET STOP requests received from clients"), 1, - GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received GET STOP request for %s from local client %p\n", - GNUNET_h2s (&dht_stop_msg->key), - client); - ctx.client = find_active_client (client); - ctx.unique_id = dht_stop_msg->unique_id; - GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, &dht_stop_msg->key, - &remove_by_unique_id, &ctx); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for monitor start messages - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - * - */ -static void -handle_dht_local_monitor (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct ClientMonitorRecord *r; - const struct GNUNET_DHT_MonitorStartStopMessage *msg; - - msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message; - r = GNUNET_new (struct ClientMonitorRecord); - - r->client = find_active_client(client); - r->type = ntohl(msg->type); - r->get = ntohs(msg->get); - r->get_resp = ntohs(msg->get_resp); - r->put = ntohs(msg->put); - if (0 == ntohs(msg->filter_key)) - r->key = NULL; - else - { - r->key = GNUNET_new (struct GNUNET_HashCode); - GNUNET_memcpy (r->key, &msg->key, sizeof (struct GNUNET_HashCode)); - } - GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, r); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for monitor stop messages - * - * @param cls closure for the service - * @param client the client we received this message from - * @param message the actual message received - */ -static void -handle_dht_local_monitor_stop (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct ClientMonitorRecord *r; - const struct GNUNET_DHT_MonitorStartStopMessage *msg; - int keys_match; - - msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message; - r = monitor_head; - - while (NULL != r) - { - if (NULL == r->key) - keys_match = (0 == ntohs(msg->filter_key)); - else - { - keys_match = (0 != ntohs(msg->filter_key) - && !memcmp(r->key, &msg->key, sizeof(struct GNUNET_HashCode))); - } - if (find_active_client(client) == r->client - && ntohl(msg->type) == r->type - && r->get == msg->get - && r->get_resp == msg->get_resp - && r->put == msg->put - && keys_match - ) - { - GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, r); - GNUNET_free_non_null (r->key); - GNUNET_free (r); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; /* Delete only ONE entry */ - } - r = r->next; - } - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Functions with this signature are called whenever a client - * is disconnected on the network level. - * - * @param cls closure (NULL for dht) - * @param client identification of the client; NULL - * for the last call when the server is destroyed - */ -static void -handle_client_disconnect (void *cls, - struct GNUNET_SERVER_Client *client) -{ - struct ClientList *pos; - struct PendingMessage *reply; - struct ClientMonitorRecord *monitor; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Local client %p disconnects\n", - client); - pos = find_active_client (client); - GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); - if (pos->transmit_handle != NULL) - GNUNET_SERVER_notify_transmit_ready_cancel (pos->transmit_handle); - while (NULL != (reply = pos->pending_head)) - { - GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, reply); - GNUNET_free (reply); - } - monitor = monitor_head; - while (NULL != monitor) - { - if (monitor->client == pos) - { - struct ClientMonitorRecord *next; - - GNUNET_free_non_null (monitor->key); - next = monitor->next; - GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, monitor); - GNUNET_free (monitor); - monitor = next; - } - else - monitor = monitor->next; - } - GNUNET_CONTAINER_multihashmap_iterate (forward_map, &remove_client_records, - pos); - GNUNET_free (pos); -} - - -/** - * Initialize client subsystem. - * - * @param server the initialized server - */ -void -GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server) -{ - static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { - {&handle_dht_local_put, NULL, - GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, 0}, - {&handle_dht_local_get, NULL, - GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, 0}, - {&handle_dht_local_get_stop, NULL, - GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP, - sizeof (struct GNUNET_DHT_ClientGetStopMessage)}, - {&handle_dht_local_monitor, NULL, - GNUNET_MESSAGE_TYPE_DHT_MONITOR_START, - sizeof (struct GNUNET_DHT_MonitorStartStopMessage)}, - {&handle_dht_local_monitor_stop, NULL, - GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP, - sizeof (struct GNUNET_DHT_MonitorStartStopMessage)}, - {&handle_dht_local_get_result_seen, NULL, - GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN, 0}, - {NULL, NULL, 0, 0} - }; - forward_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); - retry_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); - GNUNET_SERVER_add_handlers (server, plugin_handlers); - GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); -} - - -/** - * Shutdown client subsystem. - */ -void -GDS_CLIENTS_done () -{ - GNUNET_assert (client_head == NULL); - GNUNET_assert (client_tail == NULL); - if (NULL != retry_task) - { - GNUNET_SCHEDULER_cancel (retry_task); - retry_task = NULL; - } - if (NULL != retry_heap) - { - GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap)); - GNUNET_CONTAINER_heap_destroy (retry_heap); - retry_heap = NULL; - } - if (NULL != forward_map) - { - GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map)); - GNUNET_CONTAINER_multihashmap_destroy (forward_map); - forward_map = NULL; - } -} - -/* end of gnunet-service-wdht_clients.c */ diff --git a/src/dht/gnunet-service-wdht_neighbours.c b/src/dht/gnunet-service-wdht_neighbours.c deleted file mode 100644 index 0fe61cffe..000000000 --- a/src/dht/gnunet-service-wdht_neighbours.c +++ /dev/null @@ -1,1766 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009-2016 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -/** - * @file dht/gnunet-service-wdht_neighbours.c - * @brief GNUnet DHT service's finger and friend table management code - * @author Supriti Singh - * @author Christian Grothoff - * @author Arthur Dewarumez - * - * TODO: - * - initiate finding of successors - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_block_lib.h" -#include "gnunet_hello_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_ats_service.h" -#include "gnunet_core_service.h" -#include "gnunet_datacache_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_dht_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet-service-dht.h" -#include "gnunet-service-dht_datacache.h" -#include "gnunet-service-dht_neighbours.h" -#include "gnunet-service-dht_nse.h" -#include "dht.h" - -#define DEBUG(...) \ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) - -/** - * Trail timeout. After what time do trails always die? - */ -#define TRAIL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42) - -/** - * Random walk delay. How often do we walk the overlay? - */ -#define RANDOM_WALK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42) - -/** - * The number of layered ID to use. - */ -#define NUMBER_LAYERED_ID 8 - -/** - * The number of random walk to launch at the beginning of the initialization - */ -/* FIXME: find a better value */ -#define NUMBER_RANDOM_WALK 20 - - -/******************* The db structure and related functions *******************/ - -/** - * Entry in #friends_peermap. - */ -struct FriendInfo; - -/** - * - */ -struct FingerTable; - -/** - * Information we keep per trail. - */ -struct Trail -{ - - /** - * Identifier of the trail with the predecessor. - */ - struct GNUNET_HashCode pred_id; - - /** - * Identifier of the trail with the successor. - */ - struct GNUNET_HashCode succ_id; - - /** - * When does this trail expire. - */ - struct GNUNET_TIME_Absolute expiration_time; - - /** - * MDLL entry in the list of all trails with the same predecessor. - */ - struct Trail *prev_succ; - - /** - * MDLL entry in the list of all trails with the same predecessor. - */ - struct Trail *next_succ; - - /** - * MDLL entry in the list of all trails with the same predecessor. - */ - struct Trail *prev_pred; - - /** - * MDLL entry in the list of all trails with the same predecessor. - */ - struct Trail *next_pred; - - /** - * Our predecessor in the trail, NULL if we are initiator (?). - */ - struct FriendInfo *pred; - - /** - * Our successor in the trail, NULL if we are the last peer. - */ - struct FriendInfo *succ; - - /** - * Location of this trail in the heap. - */ - struct GNUNET_CONTAINER_HeapNode *hn; - - /** - * If this peer started the to create a Finger (and thus @e pred is - * NULL), this is the finger table of the finger we are trying to - * intialize. - */ - struct FingerTable *ft; - - /** - * If this peer started the trail to create a Finger (and thus @e - * pred is NULL), this is the offset of the finger we are trying to - * intialize in the unsorted array. - */ - unsigned int finger_off; - -}; - - -/** - * Entry in #friends_peermap. - */ -struct FriendInfo -{ - /** - * Friend Identity - */ - const struct GNUNET_PeerIdentity *id; - - /** - * - */ - struct Trail *pred_head; - - /** - * - */ - struct Trail *pred_tail; - - /** - * - */ - struct Trail *succ_head; - - /** - * - */ - struct Trail *succ_tail; - - /** - * Core handle for sending messages to this friend. - */ - struct GNUNET_MQ_Handle *mq; - -}; - - -/** - * - */ -struct Finger -{ - /** - * - */ - struct Trail *trail; - - /** - * - */ - struct FingerTable *ft; - - /** - * - */ - struct GNUNET_HashCode destination; - - /** - * #GNUNET_YES if a response has been received. Otherwise #GNUNET_NO. - */ - int valid; -}; - - -struct FingerTable -{ - /** - * Array of our fingers, unsorted. - */ - struct Finger **fingers; - - /** - * Size of the finger array. - */ - unsigned int finger_array_size; - - /** - * Number of valid entries in @e fingers - */ - unsigned int number_valid_fingers; - - /** - * Which offset in @e fingers will we redo next. - */ - unsigned int walk_offset; - - /** - * Is the finger array sorted? - */ - int is_sorted; - -}; - - -/*********************** end of the db structure part ***********************/ - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Setup a finger using the underlay topology ("social network"). - */ -struct RandomWalkMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK - */ - struct GNUNET_MessageHeader header; - - /** - * Number of hops this message has taken so far, we stop at - * log(NSE), in NBO. - */ - uint16_t hops_taken GNUNET_PACKED; - - /** - * Layer for the request, in NBO. - */ - uint16_t layer GNUNET_PACKED; - - /** - * Unique (random) identifier this peer will use to - * identify the trail (in future messages). - */ - struct GNUNET_HashCode trail_id; - -}; - -/** - * Response to a `struct RandomWalkMessage`. - */ -struct RandomWalkResponseMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE - */ - struct GNUNET_MessageHeader header; - - /** - * Zero, for alignment. - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Unique (random) identifier from the - * `struct RandomWalkMessage`. - */ - struct GNUNET_HashCode trail_id; - - /** - * Random location in the respective layer where the - * random path of the finger setup terminated. - */ - struct GNUNET_HashCode location; - -}; - -/** - * Response to an event that causes a trail to die. - */ -struct TrailDestroyMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY - */ - struct GNUNET_MessageHeader header; - - /** - * Zero, for alignment. - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Unique (random) identifier this peer will use to - * identify the finger (in future messages). - */ - struct GNUNET_HashCode trail_id; - -}; - - -/** - * Send a message along a trail. - */ -struct FindSuccessorMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND - */ - struct GNUNET_MessageHeader header; - - /** - * Zero, for alignment. - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Key for which we would like close values returned. - * identify the finger (in future messages). - */ - struct GNUNET_HashCode key; - -}; - - -/** - * Send a message along a trail. - */ -struct TrailRouteMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE - */ - struct GNUNET_MessageHeader header; - - /** - * #GNUNET_YES if the path should be recorded, #GNUNET_NO if not; in NBO. - */ - uint16_t record_path GNUNET_PACKED; - - /** - * Length of the recorded trail, 0 if @e record_path is #GNUNET_NO; in NBO. - */ - uint16_t path_length GNUNET_PACKED; - - /** - * Unique (random) identifier this peer will use to - * identify the finger (in future messages). - */ - struct GNUNET_HashCode trail_id; - - /** - * Path the message has taken so far (excluding sender). - */ - /* struct GNUNET_PeerIdentity path[path_length]; */ - - /* followed by payload (another `struct GNUNET_MessageHeader`) to - send along the trail */ -}; - - -/** - * P2P PUT message - */ -struct PeerPutMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_PUT - */ - struct GNUNET_MessageHeader header; - - /** - * Processing options - */ - uint32_t options GNUNET_PACKED; - - /** - * Content type. - */ - uint32_t block_type GNUNET_PACKED; - - /** - * Hop count - */ - uint32_t hop_count GNUNET_PACKED; - - /** - * Replication level for this message - * In the current implementation, this value is not used. - */ - uint32_t desired_replication_level GNUNET_PACKED; - - /** - * Length of the PUT path that follows (if tracked). - */ - uint32_t put_path_length GNUNET_PACKED; - - /** - * When does the content expire? - */ - struct GNUNET_TIME_AbsoluteNBO expiration_time; - - /** - * The key to store the value under. - */ - struct GNUNET_HashCode key GNUNET_PACKED; - - /* put path (if tracked) */ - - /* Payload */ - -}; - -/** - * P2P GET message - */ -struct PeerGetMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET - */ - struct GNUNET_MessageHeader header; - - /** - * Processing options - */ - uint32_t options GNUNET_PACKED; - - /** - * Desired content type. - */ - uint32_t block_type GNUNET_PACKED; - - /** - * Hop count - */ - uint32_t hop_count GNUNET_PACKED; - - /** - * Desired replication level for this request. - * In the current implementation, this value is not used. - */ - uint32_t desired_replication_level GNUNET_PACKED; - - /** - * Total number of peers in get path. - */ - unsigned int get_path_length; - - /** - * The key we are looking for. - */ - struct GNUNET_HashCode key; - - /* Get path. */ - /* struct GNUNET_PeerIdentity[]*/ -}; - - -/** - * P2P Result message - */ -struct PeerGetResultMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * The type for the data in NBO. - */ - uint32_t type GNUNET_PACKED; - - /** - * Number of peers recorded in the outgoing path from source to the - * stored location of this message. - */ - uint32_t put_path_length GNUNET_PACKED; - - /** - * When does the content expire? - */ - struct GNUNET_TIME_AbsoluteNBO expiration_time; - - /** - * The key of the corresponding GET request. - */ - struct GNUNET_HashCode key; - - /* put path (if tracked) */ - - /* Payload */ - -}; - -GNUNET_NETWORK_STRUCT_END - - -/** - * Contains all the layered IDs of this peer. - */ -struct GNUNET_PeerIdentity layered_id[NUMBER_LAYERED_ID]; - -/** - * Task to timeout trails that have expired. - */ -static struct GNUNET_SCHEDULER_Task *trail_timeout_task; - -/** - * Task to perform random walks. - */ -static struct GNUNET_SCHEDULER_Task *random_walk_task; - -/** - * Identity of this peer. - */ -static struct GNUNET_PeerIdentity my_identity; - -/** - * Peer map of all the friends of a peer - */ -static struct GNUNET_CONTAINER_MultiPeerMap *friends_peermap; - -/** - * Fingers per layer. - */ -static struct FingerTable fingers[NUMBER_LAYERED_ID]; - -/** - * Tail map, mapping tail identifiers to `struct Trail`s - */ -static struct GNUNET_CONTAINER_MultiHashMap *trail_map; - -/** - * Tail heap, organizing trails by expiration time. - */ -static struct GNUNET_CONTAINER_Heap *trail_heap; - -/** - * Handle to CORE. - */ -static struct GNUNET_CORE_Handle *core_api; - - -/** - * Handle the put request from the client. - * - * @param block_type Type of the block - * @param options routing options - * @param desired_replication_level desired replication level - * @param expiration_time when does the content expire - * @param hop_count how many hops has this message traversed so far - * @param bf Bloom filter of peers this PUT has already traversed - * @param key key for the content - * @param put_path_length number of entries in put_path - * @param put_path peers this request has traversed so far (if tracked) - * @param data payload to store - * @param data_size number of bytes in data - * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not - */ -int -GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type block_type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - struct GNUNET_TIME_Absolute expiration_time, - uint32_t hop_count, - struct GNUNET_CONTAINER_BloomFilter *bf, - const struct GNUNET_HashCode *key, - unsigned int put_path_length, - struct GNUNET_PeerIdentity *put_path, - const void *data, - size_t data_size) -{ - GDS_DATACACHE_handle_put (expiration_time, - key, - 0, NULL, - block_type, - data_size, - data); - GDS_CLIENTS_process_put (options, - block_type, - hop_count, - desired_replication_level, - put_path_length, put_path, - expiration_time, - key, - data, - data_size); - return GNUNET_OK; /* FIXME... */ -} - - -/** - * Perform a GET operation. Forwards the given request to other - * peers. Does not lookup the key locally. May do nothing if this is - * the only peer in the network (or if we are the closest peer in the - * network). - * - * @param type type of the block - * @param options routing options - * @param desired_replication_level desired replication count - * @param hop_count how many hops did this request traverse so far? - * @param key key for the content - * @param xquery extended query - * @param xquery_size number of bytes in @a xquery - * @param bg block group to filter duplicates - * @param peer_bf filter for peers not to select (again, updated) - * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not - */ -int -GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - uint32_t hop_count, - const struct GNUNET_HashCode *key, - const void *xquery, size_t xquery_size, - struct GNUNET_BLOCK_Group *bg, - struct GNUNET_CONTAINER_BloomFilter *peer_bf) -{ - // find closest finger(s) on all layers - // use TrailRoute with PeerGetMessage embedded to contact peer - // NOTE: actually more complicated, see paper! - GNUNET_break (0); // not implemented! - return GNUNET_SYSERR; -} - - -/** - * Delete a trail, it died (timeout, link failure, etc.). - * - * @param trail trail to delete from all data structures - * @param inform_pred should we notify the predecessor? - * @param inform_succ should we inform the successor? - */ -static void -delete_trail (struct Trail *trail, - int inform_pred, - int inform_succ) -{ - struct FriendInfo *friend; - struct GNUNET_MQ_Envelope *env; - struct TrailDestroyMessage *tdm; - struct Finger *finger; - - friend = trail->pred; - if (NULL != friend) - { - if (GNUNET_YES == inform_pred) - { - env = GNUNET_MQ_msg (tdm, - GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY); - tdm->trail_id = trail->pred_id; - GNUNET_MQ_send (friend->mq, - env); - } - GNUNET_CONTAINER_MDLL_remove (pred, - friend->pred_head, - friend->pred_tail, - trail); - } - friend = trail->succ; - if (NULL != friend) - { - if (GNUNET_YES == inform_succ) - { - env = GNUNET_MQ_msg (tdm, - GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY); - tdm->trail_id = trail->pred_id; - GNUNET_MQ_send (friend->mq, - env); - } - GNUNET_CONTAINER_MDLL_remove (succ, - friend->pred_head, - friend->pred_tail, - trail); - } - GNUNET_break (trail == - GNUNET_CONTAINER_heap_remove_node (trail->hn)); - finger = trail->ft->fingers[trail->finger_off]; - if (NULL != finger) - { - trail->ft->fingers[trail->finger_off] = NULL; - trail->ft->number_valid_fingers--; - GNUNET_free (finger); - } - GNUNET_free (trail); -} - - -/** - * Forward the given payload message along the trail. - * - * @param next_target which direction along the trail should we forward - * @param trail_id which trail should we forward along - * @param have_path do we track the forwarding path? - * @param predecessor which peer do we tack on to the path? - * @param path path the message has taken so far along the trail - * @param path_length number of entries in @a path - * @param payload payload of the message - */ -static void -forward_message_on_trail (struct FriendInfo *next_target, - const struct GNUNET_HashCode *trail_id, - int have_path, - const struct GNUNET_PeerIdentity *predecessor, - const struct GNUNET_PeerIdentity *path, - uint16_t path_length, - const struct GNUNET_MessageHeader *payload) -{ - struct GNUNET_MQ_Envelope *env; - struct TrailRouteMessage *trm; - struct GNUNET_PeerIdentity *new_path; - unsigned int plen; - uint16_t payload_len; - - payload_len = ntohs (payload->size); - if (have_path) - { - plen = path_length + 1; - if (plen >= (GNUNET_SERVER_MAX_MESSAGE_SIZE - - payload_len - - sizeof (struct TrailRouteMessage)) - / sizeof (struct GNUNET_PeerIdentity)) - { - /* Should really not have paths this long... */ - GNUNET_break_op (0); - plen = 0; - have_path = 0; - } - } - else - { - GNUNET_break_op (0 == path_length); - path_length = 0; - plen = 0; - } - env = GNUNET_MQ_msg_extra (trm, - payload_len + - plen * sizeof (struct GNUNET_PeerIdentity), - GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE); - trm->record_path = htons (have_path); - trm->path_length = htons (plen); - trm->trail_id = *trail_id; - new_path = (struct GNUNET_PeerIdentity *) &trm[1]; - if (have_path) - { - GNUNET_memcpy (new_path, - path, - path_length * sizeof (struct GNUNET_PeerIdentity)); - new_path[path_length] = *predecessor; - } - GNUNET_memcpy (&new_path[plen], - payload, - payload_len); - GNUNET_MQ_send (next_target->mq, - env); -} - - -/** - * Send the get result to requesting client. - * - * @param cls trail identifying where to send the result to, NULL for us - * @param options routing options (from GET request) - * @param key Key of the requested data. - * @param type Block type - * @param put_path_length Number of peers in @a put_path - * @param put_path Path taken to put the data at its stored location. - * @param expiration When will this result expire? - * @param data Payload to store - * @param data_size Size of the @a data - */ -void -GDS_NEIGHBOURS_send_get_result (void *cls, - enum GNUNET_DHT_RouteOption options, - const struct GNUNET_HashCode *key, - enum GNUNET_BLOCK_Type type, - unsigned int put_path_length, - const struct GNUNET_PeerIdentity *put_path, - struct GNUNET_TIME_Absolute expiration, - const void *data, - size_t data_size) -{ - const struct GNUNET_HashCode *trail_id = cls; - struct GNUNET_MessageHeader *payload; - struct Trail *trail; - - trail = GNUNET_CONTAINER_multihashmap_get (trail_map, - trail_id); - if (NULL == trail) - { - /* TODO: inform statistics */ - return; - } - if (NULL == trail->pred) - { - /* result is for *us* (local client) */ - GDS_CLIENTS_handle_reply (expiration, - key, - 0, NULL, - put_path_length, put_path, - type, - data_size, - data); - return; - } - - payload = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader) + data_size); - payload->size = data_size; - payload->type = GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT; - - forward_message_on_trail (trail->pred, - trail_id, - 0 != (options & GNUNET_DHT_RO_RECORD_ROUTE), - &my_identity, - NULL, 0, - payload); - GNUNET_free (payload); -} - - -/** - * Method called whenever a peer disconnects. - * - * @param cls closure - * @param peer peer identity this notification is about - * @param internal_cls our `struct FriendInfo` for @a peer - */ -static void -handle_core_disconnect (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *internal_cls) -{ - struct FriendInfo *remove_friend = internal_cls; - struct Trail *t; - - /* If disconnected to own identity, then return. */ - if (NULL == remove_friend) - return; - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (friends_peermap, - peer, - remove_friend)); - while (NULL != (t = remove_friend->succ_head)) - delete_trail (t, - GNUNET_YES, - GNUNET_NO); - while (NULL != (t = remove_friend->pred_head)) - delete_trail (t, - GNUNET_NO, - GNUNET_YES); - GNUNET_free (remove_friend); - if (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap)) - { - GNUNET_SCHEDULER_cancel (random_walk_task); - random_walk_task = NULL; - } -} - - -/** - * Function called with a random friend to be returned. - * - * @param cls a `struct FriendInfo **` with where to store the result - * @param peer the peer identity of the friend (ignored) - * @param value the `struct FriendInfo *` that was selected at random - * @return #GNUNET_OK (all good) - */ -static int -pick_random_helper (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *value) -{ - struct FriendInfo **fi = cls; - struct FriendInfo *v = value; - - *fi = v; - return GNUNET_OK; -} - - -/** - * Pick random friend from friends for random walk. - * - * @return NULL if we have no friends - */ -static struct FriendInfo * -pick_random_friend () -{ - struct FriendInfo *ret; - - ret = NULL; - if (0 == - GNUNET_CONTAINER_multipeermap_get_random (friends_peermap, - &pick_random_helper, - &ret)) - return NULL; - return ret; -} - - -/** - * One of our trails might have timed out, check and - * possibly initiate cleanup. - * - * @param cls NULL - */ -static void -trail_timeout_callback (void *cls) -{ - struct Trail *trail; - struct GNUNET_TIME_Relative left; - - trail_timeout_task = NULL; - while (NULL != (trail = GNUNET_CONTAINER_heap_peek (trail_heap))) - { - left = GNUNET_TIME_absolute_get_remaining (trail->expiration_time); - if (0 != left.rel_value_us) - break; - delete_trail (trail, - GNUNET_YES, - GNUNET_YES); - } - if (NULL != trail) - trail_timeout_task = GNUNET_SCHEDULER_add_delayed (left, - &trail_timeout_callback, - NULL); -} - - -/** - * Compute how big our finger arrays should be (at least). - * - * @return size of the finger array, never 0 - */ -static unsigned int -get_desired_finger_array_size () -{ - /* FIXME: This is just a stub... */ - return 64; -} - - -/** - * Initiate a random walk. - * - * @param cls NULL - */ -static void -do_random_walk (void *cls) -{ - static unsigned int walk_layer; - struct FriendInfo *friend; - struct GNUNET_MQ_Envelope *env; - struct RandomWalkMessage *rwm; - struct FingerTable *ft; - struct Finger *finger; - struct Trail *trail; - unsigned int nsize; - - random_walk_task = NULL; - friend = pick_random_friend (); - - trail = GNUNET_new (struct Trail); - /* We create the random walk so, no predecessor */ - trail->succ = friend; - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, - &trail->succ_id); - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (trail_map, - &trail->succ_id, - trail, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_break (0); - GNUNET_free (trail); - return; - } - GNUNET_CONTAINER_MDLL_insert (succ, - friend->succ_head, - friend->succ_tail, - trail); - trail->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT); - trail->hn = GNUNET_CONTAINER_heap_insert (trail_heap, - trail, - trail->expiration_time.abs_value_us); - if (NULL == trail_timeout_task) - trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT, - &trail_timeout_callback, - NULL); - env = GNUNET_MQ_msg (rwm, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK); - rwm->hops_taken = htonl (0); - rwm->trail_id = trail->succ_id; - GNUNET_MQ_send (friend->mq, - env); - /* clean up 'old' entry (implicitly via trail cleanup) */ - ft = &fingers[walk_layer]; - - if ( (NULL != ft->fingers) && - (NULL != (finger = ft->fingers[ft->walk_offset])) ) - delete_trail (finger->trail, - GNUNET_NO, - GNUNET_YES); - if (ft->finger_array_size < (nsize = get_desired_finger_array_size()) ) - GNUNET_array_grow (ft->fingers, - ft->finger_array_size, - nsize); - GNUNET_assert (NULL == ft->fingers[ft->walk_offset]); - trail->ft = ft; - trail->finger_off = ft->walk_offset; - finger = GNUNET_new (struct Finger); - finger->trail = trail; - finger->ft = ft; - ft->fingers[ft->walk_offset] = finger; - ft->is_sorted = GNUNET_NO; - ft->number_valid_fingers++; - ft->walk_offset = (ft->walk_offset + 1) % ft->finger_array_size; - - walk_layer = (walk_layer + 1) % NUMBER_LAYERED_ID; - random_walk_task = GNUNET_SCHEDULER_add_delayed (RANDOM_WALK_DELAY, - &do_random_walk, - NULL); -} - - -/** - * Method called whenever a peer connects. - * - * @param cls closure - * @param peer_identity peer identity this notification is about - * @param mq message queue for transmission to @a peer_identity - * @return the `struct FriendInfo` for the @a peer_identity, NULL for us - */ -static void * -handle_core_connect (void *cls, - const struct GNUNET_PeerIdentity *peer_identity, - struct GNUNET_MQ_Handle *mq) -{ - struct FriendInfo *friend; - - /* Check for connect to self message */ - if (0 == memcmp (&my_identity, - peer_identity, - sizeof (struct GNUNET_PeerIdentity))) - return NULL; - - friend = GNUNET_new (struct FriendInfo); - friend->id = peer_identity; - friend->mq = mq; - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (friends_peermap, - peer_identity, - friend, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - if (NULL == random_walk_task) - { - /* random walk needs to be started -- we have a first connection */ - random_walk_task = GNUNET_SCHEDULER_add_now (&do_random_walk, - NULL); - } - return friend; -} - - -/** - * To be called on core init/fail. - * - * @param cls service closure - * @param identity the public identity of this peer - */ -static void -core_init (void *cls, - const struct GNUNET_PeerIdentity *identity) -{ - my_identity = *identity; -} - - -/** - * Handle a `struct RandomWalkMessage` from a - * #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK message. - * - * @param cls the `struct FriendInfo` for the sender - * @param m the setup message - */ -static void -handle_dht_p2p_random_walk (void *cls, - const struct RandomWalkMessage *m) -{ - struct FriendInfo *pred = cls; - struct Trail *t; - uint16_t layer; - - layer = ntohs (m->layer); - if (layer > NUMBER_LAYERED_ID) - { - GNUNET_break_op (0); - return; - } - t = GNUNET_new (struct Trail); - t->pred_id = m->trail_id; - t->pred = pred; - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (trail_map, - &t->pred_id, - t, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_break_op (0); - GNUNET_free (t); - return; - } - GNUNET_CONTAINER_MDLL_insert (pred, - pred->pred_head, - pred->pred_tail, - t); - t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT); - t->hn = GNUNET_CONTAINER_heap_insert (trail_heap, - t, - t->expiration_time.abs_value_us); - if (NULL == trail_timeout_task) - trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT, - &trail_timeout_callback, - NULL); - - if (ntohl (m->hops_taken) > GDS_NSE_get ()) - { - /* We are the last hop, generate response */ - struct GNUNET_MQ_Envelope *env; - struct RandomWalkResponseMessage *rwrm; - - env = GNUNET_MQ_msg (rwrm, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE); - rwrm->reserved = htonl (0); - rwrm->trail_id = m->trail_id; - if (0 == layer) - (void) GDS_DATACACHE_get_random_key (&rwrm->location); - else - { - struct FingerTable *ft; - - ft = &fingers[layer-1]; - if (0 == ft->number_valid_fingers) - { - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, - &rwrm->location); - } - else - { - struct Finger *f; - unsigned int off; - unsigned int i; - - off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, - ft->number_valid_fingers); - for (i=0; (NULL == (f = ft->fingers[i])) || (off > 0); i++) - if (NULL != f) off--; - rwrm->location = f->destination; - } - } - GNUNET_MQ_send (pred->mq, - env); - } - else - { - struct GNUNET_MQ_Envelope *env; - struct RandomWalkMessage *rwm; - struct FriendInfo *succ; - - /* extend the trail by another random hop */ - succ = pick_random_friend (); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, - &t->succ_id); - t->succ = succ; - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (trail_map, - &t->succ_id, - t, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_break (0); - GNUNET_CONTAINER_MDLL_remove (pred, - pred->pred_head, - pred->pred_tail, - t); - GNUNET_free (t); - return; - } - GNUNET_CONTAINER_MDLL_insert (succ, - succ->succ_head, - succ->succ_tail, - t); - env = GNUNET_MQ_msg (rwm, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK); - rwm->hops_taken = htons (1 + ntohs (m->hops_taken)); - rwm->layer = m->layer; - rwm->trail_id = t->succ_id; - GNUNET_MQ_send (succ->mq, - env); - } -} - - -/** - * Handle a `struct RandomWalkResponseMessage`. - * - * @param cls closure - * @param rwrm the setup response message - */ -static void -handle_dht_p2p_random_walk_response (void *cls, - const struct RandomWalkResponseMessage *rwrm) -{ - struct Trail *trail; - struct FriendInfo *pred; - struct FingerTable *ft; - struct Finger *finger; - - trail = GNUNET_CONTAINER_multihashmap_get (trail_map, - &rwrm->trail_id); - if (NULL == trail) - { - /* TODO: log/statistics: we didn't find the trail (can happen) */ - return; - } - if (NULL != (pred = trail->pred)) - { - /* We are not the first hop, keep forwarding */ - struct GNUNET_MQ_Envelope *env; - struct RandomWalkResponseMessage *rwrm2; - - env = GNUNET_MQ_msg (rwrm2, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE); - rwrm2->reserved = htonl (0); - rwrm2->location = rwrm->location; - rwrm2->trail_id = trail->pred_id; - GNUNET_MQ_send (pred->mq, - env); - return; - } - /* We are the first hop, complete finger */ - if (NULL == (ft = trail->ft)) - { - /* Eh, why did we create the trail if we have no FT? */ - GNUNET_break (0); - delete_trail (trail, - GNUNET_NO, - GNUNET_YES); - return; - } - if (NULL == (finger = ft->fingers[trail->finger_off])) - { - /* Eh, finger got deleted, but why not the trail as well? */ - GNUNET_break (0); - delete_trail (trail, - GNUNET_NO, - GNUNET_YES); - return; - } - - - // 1) lookup trail => find Finger entry => fill in 'destination' and mark valid, move to end of sorted array, - //mark unsorted, update links from 'trails' - /* - * Steps : - * 1 check if we are the correct layer - * 1.a if true : add the returned value (finger) in the db structure - * 1.b if true : do nothing - */ - /* FIXME: add the value in db structure 1.a */ - -} - - -/** - * Handle a `struct TrailDestroyMessage`. - * - * @param cls closure - * @param tdm the trail destroy message - */ -static void -handle_dht_p2p_trail_destroy (void *cls, - const struct TrailDestroyMessage *tdm) -{ - struct FriendInfo *sender = cls; - struct Trail *trail; - - trail = GNUNET_CONTAINER_multihashmap_get (trail_map, - &tdm->trail_id); - delete_trail (trail, - ( (NULL != trail->succ) && - (0 == memcmp (sender->id, - &trail->succ->id, - sizeof (struct GNUNET_PeerIdentity))) ), - ( (NULL != trail->pred) && - (0 == memcmp (sender->id, - &trail->pred->id, - sizeof (struct GNUNET_PeerIdentity))) )); -} - - -/** - * Handle a `struct FindSuccessorMessage` from a #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND - * message. - * - * @param cls closure (NULL) - * @param trail_id path to the originator - * @param trail_path path the message took on the trail, if available - * @param trail_path_length number of entries on the @a trail_path - * @param message the finger setup message - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -handle_dht_p2p_successor_find (void *cls, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail_path, - unsigned int trail_path_length, - const struct GNUNET_MessageHeader *message) -{ - const struct FindSuccessorMessage *fsm; - - /* We do not expect to track trails for the forward-direction - of successor finding... */ - GNUNET_break_op (0 == trail_path_length); - fsm = (const struct FindSuccessorMessage *) message; - GDS_DATACACHE_get_successors (&fsm->key, - &GDS_NEIGHBOURS_send_get_result, - (void *) trail_id); - return GNUNET_OK; -} - - -/** - * Handle a `struct PeerGetMessage`. - * - * @param cls closure (NULL) - * @param trail_id path to the originator - * @param trail_path path the message took on the trail, if available - * @param trail_path_length number of entries on the @a trail_path - * @param message the peer get message - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -handle_dht_p2p_peer_get (void *cls, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail_path, - unsigned int trail_path_length, - const struct GNUNET_MessageHeader *message) -{ -#if 0 - const struct PeerGetMessage *pgm; - - // FIXME: note: never called like this, message embedded with trail route! - pgm = (const struct PeerGetMessage *) message; -#endif - // -> lookup in datacache (figure out way to remember trail!) - /* - * steps : - * 1 extract the result - * 2 save the peer - * 3 send it using the good trail - * - * What do i do when i don't have the key/value? - */ - - return GNUNET_OK; -} - - -/** - * Handle a `struct PeerGetResultMessage`. - * - * @param cls closure (NULL) - * @param trail_id path to the originator - * @param trail_path path the message took on the trail, if available - * @param trail_path_length number of entries on the @a trail_path - * @param message the peer get result message - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -handle_dht_p2p_peer_get_result (void *cls, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail_path, - unsigned int trail_path_length, - const struct GNUNET_MessageHeader *message) -{ -#if 0 - const struct PeerGetResultMessage *pgrm; - - pgrm = (const struct PeerGetResultMessage *) message; -#endif - // pretty much: parse, & pass to client (there is some call for that...) - -#if 0 - GDS_CLIENTS_process_get (options, - type, - 0, 0, - path_length, path, - key); - (void) GDS_DATACACHE_handle_get (trail_id, - key, - type, - xquery, - xquery_size, - &reply_bf, - reply_bf_mutator); -#endif - return GNUNET_OK; -} - - -/** - * Handle a `struct PeerPutMessage`. - * - * @param cls closure (NULL) - * @param trail_id path to the originator - * @param trail_path path the message took on the trail, if available - * @param trail_path_length number of entries on the @a trail_path - * @param message the peer put message - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -handle_dht_p2p_peer_put (void *cls, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail_path, - unsigned int trail_path_length, - const struct GNUNET_MessageHeader *message) -{ -#if 0 - const struct PeerGetResultMessage *pgrm; - - pgrm = (const struct PeerGetResultMessage *) message; -#endif - // parse & store in datacache, this is in response to us asking for successors. - /* - * steps : - * 1 check the size of the message - * 2 use the API to add the value in the "database". Check on the xdht file, how to do it. - * 3 Did i a have to return a notification or did i have to return GNUNET_[OK|SYSERR]? - */ -#if 0 - GDS_DATACACHE_handle_put (expiration_time, - key, - combined_path_length, combined_path, - block_type, - data_size, - data); - GDS_CLIENTS_process_put (options, - block_type, - 0, 0, - combined_path_length, combined_path, - expiration_time, - key, - data, - data_size); -#endif - return GNUNET_OK; -} - - -/** - * Handler for a message we received along some trail. - * - * @param cls closure - * @param trail_id trail identifier - * @param trail_path path the message took on the trail, if available - * @param trail_path_length number of entries on the @a trail_path - * @param message the message we got - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -typedef int -(*TrailHandlerCallback)(void *cls, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail_path, - unsigned int trail_path_length, - const struct GNUNET_MessageHeader *message); - - -/** - * Definition of a handler for a message received along some trail. - */ -struct TrailHandler -{ - /** - * NULL for end-of-list. - */ - TrailHandlerCallback callback; - - /** - * Closure for @e callback. - */ - void *cls; - - /** - * Message type this handler addresses. - */ - uint16_t message_type; - - /** - * Use 0 for variable-size. - */ - uint16_t message_size; -}; - - -/** - * Check that a `struct TrailRouteMessage` is well-formed. - * - * @param cls closure - * @param trm the finger destroy message - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -check_dht_p2p_trail_route (void *cls, - const struct TrailRouteMessage *trm) -{ - const struct GNUNET_PeerIdentity *path; - uint16_t path_length; - const struct GNUNET_MessageHeader *payload; - size_t msize; - - msize = ntohs (trm->header.size); - path_length = ntohs (trm->path_length); - if (msize < sizeof (struct TrailRouteMessage) + - path_length * sizeof (struct GNUNET_PeerIdentity) + - sizeof (struct GNUNET_MessageHeader) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - path = (const struct GNUNET_PeerIdentity *) &trm[1]; - payload = (const struct GNUNET_MessageHeader *) &path[path_length]; - if (msize != (ntohs (payload->size) + - sizeof (struct TrailRouteMessage) + - path_length * sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* FIXME: verify payload is OK!? */ - return GNUNET_OK; -} - - -/** - * Handle a `struct TrailRouteMessage`. - * - * @param cls closure - * @param trm the finger destroy message - */ -static void -handle_dht_p2p_trail_route (void *cls, - const struct TrailRouteMessage *trm) -{ - static const struct TrailHandler handlers[] = { - { &handle_dht_p2p_successor_find, NULL, - GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND, - sizeof (struct FindSuccessorMessage) }, - { &handle_dht_p2p_peer_get, NULL, - GNUNET_MESSAGE_TYPE_WDHT_GET, - 0 }, - { &handle_dht_p2p_peer_get_result, NULL, - GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT, - 0 }, - { &handle_dht_p2p_peer_put, NULL, - GNUNET_MESSAGE_TYPE_WDHT_PUT, - 0 }, - { NULL, NULL, 0, 0 } - }; - struct FriendInfo *sender = cls; - unsigned int i; - const struct GNUNET_PeerIdentity *path; - uint16_t path_length; - const struct GNUNET_MessageHeader *payload; - const struct TrailHandler *th; - struct Trail *trail; - - path_length = ntohs (trm->path_length); - path = (const struct GNUNET_PeerIdentity *) &trm[1]; - payload = (const struct GNUNET_MessageHeader *) &path[path_length]; - /* Is this message for us? */ - trail = GNUNET_CONTAINER_multihashmap_get (trail_map, - &trm->trail_id); - if ( (NULL != trail->pred) && - (0 == memcmp (sender->id, - &trail->pred->id, - sizeof (struct GNUNET_PeerIdentity))) ) - { - /* forward to 'successor' */ - if (NULL != trail->succ) - { - forward_message_on_trail (trail->succ, - &trail->succ_id, - ntohs (trm->record_path), - sender->id, - path, - path_length, - payload); - return; - } - } - else - { - /* forward to 'predecessor' */ - GNUNET_break_op ( (NULL != trail->succ) && - (0 == memcmp (sender->id, - &trail->succ->id, - sizeof (struct GNUNET_PeerIdentity))) ); - if (NULL != trail->pred) - { - forward_message_on_trail (trail->pred, - &trail->pred_id, - ntohs (trm->record_path), - sender->id, - path, - path_length, - payload); - return; - } - } - - /* Message is for us, dispatch to handler */ - th = NULL; - for (i=0; NULL != handlers[i].callback; i++) - { - th = &handlers[i]; - if (ntohs (payload->type) == th->message_type) - { - if ( (0 == th->message_size) || - (ntohs (payload->size) == th->message_size) ) - th->callback (th->cls, - &trm->trail_id, - path, - path_length, - payload); - else - GNUNET_break_op (0); - break; - } - } - GNUNET_break_op (NULL != th); -} - - -/** - * Initialize neighbours subsystem. - * - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -int -GDS_NEIGHBOURS_init (void) -{ - struct GNUNET_MQ_MessageHandler core_handlers[] = { - GNUNET_MQ_hd_fixed_size (dht_p2p_random_walk, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK, - struct RandomWalkMessage, - NULL), - GNUNET_MQ_hd_fixed_size (dht_p2p_random_walk_response, - GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE, - struct RandomWalkResponseMessage, - NULL), - GNUNET_MQ_hd_fixed_size (dht_p2p_trail_destroy, - GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY, - struct TrailDestroyMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_trail_route, - GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE, - struct TrailRouteMessage, - NULL), - GNUNET_MQ_handler_end () - }; - - core_api = GNUNET_CORE_connect (GDS_cfg, NULL, - &core_init, - &handle_core_connect, - &handle_core_disconnect, - core_handlers); - if (NULL == core_api) - return GNUNET_SYSERR; - friends_peermap = GNUNET_CONTAINER_multipeermap_create (256, - GNUNET_NO); - trail_map = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - trail_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); - return GNUNET_OK; -} - - -/** - * Shutdown neighbours subsystem. - */ -void -GDS_NEIGHBOURS_done (void) -{ - if (NULL == core_api) - return; - GNUNET_CORE_disconnect (core_api); - core_api = NULL; - GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap)); - GNUNET_CONTAINER_multipeermap_destroy (friends_peermap); - friends_peermap = NULL; - GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (trail_map)); - GNUNET_CONTAINER_multihashmap_destroy (trail_map); - trail_map = NULL; - GNUNET_CONTAINER_heap_destroy (trail_heap); - trail_heap = NULL; - if (NULL != trail_timeout_task) - { - GNUNET_SCHEDULER_cancel (trail_timeout_task); - trail_timeout_task = NULL; - } -} - - -/** - * Get my identity - * - * @return my identity - */ -struct GNUNET_PeerIdentity * -GDS_NEIGHBOURS_get_id (void) -{ - return &my_identity; -} - -/* end of gnunet-service-wdht_neighbours.c */ diff --git a/src/dht/gnunet-service-xdht.c b/src/dht/gnunet-service-xdht.c deleted file mode 100644 index 7d0cb8a3a..000000000 --- a/src/dht/gnunet-service-xdht.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009, 2010, 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -/** - * @file dht/gnunet-service-xdht.c - * @brief GNUnet DHT service - * @author Christian Grothoff - * @author Nathan Evans - */ -#include "platform.h" -#include "gnunet_block_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_hello_lib.h" -#include "gnunet_dht_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet-service-dht.h" -#include "gnunet-service-dht_datacache.h" -#include "gnunet-service-dht_neighbours.h" -#include "gnunet-service-dht_nse.h" -#include "gnunet-service-xdht_routing.h" - - -/** - * Should we store our topology predecessor and successor IDs into statistics? - */ -extern unsigned int track_topology; - - -/* Code shared between different DHT implementations */ -#include "gnunet-service-dht_clients.c" - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GDS_NEIGHBOURS_done (); - GDS_DATACACHE_done (); - GDS_ROUTING_done (); - GDS_NSE_done (); - if (NULL != GDS_block_context) - { - GNUNET_BLOCK_context_destroy (GDS_block_context); - GDS_block_context = NULL; - } - if (NULL != GDS_stats) - { - GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES); - GDS_stats = NULL; - } - GDS_CLIENTS_stop (); -} - - -/** - * Process dht requests. - * - * @param cls closure - * @param c configuration to use - * @param service the initialized service - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *service) -{ - unsigned long long _track_topology; - - GDS_cfg = c; - GDS_service = service; - GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg); - GDS_stats = GNUNET_STATISTICS_create ("dht", - GDS_cfg); - GDS_ROUTING_init (); - GDS_NSE_init (); - GDS_DATACACHE_init (); - GDS_CLIENTS_init (); - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_number (c, - "xdht", - "track_toplogy", - &_track_topology)) - { - track_topology = (unsigned int) _track_topology; - } - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, - NULL); - if (GNUNET_OK != GDS_NEIGHBOURS_init ()) - { - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/* Finally, define the main method */ -GDS_DHT_SERVICE_INIT("xdht", &run); - - -/* end of gnunet-service-xdht.c */ diff --git a/src/dht/gnunet-service-xdht.h b/src/dht/gnunet-service-xdht.h deleted file mode 100644 index 5a8e2e21d..000000000 --- a/src/dht/gnunet-service-xdht.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht.h - * @brief GNUnet DHT globals - * @author Christian Grothoff - */ -#ifndef GNUNET_SERVICE_XDHT_H -#define GNUNET_SERVICE_XDHT_H - -#include "gnunet_util_lib.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" - -#define DEBUG_DHT GNUNET_EXTRA_LOGGING - -/** - * Configuration we use. - */ -extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; - -/** - * Our handle to the BLOCK library. - */ -extern struct GNUNET_BLOCK_Context *GDS_block_context; - -/** - * Handle for the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *GDS_stats; - -#endif diff --git a/src/dht/gnunet-service-xdht_hello.c b/src/dht/gnunet-service-xdht_hello.c deleted file mode 100644 index ceaf6f853..000000000 --- a/src/dht/gnunet-service-xdht_hello.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_hello.c - * @brief GNUnet DHT integration with peerinfo - * @author Christian Grothoff - * - * TODO: - * - consider adding mechanism to remove expired HELLOs - */ -#include "platform.h" -#include "gnunet-service-xdht.h" -#include "gnunet-service-xdht_hello.h" -#include "gnunet_peerinfo_service.h" - - -/** - * Handle for peerinfo notifications. - */ -static struct GNUNET_PEERINFO_NotifyContext *pnc; - -/** - * Hash map of peers to HELLOs. - */ -static struct GNUNET_CONTAINER_MultiPeerMap *peer_to_hello; - - -/** - * Obtain a peer's HELLO if available - * - * @param peer peer to look for a HELLO from - * @return HELLO for the given peer - */ -const struct GNUNET_HELLO_Message * -GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer) -{ - if (NULL == peer_to_hello) - return NULL; - return GNUNET_CONTAINER_multipeermap_get (peer_to_hello, peer); -} - - -/** - * Function called for each HELLO known to PEERINFO. - * - * @param cls closure - * @param peer id of the peer, NULL for last call - * @param hello hello message for the peer (can be NULL) - * @param err_msg error message (not used) - */ -static void -process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, const char *err_msg) -{ - struct GNUNET_TIME_Absolute ex; - struct GNUNET_HELLO_Message *hm; - - if (hello == NULL) - return; - ex = GNUNET_HELLO_get_last_expiration (hello); - if (0 == GNUNET_TIME_absolute_get_remaining (ex).rel_value_us) - return; - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# HELLOs obtained from peerinfo"), 1, - GNUNET_NO); - hm = GNUNET_CONTAINER_multipeermap_get (peer_to_hello, peer); - GNUNET_free_non_null (hm); - hm = GNUNET_malloc (GNUNET_HELLO_size (hello)); - GNUNET_memcpy (hm, hello, GNUNET_HELLO_size (hello)); - GNUNET_assert (GNUNET_SYSERR != - GNUNET_CONTAINER_multipeermap_put (peer_to_hello, - peer, hm, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); -} - - -/** - * Initialize HELLO subsystem. - */ -void -GDS_HELLO_init () -{ - pnc = GNUNET_PEERINFO_notify (GDS_cfg, GNUNET_NO, &process_hello, NULL); - peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO); -} - - -/** - * Free memory occopied by the HELLO. - */ -static int -free_hello (void *cls, - const struct GNUNET_PeerIdentity *key, - void *hello) -{ - GNUNET_free (hello); - return GNUNET_OK; -} - - -/** - * Shutdown HELLO subsystem. - */ -void -GDS_HELLO_done () -{ - if (NULL != pnc) - { - GNUNET_PEERINFO_notify_cancel (pnc); - pnc = NULL; - } - if (NULL != peer_to_hello) - { - GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello, &free_hello, NULL); - GNUNET_CONTAINER_multipeermap_destroy (peer_to_hello); - } -} - -/* end of gnunet-service-dht_hello.c */ diff --git a/src/dht/gnunet-service-xdht_hello.h b/src/dht/gnunet-service-xdht_hello.h deleted file mode 100644 index 7e7a79bcf..000000000 --- a/src/dht/gnunet-service-xdht_hello.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_hello.h - * @brief GNUnet DHT integration with peerinfo - * @author Christian Grothoff - */ -#ifndef GNUNET_SERVICE_XDHT_HELLO_H -#define GNUNET_SERVICE_XDHT_HELLO_H - -#include "gnunet_util_lib.h" -#include "gnunet_hello_lib.h" - -/** - * Obtain a peer's HELLO if available - * - * @param peer peer to look for a HELLO from - * @return HELLO for the given peer - */ -const struct GNUNET_HELLO_Message * -GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer); - - -/** - * Initialize HELLO subsystem. - */ -void -GDS_HELLO_init (void); - - -/** - * Shutdown HELLO subsystem. - */ -void -GDS_HELLO_done (void); - -#endif diff --git a/src/dht/gnunet-service-xdht_neighbours.c b/src/dht/gnunet-service-xdht_neighbours.c deleted file mode 100644 index dd45d5a4b..000000000 --- a/src/dht/gnunet-service-xdht_neighbours.c +++ /dev/null @@ -1,6261 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009-2014, 2016 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_neighbours.c - * @brief GNUnet DHT service's finger and friend table management code - * @author Supriti Singh - * @author Christian Grothoff - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_block_lib.h" -#include "gnunet_hello_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_ats_service.h" -#include "gnunet_core_service.h" -#include "gnunet_datacache_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_dht_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet-service-dht.h" -#include "gnunet-service-dht_datacache.h" -#include "gnunet-service-dht_neighbours.h" -#include "gnunet-service-xdht_routing.h" -#include "dht.h" - -/** - * TODO: - * 1. In X-Vine paper, there is no policy defined for replicating the data to - * recover in case of peer failure. We can do it in Chord way. In R5N, the key - * is hashed and then data is stored according to the key value generated after - * hashing. - */ - -#define DEBUG(...) \ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) - -/** - * Maximum possible fingers (including predecessor) of a peer - */ -#define MAX_FINGERS 65 - -/** - * Maximum allowed number of pending messages per friend peer. - */ -#define MAXIMUM_PENDING_PER_FRIEND 64 - -/** - * How long to wait before sending another find finger trail request - */ -#define DHT_FIND_FINGER_TRAIL_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) - -/** - * How long to wait before sending another verify successor message. - */ -#define DHT_SEND_VERIFY_SUCCESSOR_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) - -/** - * How long to wait before sending another verify successor message. - */ -#define DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -/** - * How long to wait before retrying notify successor. - */ -#define DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -/** - * How long at most to wait for transmission of a request to a friend ? - */ -#define PENDING_MESSAGE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) - -/** - * Duration for which I may remain congested. - * Note: Its a static value. In future, a peer may do some analysis and calculate - * congestion_timeout based on 'some' parameters. - */ -#define CONGESTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) - -/** - * In case we don't hear back from the current successor, then we can start - * verify successor. - */ -#define WAIT_NOTIFY_CONFIRMATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 200) - -/** - * Maximum number of trails allowed to go through a friend. - */ -#define TRAILS_THROUGH_FRIEND_THRESHOLD 64 - -/** - * Maximum number of trails stored per finger. - */ -#define MAXIMUM_TRAILS_PER_FINGER 4 - -/** - * Finger map index for predecessor entry in finger table. - */ -#define PREDECESSOR_FINGER_ID 64 - -/** - * FIXME: Its use only at 3 places check if you can remove it. - * To check if a finger is predecessor or not. - */ -enum GDS_NEIGHBOURS_finger_type -{ - GDS_FINGER_TYPE_PREDECESSOR = 1, - GDS_FINGER_TYPE_NON_PREDECESSOR = 0 -}; - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * P2P PUT message - */ -struct PeerPutMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT - */ - struct GNUNET_MessageHeader header; - - /** - * Processing options - */ - uint32_t options GNUNET_PACKED; - - /** - * Content type. - */ - uint32_t block_type GNUNET_PACKED; - - /** - * Hop count - */ - uint32_t hop_count GNUNET_PACKED; - - /** - * Replication level for this message - * In the current implementation, this value is not used. - */ - uint32_t desired_replication_level GNUNET_PACKED; - - /** - * Length of the PUT path that follows (if tracked). - */ - uint32_t put_path_length GNUNET_PACKED; - - /** - * Best known destination (could be my friend or finger) which should - * get this message next. - */ - struct GNUNET_PeerIdentity best_known_destination; - - /** - * In case best_known_destination is a finger, then trail to reach - * to that finger. Else its default value is 0. - */ - struct GNUNET_HashCode intermediate_trail_id; - - /** - * When does the content expire? - */ - struct GNUNET_TIME_AbsoluteNBO expiration_time; - - /** - * The key to store the value under. - */ - struct GNUNET_HashCode key GNUNET_PACKED; - - /* put path (if tracked) */ - - /* Payload */ - -}; - -/** - * P2P GET message - */ -struct PeerGetMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_GET - */ - struct GNUNET_MessageHeader header; - - /** - * Processing options - */ - uint32_t options GNUNET_PACKED; - - /** - * Desired content type. - */ - uint32_t block_type GNUNET_PACKED; - - /** - * Hop count - */ - uint32_t hop_count GNUNET_PACKED; - - /** - * Desired replication level for this request. - * In the current implementation, this value is not used. - */ - uint32_t desired_replication_level GNUNET_PACKED; - - /** - * Total number of peers in get path. - */ - unsigned int get_path_length; - - /** - * Best known destination (could be my friend or finger) which should - * get this message next. - */ - struct GNUNET_PeerIdentity best_known_destination; - - /** - * In case best_known_destination is a finger, then trail to reach - * to that finger. Else its default value is 0. - */ - struct GNUNET_HashCode intermediate_trail_id; - - /** - * The key we are looking for. - */ - struct GNUNET_HashCode key; - - /* Get path. */ - /* struct GNUNET_PeerIdentity[]*/ -}; - -/** - * P2P Result message - */ -struct PeerGetResultMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * The type for the data. - */ - uint32_t type GNUNET_PACKED; - - /** - * Number of peers recorded in the outgoing path from source to the - * stored location of this message. - */ - uint32_t put_path_length GNUNET_PACKED; - - /** - * Length of the GET path that follows (if tracked). - */ - uint32_t get_path_length GNUNET_PACKED; - - /** - * Peer which queried for get and should get the result. - */ - struct GNUNET_PeerIdentity querying_peer; - - /** - * When does the content expire? - */ - struct GNUNET_TIME_AbsoluteNBO expiration_time; - - /** - * The key of the corresponding GET request. - */ - struct GNUNET_HashCode key; - - /* put path (if tracked) */ - - /* get path (if tracked) */ - - /* Payload */ - -}; - -/** - * P2P Trail setup message - */ -struct PeerTrailSetupMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP - */ - struct GNUNET_MessageHeader header; - - /** - * Is source_peer trying to setup the trail to a predecessor or any finger. - */ - uint32_t is_predecessor; - - /** - * Peer closest to this value will be our finger. - */ - uint64_t final_destination_finger_value; - - /** - * Source peer which wants to setup the trail to one of its finger. - */ - struct GNUNET_PeerIdentity source_peer; - - /** - * Best known destination (could be my friend or finger) which should - * get this message next. - * - * FIXME: this could be removed if we include trail_source / trail_dest - * in the routing table. This way we save 32 bytes of bandwidth by using - * extra 8 bytes of memory (2 * sizeof (GNUNET_PEER_ID)) - */ - struct GNUNET_PeerIdentity best_known_destination; - - /** - * In case best_known_destination is a finger, then trail id of trail to - * reach to this finger. - */ - struct GNUNET_HashCode intermediate_trail_id; - - /** - * Trail id for trail which we are trying to setup. - */ - struct GNUNET_HashCode trail_id; - - /* List of peers which are part of trail setup so far. - * Trail does NOT include source_peer and peer which will be closest to - * ultimate_destination_finger_value. - * struct GNUNET_PeerIdentity trail[] - */ -}; - -/** - * P2P Trail Setup Result message - */ -struct PeerTrailSetupResultMessage -{ - - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * Finger to which we have found the path. - */ - struct GNUNET_PeerIdentity finger_identity; - - /** - * Peer which started trail_setup to find trail to finger_identity - */ - struct GNUNET_PeerIdentity querying_peer; - - /** - * Is the trail setup to querying_peer's predecessor or finger? - */ - uint32_t is_predecessor; - - /** - * Value to which finger_identity is the closest peer. - */ - uint64_t ultimate_destination_finger_value; - - /** - * Identifier of the trail from querying peer to finger_identity, NOT - * including both endpoints. - */ - struct GNUNET_HashCode trail_id; - - /* List of peers which are part of the trail from querying peer to - * finger_identity, NOT including both endpoints. - * struct GNUNET_PeerIdentity trail[] - */ -}; - -/** - * P2P Verify Successor Message. - */ -struct PeerVerifySuccessorMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR - */ - struct GNUNET_MessageHeader header; - - /** - * Peer which wants to verify its successor. - */ - struct GNUNET_PeerIdentity source_peer; - - /** - * Source Peer's current successor. - */ - struct GNUNET_PeerIdentity successor; - - /** - * Identifier of trail to reach from source_peer to successor. - */ - struct GNUNET_HashCode trail_id; - - /* List of the peers which are part of trail to reach from source_peer - * to successor, NOT including them - * struct GNUNET_PeerIdentity trail[] - */ -}; - -/** - * P2P Verify Successor Result Message - */ -struct PeerVerifySuccessorResultMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * Peer which sent the request to verify its successor. - */ - struct GNUNET_PeerIdentity querying_peer; - - /** - * Successor to which PeerVerifySuccessorMessage was sent. - */ - struct GNUNET_PeerIdentity current_successor; - - /** - * Current Predecessor of source_successor. It can be same as querying peer - * or different. In case it is different then it can be querying_peer's - * probable successor. - */ - struct GNUNET_PeerIdentity probable_successor; - - /** - * Trail identifier of trail from querying_peer to current_successor. - */ - struct GNUNET_HashCode trail_id; - - /** - * Direction in which we are looking at the trail. - */ - uint32_t trail_direction; - - /* In case probable_successor != querying_peer, then trail to reach from - * querying_peer to probable_successor, NOT including end points. - * struct GNUNET_PeerIdentity trail[] - */ -}; - -/** - * P2P Notify New Successor Message. - */ -struct PeerNotifyNewSuccessorMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR - */ - struct GNUNET_MessageHeader header; - - /** - * Peer which wants to notify its new successor. - */ - struct GNUNET_PeerIdentity source_peer; - - /** - * New successor of source_peer. - */ - struct GNUNET_PeerIdentity new_successor; - - /** - * Unique identifier of the trail from source_peer to new_successor, - * NOT including the endpoints. - */ - struct GNUNET_HashCode trail_id; - - /* List of peers in trail from source_peer to new_successor, - * NOT including the endpoints. - * struct GNUNET_PeerIdentity trail[] - */ -}; - -/** - * P2P Notify Successor Confirmation message. - */ -struct PeerNotifyConfirmationMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier of the trail. - */ - struct GNUNET_HashCode trail_id; - - /** - * Direction of trail. - */ - uint32_t trail_direction; -}; - - -/** - * P2P Trail Tear Down message. - */ -struct PeerTrailTearDownMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier of the trail. - */ - struct GNUNET_HashCode trail_id; - - /** - * Direction of trail. - */ - uint32_t trail_direction; -}; - - -/** - * P2P Trail Rejection Message. - */ -struct PeerTrailRejectionMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION - */ - struct GNUNET_MessageHeader header; - - /** - * Peer which wants to set up the trail. - */ - struct GNUNET_PeerIdentity source_peer; - - /** - * Peer which sent trail rejection message as it it congested. - */ - struct GNUNET_PeerIdentity congested_peer; - - /** - * Peer identity closest to this value will be finger of - * source_peer. - */ - uint64_t ultimate_destination_finger_value; - - /** - * Is source_peer trying to setup the trail to its predecessor or finger. - */ - uint32_t is_predecessor; - - /** - * Identifier for the trail that source peer is trying to setup. - */ - struct GNUNET_HashCode trail_id; - - /** - * Relative time for which congested_peer will remain congested. - */ - struct GNUNET_TIME_Relative congestion_time; - - /* Trail_list from source_peer to peer which sent the message for trail setup - * to congested peer. This trail does NOT include source_peer. - struct GNUNET_PeerIdnetity trail[]*/ -}; - -/** - * P2P Add Trail Message. - */ -struct PeerAddTrailMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL - */ - struct GNUNET_MessageHeader header; - - /** - * Source of the routing trail. - */ - struct GNUNET_PeerIdentity source_peer; - - /** - * Destination of the routing trail. - */ - struct GNUNET_PeerIdentity destination_peer; - - /** - * Unique identifier of the trail from source_peer to destination_peer, - * NOT including the endpoints. - */ - struct GNUNET_HashCode trail_id; - - /* Trail from source peer to destination peer, NOT including them. - * struct GNUNET_PeerIdentity trail[] - */ -}; - - -GNUNET_NETWORK_STRUCT_END - - -/** - * Entry in friend_peermap. - */ -struct FriendInfo -{ - /** - * Friend Identity - */ - const struct GNUNET_PeerIdentity *id; - - /** - * Number of trails for which this friend is the first hop or if the friend - * is finger. - */ - unsigned int trails_count; - - /** - * In case not 0, then amount of time for which this friend is congested. - */ - struct GNUNET_TIME_Absolute congestion_timestamp; - - /** - * Handle for sending messages to this friend. - */ - struct GNUNET_MQ_Handle *mq; - -}; - -/** - * An individual element of the trail to reach to a finger. - */ -struct Trail_Element -{ - /** - * Pointer to next item in the list - */ - struct Trail_Element *next; - - /** - * Pointer to prev item in the list - */ - struct Trail_Element *prev; - - /** - * An element in this trail. - */ - struct GNUNET_PeerIdentity peer; -}; - -/** - * Information about an individual trail. - */ -struct Trail -{ - /** - * Head of trail. - */ - struct Trail_Element *trail_head; - - /** - * Tail of trail. - */ - struct Trail_Element *trail_tail; - - /** - * Unique identifier of this trail. - */ - struct GNUNET_HashCode trail_id; - - /** - * Length of trail pointed - */ - unsigned int trail_length; - - /** - * Is there a valid trail entry. - */ - unsigned int is_present; -}; - -/** - * An entry in finger_table - */ -struct FingerInfo -{ - /** - * Finger identity. - */ - struct GNUNET_PeerIdentity finger_identity; - - /** - * In case not 0, this amount is time to wait for notify successor message. - * Used ONLY for successor. NOT for any other finger. - */ - struct GNUNET_TIME_Absolute wait_notify_confirmation; - - /** - * Is any finger stored at this finger index. - */ - unsigned int is_present; - - /** - * Index in finger peer map - */ - uint32_t finger_table_index; - - /** - * Number of trails setup so far for this finger. - * Should not cross MAXIMUM_TRAILS_PER_FINGER. - */ - uint32_t trails_count; - - /** - * Array of trails to reach to this finger. - */ - struct Trail trail_list[MAXIMUM_TRAILS_PER_FINGER]; -}; - - -/** - * Stores information about the peer which is closest to destination_finger_value. - * 'closest' can be either successor or predecessor depending on is_predecessor - * flag. - */ -struct Closest_Peer -{ - /** - * Destination finger value. - */ - uint64_t destination_finger_value; - - /** - * Is finger_value a predecessor or any other finger. - */ - unsigned int is_predecessor; - - /** - * Trail id to reach to peer. - * In case peer is my identity or friend, it is set to 0. - */ - struct GNUNET_HashCode trail_id; - - /** - * Next destination. In case of friend and my_identity , it is same as next_hop - * In case of finger it is finger identity. - */ - struct GNUNET_PeerIdentity best_known_destination; - - /** - * In case best_known_destination is a finger, then first friend in the trail - * to reach to it. In other case, same as best_known_destination. - */ - struct GNUNET_PeerIdentity next_hop; - - /** - * In case finger is the next hop, it contains a valid finger table index - * at which the finger is stored. Else, It contains 65, which is out of range - * of finger table index. - */ - unsigned int finger_table_index; -}; - -/** - * Context for send_verify_successor_task. - */ -struct VerifySuccessorContext -{ - /** - * Number of times this has been scheduled. - */ - unsigned int num_retries_scheduled; -}; - -/** - * Task that sends FIND FINGER TRAIL requests. This task is started when we have - * get our first friend. - */ -static struct GNUNET_SCHEDULER_Task *find_finger_trail_task; - -/** - * Task that sends verify successor message. This task is started when we get - * our successor for the first time. - */ -static struct GNUNET_SCHEDULER_Task *send_verify_successor_task; - -/** - * Task that sends verify successor message. This task is started when we get - * our successor for the first time. - */ -static struct GNUNET_SCHEDULER_Task *send_verify_successor_retry_task; - -/** - * Task that sends verify successor message. This task is started when we get - * our successor for the first time. - */ -static struct GNUNET_SCHEDULER_Task *send_notify_new_successor_retry_task; - -/** - * Identity of this peer. - */ -static struct GNUNET_PeerIdentity my_identity; - -/** - * Peer map of all the friends of a peer - */ -static struct GNUNET_CONTAINER_MultiPeerMap *friend_peermap; - -/** - * Array of all the fingers. - */ -static struct FingerInfo finger_table [MAX_FINGERS]; - -/** - * Handle to CORE. - */ -static struct GNUNET_CORE_Handle *core_api; - -/** - * The current finger index that we have want to find trail to. We start the - * search with value = 0, i.e. successor and then go to PREDCESSOR_FINGER_ID - * and decrement it. For any index 63 <= index < 0, if finger is same as successor, - * we reset this index to 0. - */ -static unsigned int current_search_finger_index; - -/** - * Time duration to schedule find finger trail task. - */ -static struct GNUNET_TIME_Relative find_finger_trail_task_next_send_time; - -/** - * Time duration to schedule verify successor task. - */ -static struct GNUNET_TIME_Relative verify_successor_next_send_time; - -/** - * Time duration to send verify successor again, if result was not received in time. - */ -static struct GNUNET_TIME_Relative verify_successor_retry_time; - -/** - * Time duration to retry send_notify_successor. - */ -static struct GNUNET_TIME_Relative notify_successor_retry_time; - -/** - * Are we waiting for confirmation from our new successor that it got the - * message - */ -//static unsigned int waiting_for_notify_confirmation; - -/* Below variables are used only for testing, and statistics collection. */ -/** - * Should we store our topology predecessor and successor IDs into statistics? - */ -unsigned int track_topology; - -/** - * Count of fingers found. Ideally we should have O(logn) fingers for a - * stable network. - */ -static unsigned int total_fingers_found; - -/** - * Number of times we found the same successor. - */ -static unsigned int successor_times; - -/** - * Number of rounds for which we should search for finger. - */ -static unsigned int fingers_round_count; - - -/** - * Construct a trail setup message and forward it to @a target_friend - * - * @param source_peer Peer which wants to setup the trail - * @param ultimate_destination_finger_value Peer identity closest to this value - * will be finger to @a source_peer - * @param best_known_destination Best known destination (could be finger or friend) - * which should get this message. In case it is - * friend, then it is same as target_friend - * @param target_friend Friend to which message is forwarded now. - * @param trail_length Total number of peers in trail setup so far. - * @param trail_peer_list Trail setup so far - * @param is_predecessor Is @a source_peer looking for trail to a predecessor or not. - * @param trail_id Unique identifier for the trail we are trying to setup. - * @param intermediate_trail_id Trail id of intermediate trail to reach to - * best_known_destination when its a finger. If not - * used then set to 0. - */ -static void -GDS_NEIGHBOURS_send_trail_setup (const struct GNUNET_PeerIdentity *source_peer, - uint64_t ultimate_destination_finger_value, - const struct GNUNET_PeerIdentity *best_known_destination, - const struct FriendInfo *target_friend, - unsigned int trail_length, - const struct GNUNET_PeerIdentity *trail_peer_list, - unsigned int is_predecessor, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_HashCode *intermediate_trail_id) -{ - struct GNUNET_MQ_Envelope *env; - struct PeerTrailSetupMessage *tsm; - size_t msize; - - msize = trail_length * sizeof (struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerTrailSetupMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (tsm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP); - tsm->final_destination_finger_value = GNUNET_htonll (ultimate_destination_finger_value); - tsm->source_peer = *source_peer; - tsm->best_known_destination = *best_known_destination; - tsm->is_predecessor = htonl (is_predecessor); - tsm->trail_id = *trail_id; - tsm->intermediate_trail_id = *intermediate_trail_id; - GNUNET_memcpy (&tsm[1], - trail_peer_list, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Construct a trail setup result message and forward it to @a target_friend. - * - * @param querying_peer Peer which sent the trail setup request and should get - * the result back. - * @param Finger Peer to which the trail has been setup to. - * @param target_friend Friend to which this message should be forwarded. - * @param trail_length Numbers of peers in the trail. - * @param trail_peer_list Peers which are part of the trail from - * querying_peer to Finger, NOT including them. - * @param is_predecessor Is @a Finger predecessor to @a querying_peer ? - * @param ultimate_destination_finger_value Value to which @a finger is the closest - * peer. - * @param trail_id Unique identifier of the trail. - */ -static void -GDS_NEIGHBOURS_send_trail_setup_result (const struct GNUNET_PeerIdentity *querying_peer, - const struct GNUNET_PeerIdentity *finger, - struct FriendInfo *target_friend, - unsigned int trail_length, - const struct GNUNET_PeerIdentity *trail_peer_list, - unsigned int is_predecessor, - uint64_t ultimate_destination_finger_value, - const struct GNUNET_HashCode *trail_id) -{ - struct GNUNET_MQ_Envelope *env; - struct PeerTrailSetupResultMessage *tsrm; - size_t msize; - - msize = trail_length * sizeof (struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerTrailSetupResultMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (tsrm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT); - tsrm->querying_peer = *querying_peer; - tsrm->finger_identity = *finger; - tsrm->is_predecessor = htonl (is_predecessor); - tsrm->trail_id = *trail_id; - tsrm->ultimate_destination_finger_value - = GNUNET_htonll (ultimate_destination_finger_value); - GNUNET_memcpy (&tsrm[1], - trail_peer_list, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Send notify successor confirmation message. - * - * @param trail_id Unique Identifier of the trail. - * @param trail_direction Destination to Source. - * @param target_friend Friend to get this message next. - */ -static void -GDS_NEIGHBOURS_send_notify_succcessor_confirmation (const struct GNUNET_HashCode *trail_id, - unsigned int trail_direction, - struct FriendInfo *target_friend) -{ - struct PeerNotifyConfirmationMessage *ncm; - struct GNUNET_MQ_Envelope *env; - - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg (ncm, - GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_SUCCESSOR_CONFIRMATION); - ncm->trail_id = *trail_id; - ncm->trail_direction = htonl (trail_direction); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Send trail rejection message to @a target_friend - * - * @param source_peer Peer which is trying to setup the trail. - * @param ultimate_destination_finger_value Peer closest to this value will be - * @a source_peer's finger - * @param congested_peer Peer which sent this message as it is congested. - * @param is_predecessor Is source_peer looking for trail to a predecessor or not. - * @param trail_peer_list Trails seen so far in trail setup before getting rejected - * by congested_peer. This does NOT include @a source_peer - * and congested_peer. - * @param trail_length Total number of peers in trail_peer_list, NOT including - * @a source_peer and @a congested_peer - * @param trail_id Unique identifier of this trail. - * @param congestion_timeout Duration given by congested peer as an estimate of - * how long it may remain congested. - */ -static void -GDS_NEIGHBOURS_send_trail_rejection (const struct GNUNET_PeerIdentity *source_peer, - uint64_t ultimate_destination_finger_value, - const struct GNUNET_PeerIdentity *congested_peer, - unsigned int is_predecessor, - const struct GNUNET_PeerIdentity *trail_peer_list, - unsigned int trail_length, - const struct GNUNET_HashCode *trail_id, - struct FriendInfo *target_friend, - const struct GNUNET_TIME_Relative congestion_timeout) -{ - struct PeerTrailRejectionMessage *trm; - struct GNUNET_MQ_Envelope *env; - size_t msize; - - msize = trail_length * sizeof (struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerTrailRejectionMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (trm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION); - trm->source_peer = *source_peer; - trm->congested_peer = *congested_peer; - trm->congestion_time = congestion_timeout; - trm->is_predecessor = htonl (is_predecessor); - trm->trail_id = *trail_id; - trm->ultimate_destination_finger_value - = GNUNET_htonll (ultimate_destination_finger_value); - GNUNET_memcpy (&trm[1], - trail_peer_list, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Construct a verify successor message and forward it to target_friend. - * @param source_peer Peer which wants to verify its successor. - * @param successor Peer which is @a source_peer's current successor. - * @param trail_id Unique Identifier of trail from @a source_peer to @a successor, - * NOT including them. - * @param trail List of peers which are part of trail to reach from @a source_peer - * to @a successor, NOT including them. - * @param trail_length Total number of peers in @a trail. - * @param target_friend Next friend to get this message. - */ -static void -GDS_NEIGHBOURS_send_verify_successor_message (const struct GNUNET_PeerIdentity *source_peer, - const struct GNUNET_PeerIdentity *successor, - const struct GNUNET_HashCode *trail_id, - struct GNUNET_PeerIdentity *trail, - unsigned int trail_length, - struct FriendInfo *target_friend) -{ - struct PeerVerifySuccessorMessage *vsm; - struct GNUNET_MQ_Envelope *env; - size_t msize; - - msize = trail_length * sizeof (struct GNUNET_PeerIdentity); - if (msize + sizeof (*vsm) >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (vsm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR); - vsm->source_peer = *source_peer; - vsm->successor = *successor; - vsm->trail_id = *trail_id; - GNUNET_memcpy (&vsm[1], - trail, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * FIXME: In every function we pass target friend except for this one. - * so, either change everything or this one. also, should we just store - * the pointer to friend in routing table rather than gnunet_peeridentity. - * if yes then we should keep friend info in.h andmake lot of changes. - * Construct a trail teardown message and forward it to target friend. - * - * @param trail_id Unique identifier of the trail. - * @param trail_direction Direction of trail. - * @param target_friend Friend to get this message. - */ -void -GDS_NEIGHBOURS_send_trail_teardown (const struct GNUNET_HashCode *trail_id, - unsigned int trail_direction, - const struct GNUNET_PeerIdentity *peer) -{ - struct PeerTrailTearDownMessage *ttdm; - struct GNUNET_MQ_Envelope *env; - struct FriendInfo *target_friend; - - if (NULL == (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - peer))) - { - /* FIXME: In what case friend can be null. ?*/ - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg (ttdm, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN); - ttdm->trail_id = *trail_id; - ttdm->trail_direction = htonl (trail_direction); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Construct a verify successor result message and send it to target_friend - * - * @param querying_peer Peer which sent the verify successor message. - * @param source_successor Current_successor of @a querying_peer. - * @param current_predecessor Current predecessor of @a successor. Could be same - * or different from @a querying_peer. - * @param trail_id Unique identifier of the trail from @a querying_peer to - * @a successor, NOT including them. - * @param trail List of peers which are part of trail from @a querying_peer to - * @a successor, NOT including them. - * @param trail_length Total number of peers in @a trail - * @param trail_direction Direction in which we are sending the message. In this - * case we are sending result from @a successor to @a querying_peer. - * @param target_friend Next friend to get this message. - */ -static void -GDS_NEIGHBOURS_send_verify_successor_result (const struct GNUNET_PeerIdentity *querying_peer, - const struct GNUNET_PeerIdentity *current_successor, - const struct GNUNET_PeerIdentity *probable_successor, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length, - enum GDS_ROUTING_trail_direction trail_direction, - struct FriendInfo *target_friend) -{ - struct PeerVerifySuccessorResultMessage *vsmr; - struct GNUNET_MQ_Envelope *env; - size_t msize; - - msize = trail_length * sizeof(struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerVerifySuccessorResultMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (vsmr, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT); - vsmr->querying_peer = *querying_peer; - vsmr->current_successor = *current_successor; - vsmr->probable_successor = *probable_successor; - vsmr->trail_direction = htonl (trail_direction); - vsmr->trail_id = *trail_id; - GNUNET_memcpy (&vsmr[1], - trail, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Construct a notify new successor message and send it to target_friend - * @param source_peer Peer which wants to notify to its new successor that it - * could be its predecessor. - * @param successor New successor of @a source_peer - * @param successor_trail List of peers in Trail to reach from - * @a source_peer to @a new_successor, NOT including - * the endpoints. - * @param successor_trail_length Total number of peers in @a new_successor_trail. - * @param successor_trail_id Unique identifier of @a new_successor_trail. - * @param target_friend Next friend to get this message. - */ -static void -GDS_NEIGHBOURS_send_notify_new_successor (const struct GNUNET_PeerIdentity *source_peer, - const struct GNUNET_PeerIdentity *successor, - const struct GNUNET_PeerIdentity *successor_trail, - unsigned int successor_trail_length, - const struct GNUNET_HashCode *succesor_trail_id, - struct FriendInfo *target_friend) -{ - struct PeerNotifyNewSuccessorMessage *nsm; - struct GNUNET_MQ_Envelope *env; - size_t msize; - - msize = successor_trail_length * sizeof(struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerNotifyNewSuccessorMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (nsm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR); - nsm->new_successor = *successor; - nsm->source_peer = *source_peer; - nsm->trail_id = *succesor_trail_id; - GNUNET_memcpy (&nsm[1], - successor_trail, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Construct an add_trail message and send it to target_friend - * - * @param source_peer Source of the trail. - * @param destination_peer Destination of the trail. - * @param trail_id Unique identifier of the trail from - * @a source_peer to @a destination_peer, NOT including the endpoints. - * @param trail List of peers in Trail from @a source_peer to @a destination_peer, - * NOT including the endpoints. - * @param trail_length Total number of peers in @a trail. - * @param target_friend Next friend to get this message. - */ -static void -GDS_NEIGHBOURS_send_add_trail (const struct GNUNET_PeerIdentity *source_peer, - const struct GNUNET_PeerIdentity *destination_peer, - const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length, - struct FriendInfo *target_friend) -{ - struct PeerAddTrailMessage *adm; - struct GNUNET_MQ_Envelope *env; - size_t msize; - - msize = trail_length * sizeof(struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerAddTrailMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND) - { - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# P2P messages dropped due to full queue"), - 1, - GNUNET_NO); - return; - } - env = GNUNET_MQ_msg_extra (adm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL); - adm->source_peer = *source_peer; - adm->destination_peer = *destination_peer; - adm->trail_id = *trail_id; - GNUNET_memcpy (&adm[1], - trail, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Search my location in trail. In case I am present more than once in the - * trail (can happen during trail setup), then return my lowest index. - * - * @param trail List of peers - * @return my_index if found - * trail_length + 1 if an entry is present twice, It is an error. - * -1 if no entry found. - */ -static int -search_my_index (const struct GNUNET_PeerIdentity *trail, - int trail_length) -{ - int i; - int index_seen = trail_length + 1; - int flag = 0; - - for (i = 0; i < trail_length; i++) - { - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, &trail[i])) - { - flag = 1; - if(index_seen == (trail_length + 1)) - index_seen = i; - else - { - DEBUG("Entry is present twice in trail. Its not allowed\n"); - } - break; - } - } - - if (1 == flag) - return index_seen; - return -1; -} - - -/** - * Check if the friend is congested or have reached maximum number of trails - * it can be part of of. - * @param friend Friend to be checked. - * @return #GNUNET_NO if friend is not congested or have not crossed threshold. - * #GNUNET_YES if friend is either congested or have crossed threshold - */ -static int -is_friend_congested (struct FriendInfo *friend) -{ - if (( friend->trails_count < TRAILS_THROUGH_FRIEND_THRESHOLD) && - ((0 == GNUNET_TIME_absolute_get_remaining - (friend->congestion_timestamp).rel_value_us))) - return GNUNET_NO; - return GNUNET_YES; -} - - -/** - * Select closest finger to value. - * - * @param peer1 First peer - * @param peer2 Second peer - * @param value Value to be compare - * @return Closest peer - */ -static const struct GNUNET_PeerIdentity * -select_closest_finger (const struct GNUNET_PeerIdentity *peer1, - const struct GNUNET_PeerIdentity *peer2, - uint64_t value) -{ - uint64_t peer1_value; - uint64_t peer2_value; - - GNUNET_memcpy (&peer1_value, peer1, sizeof (uint64_t)); - GNUNET_memcpy (&peer2_value, peer2, sizeof (uint64_t)); - peer1_value = GNUNET_ntohll (peer1_value); - peer2_value = GNUNET_ntohll (peer2_value); - - if (peer1_value == value) - { - return peer1; - } - - if (peer2_value == value) - { - return peer2; - } - - if (value < peer1_value && peer1_value < peer2_value) - { - return peer1; - } - else if (value < peer2_value && peer2_value < peer1_value) - { - return peer2; - } - else if (peer1_value < value && value < peer2_value) - { - return peer2; - } - else if (peer2_value < value && value < peer1_value) - { - return peer1; - } - else if (peer1_value < peer2_value && peer2_value < value) - { - return peer1; - } - else // if (peer2_value < peer1_value && peer1_value < value) - { - return peer2; - } -} - - -/** - * Select closest predecessor to value. - * - * @param peer1 First peer - * @param peer2 Second peer - * @param value Value to be compare - * @return Peer which precedes value in the network. - */ -static const struct GNUNET_PeerIdentity * -select_closest_predecessor (const struct GNUNET_PeerIdentity *peer1, - const struct GNUNET_PeerIdentity *peer2, - uint64_t value) -{ - uint64_t peer1_value; - uint64_t peer2_value; - - GNUNET_memcpy (&peer1_value, peer1, sizeof (uint64_t)); - GNUNET_memcpy (&peer2_value, peer2, sizeof (uint64_t)); - peer1_value = GNUNET_ntohll (peer1_value); - peer2_value = GNUNET_ntohll (peer2_value); - - if (peer1_value == value) - { - return peer1; - } - - if (peer2_value == value) - { - return peer2; - } - - if (value < peer1_value && peer1_value < peer2_value) - { - return peer2; - } - else if (value < peer2_value && peer2_value < peer1_value) - { - return peer1; - } - else if (peer1_value < value && value < peer2_value) - { - return peer1; - } - else if (peer2_value < value && value < peer1_value) - { - return peer2; - } - else if (peer1_value < peer2_value && peer2_value < value) - { - return peer2; - } - else // if (peer2_value < peer1_value && peer1_value < value) - { - return peer1; - } -} - -#if 0 -/** - * - * - */ -void -test_print_trail (struct GNUNET_PeerIdentity *trail, - unsigned int trail_length) -{ - struct GNUNET_PeerIdentity print_peer; - int i; - - FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail_length = %d"), - __FILE__, __func__,__LINE__,trail_length); - for (i =0 ; i< trail_length; i++) - { - print_peer = trail[i]; - FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail[%d]=%s"), - __FILE__, __func__,__LINE__,i,GNUNET_i2s(&print_peer)); - } -} -#endif - -#if 0 -/** - * This is a test function to print all the entries of friend table. - */ -static void -test_friend_peermap_print () -{ - struct FriendInfo *friend; - struct GNUNET_CONTAINER_MultiPeerMapIterator *friend_iter; - struct GNUNET_PeerIdentity print_peer; - struct GNUNET_PeerIdentity key_ret; - int i; - - print_peer = my_identity; - FPRINTF (stderr,_("\nSUPU************ FRIEND_PEERMAP of %s"),GNUNET_i2s(&print_peer)); - friend_iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap); - - for (i = 0; i < GNUNET_CONTAINER_multipeermap_size (friend_peermap); i++) - { - if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (friend_iter, - &key_ret, - (const void **)&friend)) - { - GNUNET_memcpy (&print_peer, &key_ret, sizeof (struct GNUNET_PeerIdentity)); - FPRINTF (stderr,_("\nSUPU %s, %s, %d, friend = %s, friend->trails_count = %d"), - __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer), friend->trails_count); - } - } -} -#endif - -#if 0 -/** - * This is a test function, to print all the entries of finger table. - */ -static void -test_finger_table_print() -{ - struct FingerInfo *finger; - struct GNUNET_PeerIdentity print_peer; - //struct Trail *trail; - int i; - //int j; - //int k; - print_peer = my_identity; - FPRINTF (stderr,_("\nSUPU************ FINGER_TABLE of %s"),GNUNET_i2s(&print_peer)); - for (i = 0; i < MAX_FINGERS; i++) - { - finger = &finger_table[i]; - - if (GNUNET_NO == finger->is_present) - continue; - - print_peer = finger->finger_identity; - FPRINTF (stderr,_("\nSUPU %s, %s, %d, finger_table[%d] = %s, trails_count = %d"), - __FILE__, __func__,__LINE__,i,GNUNET_i2s (&print_peer), finger->trails_count); - -#if 0 - for (j = 0; j < finger->trails_count; j++) - { - trail = &finger->trail_list[j]; - FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail_id[%d]=%s"),__FILE__, __func__,__LINE__,j, GNUNET_h2s(&trail->trail_id)); - struct Trail_Element *element; - element = trail->trail_head; - for (k = 0; k < trail->trail_length; k++) - { - print_peer = element->peer; - FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail[%d] = %s "),__FILE__, __func__,__LINE__,k, GNUNET_i2s(&print_peer)); - element = element->next; - } - } - #endif - } -} -#endif - -/** - * Select the closest peer among two peers (which should not be same) - * with respect to value and finger_table_index - * NOTE: peer1 != peer2 - * @param peer1 First peer - * @param peer2 Second peer - * @param value Value relative to which we find the closest - * @param is_predecessor Is value a predecessor or any other finger. - * @return Closest peer among two peers. - */ -static const struct GNUNET_PeerIdentity * -select_closest_peer (const struct GNUNET_PeerIdentity *peer1, - const struct GNUNET_PeerIdentity *peer2, - uint64_t value, - unsigned int is_predecessor) -{ - /* This check is here to ensure that calling function never sends - same peer value in peer1 and peer2. Remove it later. */ - GNUNET_assert(0 != GNUNET_CRYPTO_cmp_peer_identity (peer1, peer2)); - if (1 == is_predecessor) - return select_closest_predecessor (peer1, peer2, value); - - // TODO: Change name to something like select_closest_successor!! - return select_closest_finger (peer1, peer2, value); -} - - -/** - * Iterate over the list of all the trails of a finger. In case the first - * friend to reach the finger has reached trail threshold or is congested, - * then don't select it. In case there multiple available good trails to reach - * to Finger, choose the one with shortest trail length. - * Note: We use length as parameter. But we can use any other suitable parameter - * also. - * @param finger Finger Finger whose trail we have to select. - * @return Trail Selected Trail. - */ -static struct Trail * -select_finger_trail (struct FingerInfo *finger) -{ - struct FriendInfo *friend; - struct Trail *current_finger_trail; - struct Trail *best_trail = NULL; - unsigned int i; - - GNUNET_assert (finger->trails_count > 0); - for (i = 0; i < finger->trails_count; i++) - { - current_finger_trail = &finger->trail_list[i]; - - /* No trail stored at this index. */ - if (GNUNET_NO == current_finger_trail->is_present) - continue; - - GNUNET_assert (NULL != - (friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - ¤t_finger_trail->trail_head->peer))); - - /* First friend to reach trail is not free. */ - if (GNUNET_YES == is_friend_congested (friend)) - continue; - - if (NULL == best_trail || - best_trail->trail_length > current_finger_trail->trail_length) - { - best_trail = current_finger_trail; - } - } - - return best_trail; -} - - -/** - * Compare FINGER entry with current successor. If finger's first friend of all - * its trail is not congested and has not crossed trail threshold, then check - * if finger peer identity is closer to final_destination_finger_value than - * current_successor. If yes then update current_successor. - * @param current_successor[in/out] - * @return - */ -static void -compare_finger_and_current_closest_peer (struct Closest_Peer *current_closest_peer) -{ - struct FingerInfo *finger; - const struct GNUNET_PeerIdentity *closest_peer; - struct Trail *finger_trail; - int i; - - /* Iterate over finger table. */ - for (i = 0; i < MAX_FINGERS; i++) - { - finger = &finger_table[i]; - - if (GNUNET_NO == finger->is_present) - continue; - - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity, - ¤t_closest_peer->best_known_destination)) - continue; - - /* If I am my own finger, then ignore this finger. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity, - &my_identity)) - continue; - - /* If finger is a friend, we have already checked it in previous function. */ - if (NULL != (GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &finger->finger_identity))) - { - continue; - } - - closest_peer = select_closest_peer (&finger->finger_identity, - ¤t_closest_peer->best_known_destination, - current_closest_peer->destination_finger_value, - current_closest_peer->is_predecessor); - - if (0 == GNUNET_CRYPTO_cmp_peer_identity(&finger->finger_identity, - closest_peer)) - { - /* Choose one of the trail to reach to finger. */ - finger_trail = select_finger_trail (finger); - - /* In case no trail found, ignore this finger. */ - if (NULL == finger_trail) - continue; - - current_closest_peer->best_known_destination = *closest_peer; - current_closest_peer->next_hop = finger_trail->trail_head->peer; - current_closest_peer->trail_id = finger_trail->trail_id; - current_closest_peer->finger_table_index = i; - } - continue; - } -} - - -/** - * Compare friend entry with current successor. - * If friend identity and current_successor is same, then do nothing. - * If friend is not congested and has not crossed trail threshold, then check - * if friend peer identity is closer to final_destination_finger_value than - * current_successor. If yes then update current_successor. - * - * @param cls closure - * @param key current public key - * @param value struct Closest_Peer - * @return #GNUNET_YES if we should continue to iterate, - * #GNUNET_NO if not. - */ -static int -compare_friend_and_current_closest_peer (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct FriendInfo *friend = value; - struct Closest_Peer *current_closest_peer = cls; - const struct GNUNET_PeerIdentity *closest_peer; - - /* Friend is either congested or has crossed threshold. */ - if (GNUNET_YES == is_friend_congested (friend)) - return GNUNET_YES; - - /* If current_closest_peer and friend identity are same, then do nothing.*/ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (friend->id, - ¤t_closest_peer->best_known_destination)) - { - GNUNET_break (0); - return GNUNET_YES; - } - - closest_peer = select_closest_peer (friend->id, - ¤t_closest_peer->best_known_destination, - current_closest_peer->destination_finger_value, - current_closest_peer->is_predecessor); - - /* Is friend the closest successor? */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (friend->id, - closest_peer)) - { - current_closest_peer->best_known_destination = *friend->id; - current_closest_peer->next_hop = *friend->id; - } - return GNUNET_YES; -} - - -/** - * Initialize current_successor to my_identity. - * @param my_identity My peer identity - * @return Updated closest_peer - */ -static struct Closest_Peer -init_closest_peer (struct GNUNET_PeerIdentity my_identity, - uint64_t destination_finger_value, - unsigned int is_predecessor) -{ - struct Closest_Peer current_closest_peer; - - memset (¤t_closest_peer.trail_id, - 0, - sizeof(struct GNUNET_HashCode)); - current_closest_peer.destination_finger_value = destination_finger_value; - current_closest_peer.is_predecessor = is_predecessor; - current_closest_peer.next_hop = my_identity; - current_closest_peer.best_known_destination = my_identity; - current_closest_peer.finger_table_index = 65; //65 is a for non valid finger table index. - return current_closest_peer; -} - - -/** - * Find locally best known peer, among your own identity, friend and finger list, - * which is closest to given destination_finger_value. - * - * NOTE: In case a friend is also a finger, then it is always chosen as friend - * not a finger. - * @param destination_finger_value Peer closest to this value will be the next destination. - * @param is_predecessor Are we looking for predecessor or finger? - * @return Closest_Peer that contains all the relevant field to reach to - * @a destination_finger_value - */ -static struct Closest_Peer -find_local_best_known_next_hop (uint64_t destination_finger_value, - unsigned int is_predecessor) -{ - struct Closest_Peer current_closest_peer; - - /* Initialize current_successor to my_identity. */ - current_closest_peer = init_closest_peer (my_identity, - destination_finger_value, - is_predecessor); - - /* Compare each friend entry with current_successor and update current_successor - * with friend if its closest. */ - GNUNET_assert - (GNUNET_SYSERR != - GNUNET_CONTAINER_multipeermap_iterate (friend_peermap, - &compare_friend_and_current_closest_peer, - ¤t_closest_peer)); - - /* Compare each finger entry with current_successor and update current_successor - * with finger if its closest. */ - compare_finger_and_current_closest_peer (¤t_closest_peer); - return current_closest_peer; -} - - -/** - * Construct a Put message and send it to target_peer. - * @param key Key for the content - * @param block_type Type of the block - * @param options Routing options - * @param desired_replication_level Desired replication count - * @param best_known_dest Peer to which this message should reach eventually, - * as it is best known destination to me. - * @param intermediate_trail_id Trail id in case - * @param target_peer Peer to which this message will be forwarded. - * @param hop_count Number of hops traversed so far. - * @param put_path_length Total number of peers in @a put_path - * @param put_path Number of peers traversed so far - * @param expiration_time When does the content expire - * @param data Content to store - * @param data_size Size of content @a data in bytes - */ -void -GDS_NEIGHBOURS_send_put (const struct GNUNET_HashCode *key, - enum GNUNET_BLOCK_Type block_type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - struct GNUNET_PeerIdentity best_known_dest, - struct GNUNET_HashCode intermediate_trail_id, - struct GNUNET_PeerIdentity *target_peer, - uint32_t hop_count, - uint32_t put_path_length, - struct GNUNET_PeerIdentity *put_path, - struct GNUNET_TIME_Absolute expiration_time, - const void *data, size_t data_size) -{ - struct PeerPutMessage *ppm; - struct GNUNET_MQ_Envelope *env; - struct FriendInfo *target_friend; - struct GNUNET_PeerIdentity *pp; - size_t msize; - - msize = put_path_length * sizeof (struct GNUNET_PeerIdentity) + data_size; - if (msize + sizeof (struct PeerPutMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - put_path_length = 0; - msize = data_size; - } - if (msize + sizeof (struct PeerPutMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - target_peer))); - env = GNUNET_MQ_msg_extra (ppm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT); - ppm->options = htonl (options); - ppm->block_type = htonl (block_type); - ppm->hop_count = htonl (hop_count + 1); - ppm->desired_replication_level = htonl (desired_replication_level); - ppm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time); - ppm->best_known_destination = best_known_dest; - ppm->intermediate_trail_id = intermediate_trail_id; - ppm->key = *key; - ppm->put_path_length = htonl (put_path_length); - pp = (struct GNUNET_PeerIdentity *) &ppm[1]; - GNUNET_memcpy (pp, - put_path, - put_path_length * sizeof (struct GNUNET_PeerIdentity)); - GNUNET_memcpy (&pp[put_path_length], - data, - data_size); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Handle the put request from the client. - * - * @param block_type Type of the block - * @param options Routing options - * @param desired_replication_level Desired replication count - * @param expiration_time When does the content expire - * @param hop_count how many hops has this message traversed so far - * @param bf Bloom filter of peers this PUT has already traversed - * @param key Key for the content - * @param put_path_length number of entries in put_path - * @param put_path peers this request has traversed so far (if tracked) - * @param data Content to store - * @param data_size Size of content @a data in bytes - * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not - */ -int -GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type block_type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - struct GNUNET_TIME_Absolute expiration_time, - uint32_t hop_count, - struct GNUNET_CONTAINER_BloomFilter *bf, - const struct GNUNET_HashCode *key, - unsigned int put_path_length, - struct GNUNET_PeerIdentity *put_path, - const void *data, - size_t data_size) -{ - struct GNUNET_PeerIdentity best_known_dest; - struct GNUNET_HashCode intermediate_trail_id; - struct GNUNET_PeerIdentity next_hop; - uint64_t key_value; - struct Closest_Peer successor; - - GNUNET_memcpy (&key_value, - key, - sizeof (uint64_t)); - key_value = GNUNET_ntohll (key_value); - successor = find_local_best_known_next_hop (key_value, - GDS_FINGER_TYPE_NON_PREDECESSOR); - best_known_dest = successor.best_known_destination; - next_hop = successor.next_hop; - intermediate_trail_id = successor.trail_id; - - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&best_known_dest, - &my_identity)) - { - DEBUG("\n PUT_REQUEST_SUCCESSFUL for key = %s", - GNUNET_h2s(key)); - /* I am the destination. */ - GDS_DATACACHE_handle_put (expiration_time, - key, - 0, - NULL, - block_type, - data_size, - data); - GDS_CLIENTS_process_put (options, - block_type, - 0, - ntohl (desired_replication_level), - 1, - &my_identity, - expiration_time, - key, - data, - data_size); - return GNUNET_NO; - } - /* In case we are sending the request to a finger, then send across all of its - trail.*/ - GDS_NEIGHBOURS_send_put (key, - block_type, - options, - desired_replication_level, - best_known_dest, - intermediate_trail_id, - &next_hop, - 0, - 1, - &my_identity, - expiration_time, - data, - data_size); - return GNUNET_OK; -} - - -/** - * Construct a Get message and send it to target_peer. - * - * @param key Key for the content - * @param block_type Type of the block - * @param options Routing options - * @param desired_replication_level Desired replication count - * @param best_known_dest Peer which should get this message. Same as target peer - * if best_known_dest is a friend else its a finger. - * @param intermediate_trail_id Trail id to reach to @a best_known_dest - * in case it is a finger else set to 0. - * @param target_peer Peer to which this message will be forwarded. - * @param hop_count Number of hops traversed so far. - * @param data Content to store - * @param data_size Size of content @a data in bytes - * @param get_path_length Total number of peers in @a get_path - * @param get_path Number of peers traversed so far - */ -void -GDS_NEIGHBOURS_send_get (const struct GNUNET_HashCode *key, - enum GNUNET_BLOCK_Type block_type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - const struct GNUNET_PeerIdentity *best_known_dest, - const struct GNUNET_HashCode *intermediate_trail_id, - const struct GNUNET_PeerIdentity *target_peer, - uint32_t hop_count, - uint32_t get_path_length, - const struct GNUNET_PeerIdentity *get_path) -{ - struct PeerGetMessage *pgm; - struct GNUNET_MQ_Envelope *env; - struct FriendInfo *target_friend; - size_t msize; - - msize = get_path_length * sizeof (struct GNUNET_PeerIdentity); - if (msize + sizeof (struct PeerGetMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - target_peer))); - env = GNUNET_MQ_msg_extra (pgm, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_GET); - pgm->get_path_length = htonl (get_path_length); - pgm->best_known_destination = *best_known_dest; - pgm->key = *key; - pgm->intermediate_trail_id = *intermediate_trail_id; - pgm->hop_count = htonl (hop_count + 1); - pgm->get_path_length = htonl (get_path_length); - GNUNET_memcpy (&pgm[1], - get_path, - msize); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Send the get result to requesting client. - * - * @param key Key of the requested data. - * @param block_type Block type - * @param target_peer Next peer to forward the message to. - * @param source_peer Peer which has the data for the key. - * @param put_path_length Number of peers in @a put_path - * @param put_path Path taken to put the data at its stored location. - * @param get_path_length Number of peers in @a get_path - * @param get_path Path taken to reach to the location of the key. - * @param expiration When will this result expire? - * @param data Payload to store - * @param data_size Size of the @a data - */ -void -GDS_NEIGHBOURS_send_get_result (const struct GNUNET_HashCode *key, - enum GNUNET_BLOCK_Type block_type, - const struct GNUNET_PeerIdentity *target_peer, - const struct GNUNET_PeerIdentity *source_peer, - unsigned int put_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *get_path, - struct GNUNET_TIME_Absolute expiration, - const void *data, size_t data_size) -{ - struct PeerGetResultMessage *get_result; - struct GNUNET_PeerIdentity *paths; - struct GNUNET_MQ_Envelope *env; - struct FriendInfo *target_friend; - int current_path_index; - size_t msize; - - msize = (put_path_length + get_path_length) * sizeof (struct GNUNET_PeerIdentity) + - data_size; - if (msize + sizeof (struct PeerGetResultMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - put_path_length = 0; - msize = data_size; - } - if (msize + sizeof (struct PeerGetResultMessage) - >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) - { - GNUNET_break(0); - return; - } - current_path_index = 0; - if (get_path_length > 0) - { - current_path_index = search_my_index (get_path, - get_path_length); - if (-1 == current_path_index) - { - GNUNET_break (0); - return; - } - if ((get_path_length + 1) == current_path_index) - { - DEBUG ("Peer found twice in get path. Not allowed \n"); - GNUNET_break (0); - return; - } - } - if (0 == current_path_index) - { - DEBUG ("GET_RESULT TO CLIENT KEY = %s, Peer = %s", - GNUNET_h2s (key), - GNUNET_i2s (&my_identity)); - GDS_CLIENTS_handle_reply (expiration, - key, - get_path_length, - get_path, - put_path_length, - put_path, - block_type, - data_size, - data); - return; - } - env = GNUNET_MQ_msg_extra (get_result, - msize, - GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT); - get_result->key = *key; - get_result->querying_peer = *source_peer; - get_result->expiration_time = GNUNET_TIME_absolute_hton (expiration); - get_result->get_path_length = htonl (get_path_length); - get_result->put_path_length = htonl (put_path_length); - paths = (struct GNUNET_PeerIdentity *)&get_result[1]; - GNUNET_memcpy (paths, - put_path, - put_path_length * sizeof (struct GNUNET_PeerIdentity)); - GNUNET_memcpy (&paths[put_path_length], - get_path, - get_path_length * sizeof (struct GNUNET_PeerIdentity)); - GNUNET_memcpy (&paths[put_path_length + get_path_length], - data, - data_size); - - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &get_path[current_path_index - 1]))); - GNUNET_MQ_send (target_friend->mq, - env); -} - - -/** - * Handle a result for a GET operation. - * - * @param cls closure - * @param type type of the block - * @param expiration_time when does the content expire - * @param key key for the content - * @param put_path_length number of entries in @a put_path - * @param put_path peers the original PUT traversed (if tracked) - * @param get_path_length number of entries in @a get_path - * @param get_path peers this reply has traversed so far (if tracked) - * @param data payload of the reply - * @param data_size number of bytes in @a data - */ -static void -get_cb (void *cls, - enum GNUNET_BLOCK_Type type, - struct GNUNET_TIME_Absolute expiration_time, - const struct GNUNET_HashCode *key, - unsigned int put_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *get_path, - const void *data, - size_t data_size) -{ - struct GNUNET_PeerIdentity *target_peer = cls; - // FIXME: inline? - GDS_NEIGHBOURS_send_get_result (key, - type, - target_peer, - &my_identity, - put_path_length, - put_path, - 1, - &my_identity, - expiration_time, - data, - data_size); -} - - -/** - * Perform a GET operation. Forwards the given request to other - * peers. Does not lookup the key locally. May do nothing if this is - * the only peer in the network (or if we are the closest peer in the - * network). - * - * @param block_type type of the block - * @param options routing options - * @param desired_replication_level desired replication count - * @param hop_count how many hops did this request traverse so far? - * @param key key for the content - * @param xquery extended query - * @param xquery_size number of bytes in @a xquery - * @param bg group to filter duplicates - * @param peer_bf filter for peers not to select (again, updated) - * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not - */ -int -GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type block_type, - enum GNUNET_DHT_RouteOption options, - uint32_t desired_replication_level, - uint32_t hop_count, - const struct GNUNET_HashCode *key, - const void *xquery, - size_t xquery_size, - struct GNUNET_BLOCK_Group *bg, - struct GNUNET_CONTAINER_BloomFilter *peer_bf) -{ - struct Closest_Peer successor; - struct GNUNET_PeerIdentity best_known_dest; - struct GNUNET_HashCode intermediate_trail_id; - uint64_t key_value; - - GNUNET_memcpy (&key_value, - key, - sizeof (uint64_t)); - key_value = GNUNET_ntohll (key_value); - successor = find_local_best_known_next_hop (key_value, - GDS_FINGER_TYPE_NON_PREDECESSOR); - best_known_dest = successor.best_known_destination; - intermediate_trail_id = successor.trail_id; - - /* I am the destination. I have the data. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &best_known_dest)) - { - GDS_DATACACHE_handle_get (key, - block_type, - NULL, - 0, - bg, - &get_cb, - NULL); - return GNUNET_NO; - } - - GDS_NEIGHBOURS_send_get (key, - block_type, - options, - desired_replication_level, - &best_known_dest, - &intermediate_trail_id, - &successor.next_hop, - 0, - 1, - &my_identity); - return GNUNET_OK; -} - - -/** - * Randomly choose one of your friends (which is not congested and have not crossed - * trail threshold) from the friend_peermap - * @return Friend Randomly chosen friend. - * NULL in case friend peermap is empty, or all the friends are either - * congested or have crossed trail threshold. - */ -static struct FriendInfo * -select_random_friend () -{ - unsigned int current_size; - uint32_t index; - unsigned int j = 0; - struct GNUNET_CONTAINER_MultiPeerMapIterator *iter; - struct GNUNET_PeerIdentity key_ret; - struct FriendInfo *friend; - - current_size = GNUNET_CONTAINER_multipeermap_size (friend_peermap); - - /* No friends.*/ - if (0 == current_size) - return NULL; - - index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, current_size); - iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap); - - /* Iterate till you don't reach to index. */ - for (j = 0; j < index ; j++) - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL)); - - do - { - /* Reset the index in friend peermap to 0 as we reached to the end. */ - if (j == current_size) - { - j = 0; - GNUNET_CONTAINER_multipeermap_iterator_destroy (iter); - iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap); - - } - - /* Get the friend stored at the index, j*/ - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_iterator_next (iter, - &key_ret, - (const void **)&friend)); - - /* This friend is not congested and has not crossed trail threshold. */ - if ((friend->trails_count < TRAILS_THROUGH_FRIEND_THRESHOLD) && - (0 == GNUNET_TIME_absolute_get_remaining (friend->congestion_timestamp).rel_value_us)) - { - break; - } - friend = NULL; - j++; - } while (j != index); - - GNUNET_CONTAINER_multipeermap_iterator_destroy (iter); - return friend; -} - - -/** - * Compute 64 bit value of finger_identity corresponding to a finger index using - * Chord formula. - * For all fingers, n.finger[i] = n + pow (2,i), - * For predecessor, n.finger[PREDECESSOR_FINGER_ID] = n - 1, where - * n = my_identity, i = finger_index, n.finger[i] = 64 bit finger value - * - * @param finger_index Index corresponding to which we calculate 64 bit value. - * @return 64 bit value. - */ -static uint64_t -compute_finger_identity_value (unsigned int finger_index) -{ - uint64_t my_id64; - - GNUNET_memcpy (&my_id64, - &my_identity, - sizeof (uint64_t)); - my_id64 = GNUNET_ntohll (my_id64); - - /* Are we looking for immediate predecessor? */ - if (PREDECESSOR_FINGER_ID == finger_index) - return (my_id64 - 1); - uint64_t add = (uint64_t)1 << finger_index; - return (my_id64 + add); -} - - -/** - * Choose a random friend. Calculate the next finger identity to search,from - * current_search_finger_index. Start looking for the trail to reach to - * finger identity through this random friend. - * - * @param cls closure for this task - */ -static void -send_find_finger_trail_message (void *cls) -{ - struct FriendInfo *target_friend; - struct GNUNET_HashCode trail_id; - struct GNUNET_HashCode intermediate_trail_id; - unsigned int is_predecessor = 0; - uint64_t finger_id_value; - - /* Schedule another send_find_finger_trail_message task. After one round of - * finger search, this time is exponentially backoff. */ - find_finger_trail_task_next_send_time.rel_value_us = - find_finger_trail_task_next_send_time.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us); - find_finger_trail_task = - GNUNET_SCHEDULER_add_delayed (find_finger_trail_task_next_send_time, - &send_find_finger_trail_message, - NULL); - - /* No space in my routing table. (Source and destination peers also store entries - * in their routing table). */ - if (GNUNET_YES == GDS_ROUTING_threshold_reached()) - return; - - target_friend = select_random_friend (); - if (NULL == target_friend) - return; - - finger_id_value = compute_finger_identity_value (current_search_finger_index); - if (PREDECESSOR_FINGER_ID == current_search_finger_index) - is_predecessor = 1; - - /* Generate a unique trail id for trail we are trying to setup. */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, - &trail_id, - sizeof (trail_id)); - memset (&intermediate_trail_id, - 0, - sizeof (struct GNUNET_HashCode)); - GDS_NEIGHBOURS_send_trail_setup (&my_identity, - finger_id_value, - target_friend->id, - target_friend, - 0, NULL, - is_predecessor, - &trail_id, - &intermediate_trail_id); -} - - -/** - * In case there are already maximum number of possible trails to reach to a - * finger, then check if the new trail's length is lesser than any of the - * existing trails. - * If yes then replace that old trail by new trail. - * - * Note: Here we are taking length as a parameter to choose the best possible - * trail, but there could be other parameters also like: - * 1. duration of existence of a trail - older the better. - * 2. if the new trail is completely disjoint than the - * other trails, then may be choosing it is better. - * - * @param finger Finger - * @param new_finger_trail List of peers to reach from me to @a finger, NOT - * including the endpoints. - * @param new_finger_trail_length Total number of peers in @a new_finger_trail - * @param new_finger_trail_id Unique identifier of @a new_finger_trail. - */ -static void -select_and_replace_trail (struct FingerInfo *finger, - const struct GNUNET_PeerIdentity *new_trail, - unsigned int new_trail_length, - const struct GNUNET_HashCode *new_trail_id) -{ - struct Trail *current_trail; - unsigned int largest_trail_length; - unsigned int largest_trail_index; - struct Trail_Element *trail_element; - const struct GNUNET_PeerIdentity *next_hop; - unsigned int i; - - largest_trail_length = new_trail_length; - largest_trail_index = MAXIMUM_TRAILS_PER_FINGER + 1; - - GNUNET_assert (MAXIMUM_TRAILS_PER_FINGER == finger->trails_count); - - for (i = 0; i < finger->trails_count; i++) - { - current_trail = &finger->trail_list[i]; - GNUNET_assert (GNUNET_YES == current_trail->is_present); - if (current_trail->trail_length > largest_trail_length) - { - largest_trail_length = current_trail->trail_length; - largest_trail_index = i; - } - } - - /* New trail is not better than existing ones. Send trail teardown. */ - if (largest_trail_index == (MAXIMUM_TRAILS_PER_FINGER + 1)) - { - next_hop = GDS_ROUTING_get_next_hop (new_trail_id, - GDS_ROUTING_SRC_TO_DEST); - GDS_ROUTING_remove_trail (new_trail_id); - GDS_NEIGHBOURS_send_trail_teardown (new_trail_id, - GDS_ROUTING_SRC_TO_DEST, - next_hop); - return; - } - - /* Send trail teardown message across the replaced trail. */ - struct Trail *replace_trail = &finger->trail_list[largest_trail_index]; - next_hop = GDS_ROUTING_get_next_hop (&replace_trail->trail_id, - GDS_ROUTING_SRC_TO_DEST); - GNUNET_assert (GNUNET_YES == GDS_ROUTING_remove_trail (&replace_trail->trail_id)); - GDS_NEIGHBOURS_send_trail_teardown (&replace_trail->trail_id, - GDS_ROUTING_SRC_TO_DEST, - next_hop); - - /* Free the trail. */ - while (NULL != (trail_element = replace_trail->trail_head)) - { - GNUNET_CONTAINER_DLL_remove (replace_trail->trail_head, - replace_trail->trail_tail, - trail_element); - GNUNET_free_non_null (trail_element); - } - - /* Add new trial at that location. */ - replace_trail->is_present = GNUNET_YES; - replace_trail->trail_length = new_trail_length; - replace_trail->trail_id = *new_trail_id; - - for (i = 0; i < new_trail_length; i++) - { - struct Trail_Element *element = GNUNET_new (struct Trail_Element); - element->peer = new_trail[i]; - - GNUNET_CONTAINER_DLL_insert_tail (replace_trail->trail_head, - replace_trail->trail_tail, - element); - } - /* FIXME: URGENT Are we adding the trail back to the list. */ -} - - -/** - * Check if the new trail to reach to finger is unique or do we already have - * such a trail present for finger. - * @param existing_finger Finger identity - * @param new_trail New trail to reach @a existing_finger - * @param trail_length Total number of peers in new_trail. - * @return #GNUNET_YES if the new trail is unique - * #GNUNET_NO if same trail is already present. - */ -static int -is_new_trail_unique (struct FingerInfo *existing_finger, - const struct GNUNET_PeerIdentity *new_trail, - unsigned int trail_length) -{ - struct Trail *current_trail; - struct Trail_Element *trail_element; - int i; - int j; - - GNUNET_assert (existing_finger->trails_count > 0); - - /* Iterate over list of trails. */ - for (i = 0; i < existing_finger->trails_count; i++) - { - current_trail = &(existing_finger->trail_list[i]); - if(GNUNET_NO == current_trail->is_present) - continue; - - /* New trail and existing trail length are not same. */ - if (current_trail->trail_length != trail_length) - { - return GNUNET_YES; - } - - trail_element = current_trail->trail_head; - for (j = 0; j < current_trail->trail_length; j++) - { - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&new_trail[j], - &trail_element->peer)) - { - return GNUNET_YES; - } - trail_element = trail_element->next; - } - } - return GNUNET_NO; -} - - -/** - * FIXME; In case of multiple trails, we may have a case where a trail from in - * between has been removed, then we should try to find a free slot , not simply - * add a trail at then end of the list. - * Add a new trail at a free slot in trail array of existing finger. - * @param existing_finger Finger - * @param new_finger_trail New trail from me to finger, NOT including endpoints - * @param new_finger_trail_length Total number of peers in @a new_finger_trail - * @param new_finger_trail_id Unique identifier of the trail. - */ -static void -add_new_trail (struct FingerInfo *existing_finger, - const struct GNUNET_PeerIdentity *new_trail, - unsigned int new_trail_length, - const struct GNUNET_HashCode *new_trail_id) -{ - struct FriendInfo *friend; - struct Trail *trail; - unsigned int i; - int free_slot = -1; - - if (GNUNET_NO == is_new_trail_unique (existing_finger, - new_trail, - new_trail_length)) - return; - - for (i = 0; i < existing_finger->trails_count; i++) - { - if (GNUNET_NO == existing_finger->trail_list[i].is_present) - { - free_slot = i; - break; - } - } - - if (-1 == free_slot) - free_slot = i; - - trail = &existing_finger->trail_list[free_slot]; - GNUNET_assert (GNUNET_NO == trail->is_present); - trail->trail_id = *new_trail_id; - trail->trail_length = new_trail_length; - existing_finger->trails_count++; - trail->is_present = GNUNET_YES; - if (0 == new_trail_length) - { - friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &existing_finger->finger_identity); - } - else - { - friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &new_trail[0]); - } - GNUNET_assert (NULL != friend); - friend->trails_count++; - for (i = 0; i < new_trail_length; i++) - { - struct Trail_Element *element; - - element = GNUNET_new (struct Trail_Element); - element->peer = new_trail[i]; - GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head, - trail->trail_tail, - element); - } - - existing_finger->trail_list[free_slot].trail_head = trail->trail_head; - existing_finger->trail_list[free_slot].trail_tail = trail->trail_tail; - existing_finger->trail_list[free_slot].trail_length = new_trail_length; - existing_finger->trail_list[free_slot].trail_id = *new_trail_id; - existing_finger->trail_list[free_slot].is_present = GNUNET_YES; -} - - -#if 0 -/** - * FIXME; In case of multiple trails, we may have a case where a trail from in - * between has been removed, then we should try to find a free slot , not simply - * add a trail at then end of the list. - * Add a new trail at a free slot in trail array of existing finger. - * @param existing_finger Finger - * @param new_finger_trail New trail from me to finger, NOT including endpoints - * @param new_finger_trail_length Total number of peers in @a new_finger_trail - * @param new_finger_trail_id Unique identifier of the trail. - */ -static void -add_new_trail (struct FingerInfo *existing_finger, - const struct GNUNET_PeerIdentity *new_trail, - unsigned int new_trail_length, - const struct GNUNET_HashCode *new_trail_id) -{ - struct Trail *trail; - struct FriendInfo *first_friend; - int i; - int index; - - if (GNUNET_NO == is_new_trail_unique (existing_finger, - new_trail, - new_trail_length)) - return; - - index = existing_finger->trails_count; - trail = &existing_finger->trail_list[index]; - GNUNET_assert (GNUNET_NO == trail->is_present); - trail->trail_id = *new_trail_id; - trail->trail_length = new_trail_length; - existing_finger->trails_count++; - trail->is_present = GNUNET_YES; - - GNUNET_assert (NULL == (GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &existing_finger->finger_identity))); - /* If finger is a friend then we never call this function. */ - GNUNET_assert (new_trail_length > 0); - - first_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &new_trail[0]); - first_friend->trails_count++; - - for (i = 0; i < new_trail_length; i++) - { - struct Trail_Element *element; - - element = GNUNET_new (struct Trail_Element); - element->peer = new_trail[i]; - GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head, - trail->trail_tail, - element); - } - /* Do we need to add trail head and trail tail in the trail list itearator.*/ - existing_finger->trail_list[index].trail_head = trail->trail_head; - existing_finger->trail_list[index].trail_tail = trail->trail_tail; - existing_finger->trail_list[index].trail_length = new_trail_length; - existing_finger->trail_list[index].trail_id = *new_trail_id; - existing_finger->trail_list[index].is_present = GNUNET_YES; -} -#endif - -/** - * Get the next hop to send trail teardown message from routing table and - * then delete the entry from routing table. Send trail teardown message for a - * specific trail of a finger. - * @param finger Finger whose trail is to be removed. - * @param trail List of peers in trail from me to a finger, NOT including - * endpoints. - */ -static void -send_trail_teardown (struct FingerInfo *finger, - struct Trail *trail) -{ - struct FriendInfo *friend; - const struct GNUNET_PeerIdentity *next_hop; - - next_hop = GDS_ROUTING_get_next_hop (&trail->trail_id, - GDS_ROUTING_SRC_TO_DEST); - if (NULL == next_hop) - { -// DEBUG(" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line=%d,traillength = %d", -// GNUNET_i2s(&my_identity), GNUNET_h2s(&trail->trail_id), __LINE__,trail->trail_length); - return; - } - GNUNET_assert (0 != GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity, - &my_identity)); - - GNUNET_assert(GNUNET_YES == trail->is_present); - if (trail->trail_length > 0) - { - friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail->trail_head->peer); - } - else - { - friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &finger->finger_identity); - } - - if(NULL == friend) - { - DEBUG ("\n LINE NO: = %d, Friend not found for trail id %s of peer %s trail length = %d", - __LINE__, - GNUNET_h2s (&trail->trail_id), - GNUNET_i2s(&my_identity), - trail->trail_length); - return; - } - if ( (0 != GNUNET_CRYPTO_cmp_peer_identity (next_hop, - friend->id) ) && - (0 == trail->trail_length)) - { - DEBUG ("\n LINE NO: = %d, Friend not found for trail id %s of peer %s trail length = %d", - __LINE__, - GNUNET_h2s (&trail->trail_id), - GNUNET_i2s (&my_identity), - trail->trail_length); - return; - } - GNUNET_assert (GNUNET_YES == - GDS_ROUTING_remove_trail (&trail->trail_id)); - friend->trails_count--; - GDS_NEIGHBOURS_send_trail_teardown (&trail->trail_id, - GDS_ROUTING_SRC_TO_DEST, - friend->id); -} - - -/** - * Send trail teardown message across all the trails to reach to finger. - * @param finger Finger whose all the trail should be freed. - */ -static void -send_all_finger_trails_teardown (struct FingerInfo *finger) -{ - for (unsigned int i = 0; i < finger->trails_count; i++) - { - struct Trail *trail; - - trail = &finger->trail_list[i]; - if (GNUNET_YES == trail->is_present) - { - send_trail_teardown (finger, trail); - trail->is_present = GNUNET_NO; - } - } -} - - -/** - * Free a specific trail - * @param trail List of peers to be freed. - */ -static void -free_trail (struct Trail *trail) -{ - struct Trail_Element *trail_element; - - while (NULL != (trail_element = trail->trail_head)) - { - GNUNET_CONTAINER_DLL_remove (trail->trail_head, - trail->trail_tail, - trail_element); - GNUNET_free_non_null (trail_element); - } - trail->trail_head = NULL; - trail->trail_tail = NULL; -} - - -/** - * Free finger and its trail. - * - * @param finger Finger to be freed. - * @param finger_table_index Index at which finger is stored. - */ -static void -free_finger (struct FingerInfo *finger, - unsigned int finger_table_index) -{ - struct Trail *trail; - - for (unsigned int i = 0; i < finger->trails_count; i++) - { - trail = &finger->trail_list[i]; - if (GNUNET_NO == trail->is_present) - continue; - - if (trail->trail_length > 0) - free_trail (trail); - trail->is_present = GNUNET_NO; - } - - finger->is_present = GNUNET_NO; - memset (&finger_table[finger_table_index], - 0, - sizeof (finger_table[finger_table_index])); -} - - -/** - * Add a new entry in finger table at finger_table_index. - * In case I am my own finger, then we don't have a trail. In case of a friend, - * we have a trail with unique id and '0' trail length. - * In case a finger is a friend, then increment the trails count of the friend. - * - * @param finger_identity Peer Identity of new finger - * @param finger_trail Trail to reach from me to finger (excluding both end points). - * @param finger_trail_length Total number of peers in @a finger_trail. - * @param trail_id Unique identifier of the trail. - * @param finger_table_index Index in finger table. - */ -static void -add_new_finger (const struct GNUNET_PeerIdentity *finger_identity, - const struct GNUNET_PeerIdentity *finger_trail, - unsigned int finger_trail_length, - const struct GNUNET_HashCode *trail_id, - unsigned int finger_table_index) -{ - struct FingerInfo *new_entry; - struct FriendInfo *first_trail_hop; - struct Trail *trail; - unsigned int i; - - new_entry = GNUNET_new (struct FingerInfo); - new_entry->finger_identity = *finger_identity; - new_entry->finger_table_index = finger_table_index; - new_entry->is_present = GNUNET_YES; - - /* If the new entry is my own identity. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - finger_identity)) - { - new_entry->trails_count = 0; - finger_table[finger_table_index] = *new_entry; - GNUNET_free (new_entry); - return; - } - - /* Finger is a friend. */ - if (0 == finger_trail_length) - { - new_entry->trail_list[0].trail_id = *trail_id; - new_entry->trails_count = 1; - new_entry->trail_list[0].is_present = GNUNET_YES; - new_entry->trail_list[0].trail_length = 0; - new_entry->trail_list[0].trail_head = NULL; - new_entry->trail_list[0].trail_tail = NULL; - finger_table[finger_table_index] = *new_entry; - GNUNET_assert (NULL != - (first_trail_hop = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - finger_identity))); - - first_trail_hop->trails_count++; - GNUNET_free (new_entry); - return; - } - - GNUNET_assert (NULL != - (first_trail_hop = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &finger_trail[0]))); - new_entry->trails_count = 1; - first_trail_hop->trails_count++; - /* Copy the finger trail into trail. */ - trail = &new_entry->trail_list[0]; - for(i = 0; i < finger_trail_length; i++) - { - struct Trail_Element *element = GNUNET_new (struct Trail_Element); - - element->next = NULL; - element->prev = NULL; - element->peer = finger_trail[i]; - GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head, - trail->trail_tail, - element); - } - - /* Add trail to trail list. */ - trail->trail_length = finger_trail_length; - trail->trail_id = *trail_id; - trail->is_present = GNUNET_YES; - finger_table[finger_table_index] = *new_entry; - GNUNET_free (new_entry); -} - - -/** - * Periodic task to verify current successor. There can be multiple trails to reach - * to successor, choose the shortest one and send verify successor message - * across that trail. - * - * @param cls closure for this task - */ -static void -send_verify_successor_message (void *cls) -{ - struct FriendInfo *target_friend; - struct Trail *trail; - struct Trail_Element *element; - unsigned int trail_length; - unsigned int i = 0; - struct FingerInfo *successor; - - successor = &finger_table[0]; - - /* This task will be scheduled when the result for Verify Successor is received. */ - send_verify_successor_task = NULL; - - /* When verify successor is being called for first time *for current context* - * cls will be NULL. If send_verify_successor_retry_task is not NO_TASK, we - * must cancel the retry task scheduled for verify_successor of previous - * context. - */ - if (NULL == cls) - { - /* FIXME: Here we are scheduling a new verify successor task, as we - got a new successor. But a send verify successor task may be in progress. - 1. We need to be sure that this is indeed a new successor. As this function - is called even if we add a new trail to reach t old successor. - 2. Assuming the new successor is different, then verify successor message - * to old successor may be following stages. - * --> Waiting for verify successor result. Don't wait anymore. there is - * no trail to reach from old successor to me, hence, routing - * lookup will fail. - * --> Waiting for notify confirmation. again don't wait for it. notify - * confirmation will not succeded. - */ - if (send_verify_successor_retry_task != NULL) - { - /* FIXME: Are we scheduling retry task as soon as we send verify message. - If yes then here before making this task, first check if the message - is for the same peer again. */ - struct VerifySuccessorContext *old_ctx = - GNUNET_SCHEDULER_cancel(send_verify_successor_retry_task); - /* old_ctx must not be NULL, as the retry task had been scheduled */ - GNUNET_assert(NULL != old_ctx); - GNUNET_free(old_ctx); - /* FIXME: Why don't we reset the task to NO_TASK here? */ - } - - struct VerifySuccessorContext *ctx; - ctx = GNUNET_new (struct VerifySuccessorContext); - - ctx->num_retries_scheduled++; - send_verify_successor_retry_task = - GNUNET_SCHEDULER_add_delayed (verify_successor_retry_time, - &send_verify_successor_message, - ctx); - } - else - { - /* This is a retry attempt for verify_successor for a previous context */ - struct VerifySuccessorContext *ctx; - - ctx = cls; - ctx->num_retries_scheduled++; - send_verify_successor_retry_task = - GNUNET_SCHEDULER_add_delayed (verify_successor_retry_time, - &send_verify_successor_message, - ctx); - } - - /* Among all the trails to reach to successor, select first one which is present.*/ - for (i = 0; i < successor->trails_count; i++) - { - trail = &successor->trail_list[i]; - if (GNUNET_YES == trail->is_present) - break; - } - - /* No valid trail found to reach to successor. */ - if (i == successor->trails_count) - return; - - GNUNET_assert(0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &successor->finger_identity)); - /* Trail stored at this index. */ - GNUNET_assert (GNUNET_YES == trail->is_present); - if (NULL == GDS_ROUTING_get_next_hop (&trail->trail_id, - GDS_ROUTING_SRC_TO_DEST)) - { - DEBUG (" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u", - GNUNET_i2s (&my_identity), - GNUNET_h2s (&trail->trail_id), - __LINE__); - GNUNET_break(0); - return; - } - trail_length = trail->trail_length; - if (trail_length > 0) - { - /* Copy the trail into peer list. */ - struct GNUNET_PeerIdentity peer_list[trail_length]; - - element = trail->trail_head; - for(i = 0; i < trail_length; i++) - { - peer_list[i] = element->peer; - element = element->next; - } - GNUNET_assert (NULL != (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &peer_list[0]))); - GDS_NEIGHBOURS_send_verify_successor_message (&my_identity, - &successor->finger_identity, - &trail->trail_id, - peer_list, - trail_length, - target_friend); - } - else - { - GNUNET_assert (NULL != (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &successor->finger_identity))); - GDS_NEIGHBOURS_send_verify_successor_message (&my_identity, - &successor->finger_identity, - &trail->trail_id, - NULL, - 0, - target_friend); - } -} - - -/** - * FIXME: should this be a periodic task, incrementing the search finger index? - * Update the current search finger index. - * @a finger_identity - * @a finger_table_index - */ -static void -update_current_search_finger_index (unsigned int finger_table_index) -{ - struct FingerInfo *successor; - - /* FIXME correct this: only move current index periodically */ - if (finger_table_index != current_search_finger_index) - return; - - successor = &finger_table[0]; - GNUNET_assert (GNUNET_YES == successor->is_present); - - /* We were looking for immediate successor. */ - if (0 == current_search_finger_index) - { - current_search_finger_index = PREDECESSOR_FINGER_ID; - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &successor->finger_identity)) - { - if (NULL == send_verify_successor_task) - { - send_verify_successor_task - = GNUNET_SCHEDULER_add_now (&send_verify_successor_message, - NULL); - } - } - return; - } - current_search_finger_index--; -} - - -/** - * Get the least significant bit set in val. - * - * @param val Value - * @return Position of first bit set, 65 in case of error. - */ -static unsigned int -find_set_bit (uint64_t val) -{ - uint64_t i; - unsigned int pos; - - i = 1; - pos = 0; - - while (!(i & val)) - { - i = i << 1; - pos++; - if (pos > 63) - { - GNUNET_break (0); - return 65; - } - } - - if (val/i != 1) - return 65; /* Some other bit was set to 1 as well. */ - - return pos; -} - - -/** - * Calculate finger_table_index from initial 64 bit finger identity value that - * we send in trail setup message. - * @param ultimate_destination_finger_value Value that we calculated from our - * identity and finger_table_index. - * @param is_predecessor Is the entry for predecessor or not? - * @return finger_table_index Value between 0 <= finger_table_index <= 64 - * finger_table_index > PREDECESSOR_FINGER_ID, if error occurs. - */ -static unsigned int -get_finger_table_index (uint64_t ultimate_destination_finger_value, - unsigned int is_predecessor) -{ - uint64_t my_id64; - uint64_t diff; - unsigned int finger_table_index; - - GNUNET_memcpy (&my_id64, &my_identity, sizeof (uint64_t)); - my_id64 = GNUNET_ntohll (my_id64); - - /* Is this a predecessor finger? */ - if (1 == is_predecessor) - { - diff = my_id64 - ultimate_destination_finger_value; - if (1 == diff) - finger_table_index = PREDECESSOR_FINGER_ID; - else - finger_table_index = PREDECESSOR_FINGER_ID + 1; //error value - - } - else - { - diff = ultimate_destination_finger_value - my_id64; - finger_table_index = find_set_bit (diff); - } - return finger_table_index; -} - - -/** - * Remove finger and its associated data structures from finger table. - * @param existing_finger Finger to be removed which is in finger table. - * @param finger_table_index Index in finger table where @a existing_finger - * is stored. - */ -static void -remove_existing_finger (struct FingerInfo *existing_finger, - unsigned int finger_table_index) -{ - GNUNET_assert (GNUNET_YES == existing_finger->is_present); - - /* If I am my own finger, then we have no trails. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity, - &my_identity)) - { - existing_finger->is_present = GNUNET_NO; - memset ((void *)&finger_table[finger_table_index], 0, - sizeof (finger_table[finger_table_index])); - return; - } - - /* For all other fingers, send trail teardown across all the trails to reach - finger, and free the finger. */ - send_all_finger_trails_teardown (existing_finger); - free_finger (existing_finger, finger_table_index); -} - - -/** - * Check if there is already an entry in finger_table at finger_table_index. - * We get the finger_table_index from 64bit finger value we got from the network. - * -- If yes, then select the closest finger. - * -- If new and existing finger are same, then check if you can store more - * trails. - * -- If yes then add trail, else keep the best trails to reach to the - * finger. - * -- If the new finger is closest, remove the existing entry, send trail - * teardown message across all the trails to reach the existing entry. - * Add the new finger. - * -- If new and existing finger are different, and existing finger is closest - * then do nothing. - * -- Update current_search_finger_index. - * @param finger_identity Peer Identity of new finger - * @param finger_trail Trail to reach the new finger - * @param finger_trail_length Total number of peers in @a new_finger_trail. - * @param is_predecessor Is this entry for predecessor in finger_table? - * @param finger_value 64 bit value of finger identity that we got from network. - * @param finger_trail_id Unique identifier of @finger_trail. - */ -static void -finger_table_add (const struct GNUNET_PeerIdentity *finger_identity, - const struct GNUNET_PeerIdentity *finger_trail, - unsigned int finger_trail_length, - unsigned int is_predecessor, - uint64_t finger_value, - const struct GNUNET_HashCode *finger_trail_id) -{ - struct FingerInfo *existing_finger; - const struct GNUNET_PeerIdentity *closest_peer; - struct FingerInfo *successor; - unsigned int finger_table_index; - - /* Get the finger_table_index corresponding to finger_value we got from network.*/ - finger_table_index = get_finger_table_index (finger_value, is_predecessor); - - /* Invalid finger_table_index. */ - if ((finger_table_index > PREDECESSOR_FINGER_ID)) - { - GNUNET_break_op (0); - return; - } - - /* Check if new entry is same as successor. */ - if ((0 != finger_table_index) && - (PREDECESSOR_FINGER_ID != finger_table_index)) - { - successor = &finger_table[0]; - if (GNUNET_NO == successor->is_present) - { - GNUNET_break (0); //ASSERTION FAILS HERE. FIXME - return; - } - if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity, - &successor->finger_identity)) - { - if (0 == fingers_round_count) - { - find_finger_trail_task_next_send_time = - GNUNET_TIME_STD_BACKOFF(find_finger_trail_task_next_send_time); - } - else - fingers_round_count--; - current_search_finger_index = 0; - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop - ("# FINGERS_COUNT"), (int64_t) total_fingers_found, - GNUNET_NO); - total_fingers_found = 0; - return; - } - - struct FingerInfo prev_finger; - prev_finger = finger_table[finger_table_index - 1]; - if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity, - &prev_finger.finger_identity)) - { - current_search_finger_index--; - return; - } - } - - total_fingers_found++; - existing_finger = &finger_table[finger_table_index]; - - /* No entry present in finger_table for given finger map index. */ - if (GNUNET_NO == existing_finger->is_present) - { - /* Shorten the trail if possible. */ - add_new_finger (finger_identity, - finger_trail, - finger_trail_length, - finger_trail_id, - finger_table_index); - update_current_search_finger_index (finger_table_index); - return; - } - - /* If existing entry and finger identity are not same. */ - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity, - finger_identity)) - { - closest_peer = select_closest_peer (&existing_finger->finger_identity, - finger_identity, - finger_value, - is_predecessor); - - /* If the new finger is the closest peer. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity, - closest_peer)) - { - remove_existing_finger (existing_finger, - finger_table_index); - add_new_finger (finger_identity, - finger_trail, - finger_trail_length, - finger_trail_id, - finger_table_index); - } - else - { - /* Existing finger is the closest one. We need to send trail teardown - across the trail setup in routing table of all the peers. */ - if (0 != GNUNET_CRYPTO_cmp_peer_identity (finger_identity, - &my_identity)) - { - if (finger_trail_length > 0) - GDS_NEIGHBOURS_send_trail_teardown (finger_trail_id, - GDS_ROUTING_SRC_TO_DEST, - &finger_trail[0]); - else - GDS_NEIGHBOURS_send_trail_teardown (finger_trail_id, - GDS_ROUTING_SRC_TO_DEST, - finger_identity); - } - } - } - else - { - /* If both new and existing entry are same as my_identity, then do nothing. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity, - &my_identity)) - { - return; - } - - /* If there is space to store more trails. */ - if (existing_finger->trails_count < MAXIMUM_TRAILS_PER_FINGER) - add_new_trail (existing_finger, - finger_trail, - finger_trail_length, - finger_trail_id); - else - select_and_replace_trail (existing_finger, - finger_trail, - finger_trail_length, - finger_trail_id); - } - update_current_search_finger_index (finger_table_index); - return; -} - - -/** - * Verify validity of P2P put messages. - * - * @param cls closure - * @param put the message - * @return #GNUNET_OK if the message is well-formed - */ -static int -check_dht_p2p_put (void *cls, - const struct PeerPutMessage *put) -{ - size_t msize; - uint32_t putlen; - - msize = ntohs (put->header.size); - putlen = ntohl (put->put_path_length); - if ((msize < - sizeof (struct PeerPutMessage) + - putlen * sizeof (struct GNUNET_PeerIdentity)) || - (putlen > - GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handler for P2P put messages. - * - * @param cls closure - * @param put the message - */ -static void -handle_dht_p2p_put (void *cls, - const struct PeerPutMessage *put) -{ - struct GNUNET_PeerIdentity *put_path; - struct GNUNET_PeerIdentity current_best_known_dest; - struct GNUNET_PeerIdentity best_known_dest; - struct GNUNET_HashCode received_intermediate_trail_id; - struct GNUNET_HashCode intermediate_trail_id; - struct GNUNET_PeerIdentity next_hop; - const struct GNUNET_PeerIdentity *next_routing_hop; - enum GNUNET_DHT_RouteOption options; - struct GNUNET_HashCode test_key; - struct Closest_Peer successor; - void *payload; - size_t msize; - uint32_t putlen = ntohl (put->put_path_length); - struct GNUNET_PeerIdentity pp[putlen + 1]; - uint32_t hop_count; - size_t payload_size; - uint64_t key_value; - - msize = ntohs (put->header.size); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - (int64_t) msize, - GNUNET_NO); - - current_best_known_dest = put->best_known_destination; - put_path = (struct GNUNET_PeerIdentity *) &put[1]; - payload = &put_path[putlen]; - options = ntohl (put->options); - received_intermediate_trail_id = put->intermediate_trail_id; - hop_count = ntohl(put->hop_count); - payload_size = msize - (sizeof (struct PeerPutMessage) + - putlen * sizeof (struct GNUNET_PeerIdentity)); - hop_count++; - switch (GNUNET_BLOCK_get_key (GDS_block_context, - ntohl (put->block_type), - payload, - payload_size, - &test_key)) - { - case GNUNET_YES: - if (0 != memcmp (&test_key, - &put->key, - sizeof (struct GNUNET_HashCode))) - { - char *put_s = GNUNET_strdup (GNUNET_h2s_full (&put->key)); - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "PUT with key `%s' for block with key %s\n", - put_s, - GNUNET_h2s_full (&test_key)); - GNUNET_free (put_s); - return; - } - break; - case GNUNET_NO: - GNUNET_break_op (0); - return; - case GNUNET_SYSERR: - /* cannot verify, good luck */ - break; - } - - if (ntohl (put->block_type) == GNUNET_BLOCK_TYPE_REGEX) /* FIXME: do for all tpyes */ - { - switch (GNUNET_BLOCK_evaluate (GDS_block_context, - ntohl (put->block_type), - NULL, - GNUNET_BLOCK_EO_NONE, - NULL, /* query */ - NULL, 0, /* xquery */ - payload, - payload_size)) - { - case GNUNET_BLOCK_EVALUATION_OK_MORE: - case GNUNET_BLOCK_EVALUATION_OK_LAST: - break; - - case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: - case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: - case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT: - case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: - case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: - case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: - default: - GNUNET_break_op (0); - return; - } - } - - /* Check if you are already a part of put path. */ - unsigned int i; - for (i = 0; i < putlen; i++) - { - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &put_path[i])) - { - putlen = i; - break; - } - } - - /* Add yourself to the list. */ - //if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE)) - if (1) - { - GNUNET_memcpy (pp, - put_path, - putlen * sizeof (struct GNUNET_PeerIdentity)); - pp[putlen] = my_identity; - putlen++; - } - else - { - putlen = 0; - } - GNUNET_memcpy (&key_value, - &put->key, - sizeof (uint64_t)); - key_value = GNUNET_ntohll (key_value); - successor = find_local_best_known_next_hop (key_value, - GDS_FINGER_TYPE_NON_PREDECESSOR); - next_hop = successor.next_hop; - intermediate_trail_id = successor.trail_id; - best_known_dest = successor.best_known_destination; - - if (0 != (GNUNET_CRYPTO_cmp_peer_identity (¤t_best_known_dest, - &my_identity))) - { - next_routing_hop = GDS_ROUTING_get_next_hop (&received_intermediate_trail_id, - GDS_ROUTING_SRC_TO_DEST); - if (NULL != next_routing_hop) - { - next_hop = *next_routing_hop; - intermediate_trail_id = received_intermediate_trail_id; - best_known_dest = current_best_known_dest; - } - } - - GDS_CLIENTS_process_put (options, - ntohl (put->block_type), - hop_count, - ntohl (put->desired_replication_level), - putlen, - pp, - GNUNET_TIME_absolute_ntoh (put->expiration_time), - &put->key, - payload, - payload_size); - - /* I am the final destination */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &best_known_dest)) - { - DEBUG ("\n PUT_REQUEST_SUCCESSFUL for key = %s", - GNUNET_h2s(&put->key)); - GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time), - &put->key, - putlen, - pp, - ntohl (put->block_type), - payload_size, - payload); - } - GDS_NEIGHBOURS_send_put (&put->key, - ntohl (put->block_type), - ntohl (put->options), - ntohl (put->desired_replication_level), - best_known_dest, - intermediate_trail_id, - &next_hop, - hop_count, - putlen, - pp, - GNUNET_TIME_absolute_ntoh (put->expiration_time), - payload, - payload_size); -} - - -/** - * Check integrity of @a get message. - * - * @param cls closure - * @param get the message - * @return #GNUNET_OK if @a get is well-formed - */ -static int -check_dht_p2p_get (void *cls, - const struct PeerGetMessage *get) -{ - uint32_t get_length; - size_t msize; - - msize = ntohs (get->header.size); - get_length = ntohl (get->get_path_length); - if ((msize < - sizeof (struct PeerGetMessage) + - get_length * sizeof (struct GNUNET_PeerIdentity)) || - (get_length > - GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * FIXME: Check for loop in the request. If you already are part of get path, - * then you need to reset the get path length. - * Core handler for p2p get requests. - * - * @param cls closure - * @param get the message - */ -static void -handle_dht_p2p_get (void *cls, - const struct PeerGetMessage *get) -{ - const struct GNUNET_PeerIdentity *get_path; - struct GNUNET_PeerIdentity best_known_dest; - struct GNUNET_PeerIdentity current_best_known_dest; - struct GNUNET_HashCode intermediate_trail_id; - struct GNUNET_HashCode received_intermediate_trail_id; - struct Closest_Peer successor; - struct GNUNET_PeerIdentity next_hop; - const struct GNUNET_PeerIdentity *next_routing_hop; - uint32_t get_length; - uint64_t key_value; - uint32_t hop_count; - size_t msize; - - msize = ntohs (get->header.size); - get_length = ntohl (get->get_path_length); - current_best_known_dest = get->best_known_destination; - received_intermediate_trail_id = get->intermediate_trail_id; - get_path = (const struct GNUNET_PeerIdentity *) &get[1]; - hop_count = get->hop_count; - hop_count++; - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - GNUNET_memcpy (&key_value, - &get->key, - sizeof (uint64_t)); - key_value = GNUNET_ntohll (key_value); - - /* Check if you are already a part of get path. */ - for (unsigned int i = 0; i < get_length; i++) - { - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &get_path[i])) - { - get_length = i; - break; - } - } - - /* Add yourself in the get path. */ - struct GNUNET_PeerIdentity gp[get_length + 1]; - GNUNET_memcpy (gp, - get_path, - get_length * sizeof (struct GNUNET_PeerIdentity)); - gp[get_length] = my_identity; - get_length = get_length + 1; - GDS_CLIENTS_process_get (get->options, - get->block_type, - hop_count, - get->desired_replication_level, - get->get_path_length, - gp, - &get->key); - - - successor = find_local_best_known_next_hop (key_value, - GDS_FINGER_TYPE_NON_PREDECESSOR); - next_hop = successor.next_hop; - best_known_dest = successor.best_known_destination; - intermediate_trail_id = successor.trail_id; - /* I am not the final destination. I am part of trail to reach final dest. */ - if (0 != (GNUNET_CRYPTO_cmp_peer_identity (¤t_best_known_dest, &my_identity))) - { - next_routing_hop = GDS_ROUTING_get_next_hop (&received_intermediate_trail_id, - GDS_ROUTING_SRC_TO_DEST); - if (NULL != next_routing_hop) - { - next_hop = *next_routing_hop; - best_known_dest = current_best_known_dest; - intermediate_trail_id = received_intermediate_trail_id; - } - } - - /* I am the final destination. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &best_known_dest)) - { - if (1 == get_length) - { - DEBUG ("\n GET_REQUEST DONE for key = %s", - GNUNET_h2s(&get->key)); - GDS_DATACACHE_handle_get (&get->key, - get->block_type, /* FIXME: endianess? */ - NULL, - 0, - NULL, - &get_cb, - NULL); - } - else - { - GDS_DATACACHE_handle_get (&get->key, - get->block_type, /* FIXME: endianess? */ - NULL, - 0, - NULL, - &get_cb, - &gp[get_length - 2]); - } - } - else - { - GDS_NEIGHBOURS_send_get (&get->key, - get->block_type, /* FIXME: endianess? */ - get->options, - get->desired_replication_level, - &best_known_dest, - &intermediate_trail_id, - &next_hop, - hop_count, - get_length, - gp); - } -} - - -/** - * Check validity of @a get_result message. - * - * @param cls closure - * @param get_result the message - * @return #GNUNET_OK if @a get_result is well-formed - */ -static int -check_dht_p2p_get_result (void *cls, - const struct PeerGetResultMessage *get_result) -{ - size_t msize; - unsigned int getlen; - unsigned int putlen; - - msize = ntohs (get_result->header.size); - getlen = ntohl (get_result->get_path_length); - putlen = ntohl (get_result->put_path_length); - if ((msize < - sizeof (struct PeerGetResultMessage) + - getlen * sizeof (struct GNUNET_PeerIdentity) + - putlen * sizeof (struct GNUNET_PeerIdentity)) || - (getlen > - GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity) || - (putlen > - GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handler for get result - * - * @param cls closure - * @param get_result the message - */ -static void -handle_dht_p2p_get_result (void *cls, - const struct PeerGetResultMessage *get_result) -{ - const struct GNUNET_PeerIdentity *get_path; - const struct GNUNET_PeerIdentity *put_path; - const void *payload; - size_t payload_size; - size_t msize; - unsigned int getlen; - unsigned int putlen; - int current_path_index; - - msize = ntohs (get_result->header.size); - getlen = ntohl (get_result->get_path_length); - putlen = ntohl (get_result->put_path_length); - DEBUG ("GET_RESULT FOR DATA_SIZE = %u\n", - (unsigned int) msize); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - put_path = (const struct GNUNET_PeerIdentity *) &get_result[1]; - get_path = &put_path[putlen]; - payload = (const void *) &get_path[getlen]; - payload_size = msize - (sizeof (struct PeerGetResultMessage) + - (getlen + putlen) * sizeof (struct GNUNET_PeerIdentity)); - - if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &get_path[0]))) - { - GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (get_result->expiration_time), - &get_result->key, - getlen, - get_path, - putlen, - put_path, - get_result->type, - payload_size, - payload); - return; - } - current_path_index = search_my_index (get_path, - getlen); - if (-1 == current_path_index) - { - DEBUG ("No entry found in get path.\n"); - GNUNET_break (0); - return; - } - if ((getlen + 1) == current_path_index) - { - DEBUG("Present twice in get path. Not allowed. \n"); - GNUNET_break (0); - return; - } - GDS_NEIGHBOURS_send_get_result (&get_result->key, - get_result->type, /* FIXME: endianess? */ - &get_path[current_path_index - 1], - &get_result->querying_peer, - putlen, - put_path, - getlen, - get_path, - GNUNET_TIME_absolute_ntoh (get_result->expiration_time), - payload, - payload_size); -} - - -/** - * Find the next hop to pass trail setup message. First find the local best known - * hop from your own identity, friends and finger. If you were part of trail, - * then get the next hop from routing table. Compare next_hop from routing table - * and local best known hop, and return the closest one to final_dest_finger_val - * @param final_dest_finger_val 64 bit value of finger identity - * @param intermediate_trail_id If you are part of trail to reach to some other - * finger, then it is the trail id to reach to - * that finger, else set to 0. - * @param is_predecessor Are we looking for closest successor or predecessor. - * @param source Source of trail setup message. - * @param current_dest In case you are part of trail, then finger to which - * we should forward the message. Else my own identity - * @return Closest Peer for @a final_dest_finger_val - */ -static struct Closest_Peer -get_local_best_known_next_hop (uint64_t final_dest_finger_val, - const struct GNUNET_HashCode *intermediate_trail_id, - unsigned int is_predecessor, - const struct GNUNET_PeerIdentity *source, - const struct GNUNET_PeerIdentity *current_dest) -{ - struct Closest_Peer peer; - - peer = find_local_best_known_next_hop (final_dest_finger_val, - is_predecessor); - - /* Am I just a part of a trail towards a finger (current_destination)? */ - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - current_dest) && - 0 != GNUNET_CRYPTO_cmp_peer_identity (&peer.best_known_destination, - current_dest)) - { - const struct GNUNET_PeerIdentity *closest_peer; - - /* Select best successor among one found locally and current_destination - * that we got from network.*/ - closest_peer = select_closest_peer (&peer.best_known_destination, - current_dest, - final_dest_finger_val, - is_predecessor); - - /* Is current dest (end point of the trail of which I am a part) closest_peer? */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (current_dest, - closest_peer)) - { - const struct GNUNET_PeerIdentity *next_hop; - - next_hop = GDS_ROUTING_get_next_hop (intermediate_trail_id, - GDS_ROUTING_SRC_TO_DEST); - /* next_hop NULL is a valid case. This intermediate trail id is set by - some other finger, and while this trail setup is in progress, that other - peer might have found a better trail ,and send trail teardown message - across the network. In case we got the trail teardown message first, - then next_hop will be NULL. A possible solution could be to keep track - * of all removed trail id, and be sure that there is no other reason . */ - if(NULL != next_hop) - { - peer.next_hop = *next_hop; - peer.best_known_destination = *current_dest; - peer.trail_id = *intermediate_trail_id; - } - } - } - return peer; -} - - -/** - * Check format of a PeerTrailSetupMessage. - * - * @param cls closure - * @param trail_setup the message - * @return #GNUNET_OK if @a trail_setup is well-formed - */ -static int -check_dht_p2p_trail_setup (void *cls, - const struct PeerTrailSetupMessage *trail_setup) -{ - size_t msize; - - msize = ntohs (trail_setup->header.size); - if ((msize - sizeof (struct PeerTrailSetupMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for PeerTrailSetupMessage. - * - * @param cls closure - * @param trail_setup the message - */ -static void -handle_dht_p2p_trail_setup (void *cls, - const struct PeerTrailSetupMessage *trail_setup) -{ - struct FriendInfo *friend = cls; - const struct GNUNET_PeerIdentity *trail_peer_list; - struct GNUNET_PeerIdentity current_dest; - struct FriendInfo *target_friend; - struct GNUNET_PeerIdentity source; - struct GNUNET_HashCode intermediate_trail_id; - struct GNUNET_HashCode trail_id; - unsigned int is_predecessor; - uint32_t trail_length; - uint64_t final_dest_finger_val; - int i; - size_t msize; - - msize = ntohs (trail_setup->header.size); - trail_length = (msize - sizeof (struct PeerTrailSetupMessage))/ - sizeof (struct GNUNET_PeerIdentity); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_setup[1]; - current_dest = trail_setup->best_known_destination; - trail_id = trail_setup->trail_id; - final_dest_finger_val - = GNUNET_ntohll (trail_setup->final_destination_finger_value); - source = trail_setup->source_peer; - is_predecessor = ntohl (trail_setup->is_predecessor); - intermediate_trail_id = trail_setup->intermediate_trail_id; - - /* Did the friend insert its ID in the trail list? */ - if ( (trail_length > 0) && - (0 != memcmp (&trail_peer_list[trail_length-1], - friend->id, - sizeof (struct GNUNET_PeerIdentity))) ) - { - GNUNET_break_op (0); - return; - } - - /* If I was the source and got the message back, then set trail length to 0.*/ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &source)) - { - trail_length = 0; - } - - /* Check if you are present in the trail seen so far? */ - for (i = 0; i < trail_length; i++) - { - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[i], - &my_identity)) - { - /* We will add ourself later in code, if NOT destination. */ - trail_length = i; - break; - } - } - - /* Is my routing table full? */ - if (GNUNET_YES == GDS_ROUTING_threshold_reached ()) - { - target_friend - = (trail_length > 0) - ? GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail_peer_list[trail_length - 1]) - : GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &source); - if (NULL == target_friend) - { - DEBUG ("\n friend not found"); - GNUNET_break(0); - return; - } - GDS_NEIGHBOURS_send_trail_rejection (&source, - final_dest_finger_val, - &my_identity, - is_predecessor, - trail_peer_list, - trail_length, - &trail_id, - target_friend, - CONGESTION_TIMEOUT); - return; - } - - /* Get the next hop to forward the trail setup request. */ - struct Closest_Peer next_peer - = get_local_best_known_next_hop (final_dest_finger_val, - &intermediate_trail_id, - is_predecessor, - &source, - ¤t_dest); - - /* Am I the final destination? */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&next_peer.best_known_destination, - &my_identity)) - { - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&source, - &my_identity)) - { - finger_table_add (&my_identity, - NULL, - 0, - is_predecessor, - final_dest_finger_val, - &trail_id); - return; - } - - target_friend - = (trail_length > 0) - ? GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail_peer_list[trail_length-1]) - : GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &source); - if (NULL == target_friend) - { - GNUNET_break_op (0); - return; - } - GDS_ROUTING_add (&trail_id, - target_friend->id, - &my_identity); - GDS_NEIGHBOURS_send_trail_setup_result (&source, - &my_identity, - target_friend, - trail_length, - trail_peer_list, - is_predecessor, - final_dest_finger_val, - &trail_id); - return; - } - /* I'm not the final destination. */ - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_peer.next_hop); - if (NULL == target_friend) - { - DEBUG ("\n target friend not found for peer = %s", - GNUNET_i2s(&next_peer.next_hop)); - GNUNET_break (0); - return; - } - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &source)) - { - /* Add yourself to list of peers. */ - struct GNUNET_PeerIdentity peer_list[trail_length + 1]; - - GNUNET_memcpy (peer_list, - trail_peer_list, - trail_length * sizeof (struct GNUNET_PeerIdentity)); - peer_list[trail_length] = my_identity; - GDS_NEIGHBOURS_send_trail_setup (&source, - final_dest_finger_val, - &next_peer.best_known_destination, - target_friend, - trail_length + 1, - peer_list, - is_predecessor, - &trail_id, - &next_peer.trail_id); - return; - } - GDS_NEIGHBOURS_send_trail_setup (&source, - final_dest_finger_val, - &next_peer.best_known_destination, - target_friend, - 0, - NULL, - is_predecessor, - &trail_id, - &next_peer.trail_id); -} - - -/** - * Validate format of trail setup result messages. - * - * @param closure - * @param trail_result the message - * @return #GNUNET_OK if @a trail_result is well-formed - */ -static int -check_dht_p2p_trail_setup_result (void *cls, - const struct PeerTrailSetupResultMessage *trail_result) -{ - size_t msize; - - msize = ntohs (trail_result->header.size); - if ((msize - sizeof (struct PeerTrailSetupResultMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for p2p trail setup result messages. - * - * @param closure - * @param trail_result the message - */ -static void -handle_dht_p2p_trail_setup_result (void *cls, - const struct PeerTrailSetupResultMessage *trail_result) -{ - struct FriendInfo *friend = cls; - const struct GNUNET_PeerIdentity *trail_peer_list; - struct GNUNET_PeerIdentity next_hop; - struct FriendInfo *target_friend; - struct GNUNET_PeerIdentity querying_peer; - struct GNUNET_PeerIdentity finger_identity; - uint32_t trail_length; - uint64_t ultimate_destination_finger_value; - uint32_t is_predecessor; - struct GNUNET_HashCode trail_id; - int my_index; - size_t msize; - - msize = ntohs (trail_result->header.size); - trail_length = (msize - sizeof (struct PeerTrailSetupResultMessage))/ - sizeof (struct GNUNET_PeerIdentity); - - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - - is_predecessor = ntohl (trail_result->is_predecessor); - querying_peer = trail_result->querying_peer; - finger_identity = trail_result->finger_identity; - trail_id = trail_result->trail_id; - trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_result[1]; - ultimate_destination_finger_value - = GNUNET_ntohll (trail_result->ultimate_destination_finger_value); - - /* Am I the one who initiated the query? */ - if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&querying_peer, - &my_identity))) - { - /* Check that you got the message from the correct peer. */ - if (trail_length > 0) - { - GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[0], - friend->id)); - } - else - { - GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger_identity, - friend->id)); - } - GDS_ROUTING_add (&trail_id, - &my_identity, - friend->id); - finger_table_add (&finger_identity, - trail_peer_list, - trail_length, - is_predecessor, - ultimate_destination_finger_value, - &trail_id); - return; - } - - /* Get my location in the trail. */ - my_index = search_my_index (trail_peer_list, - trail_length); - if (-1 == my_index) - { - DEBUG ("Not found in trail\n"); - GNUNET_break_op(0); - return; - } - //TODO; return -2. - if ((trail_length + 1) == my_index) - { - DEBUG ("Found twice in trail.\n"); - GNUNET_break_op(0); - return; - } - - //TODO; Refactor code here and above to check if sender peer is correct - if (my_index == 0) - { - if (trail_length > 1) - GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[1], - friend->id)); - else - GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger_identity, - friend->id)); - next_hop = trail_result->querying_peer; - } - else - { - if (my_index == trail_length - 1) - { - GNUNET_assert (0 == - GNUNET_CRYPTO_cmp_peer_identity (&finger_identity, - friend->id)); - } - else - GNUNET_assert (0 == - GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[my_index + 1], - friend->id)); - next_hop = trail_peer_list[my_index - 1]; - } - - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_hop); - if (NULL == target_friend) - { - GNUNET_break_op (0); - return; - } - GDS_ROUTING_add (&trail_id, - &next_hop, - friend->id); - GDS_NEIGHBOURS_send_trail_setup_result (&querying_peer, - &finger_identity, - target_friend, - trail_length, - trail_peer_list, - is_predecessor, - ultimate_destination_finger_value, - &trail_id); -} - - -/** - * Invert the trail. - * - * @param trail Trail to be inverted - * @param trail_length Total number of peers in the trail. - * @return Updated trail - */ -static struct GNUNET_PeerIdentity * -invert_trail (const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length) -{ - int i; - int j; - struct GNUNET_PeerIdentity *inverted_trail; - - inverted_trail = GNUNET_new_array (trail_length, - struct GNUNET_PeerIdentity); - i = 0; - j = trail_length - 1; - while (i < trail_length) - { - inverted_trail[i] = trail[j]; - i++; - j--; - } - - GNUNET_assert (NULL != - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &inverted_trail[0])); - return inverted_trail; -} - - -/** - * Return the shortest trail among all the trails to reach to finger from me. - * - * @param finger Finger - * @param shortest_trail_length[out] Trail length of shortest trail from me - * to @a finger - * @return Shortest trail. - */ -static struct GNUNET_PeerIdentity * -get_shortest_trail (struct FingerInfo *finger, - unsigned int *trail_length) -{ - struct Trail *trail; - unsigned int flag = 0; - unsigned int shortest_trail_index = 0; - int shortest_trail_length = -1; - struct Trail_Element *trail_element; - struct GNUNET_PeerIdentity *trail_list; - unsigned int i; - - /* Get the shortest trail to reach to current successor. */ - for (i = 0; i < finger->trails_count; i++) - { - trail = &finger->trail_list[i]; - - if (0 == flag) - { - shortest_trail_index = i; - shortest_trail_length = trail->trail_length; - flag = 1; - continue; - } - - if (shortest_trail_length > trail->trail_length) - { - shortest_trail_index = i; - shortest_trail_length = trail->trail_length; - } - continue; - } - - /* Copy the shortest trail and return. */ - trail = &finger->trail_list[shortest_trail_index]; - trail_element = trail->trail_head; - - trail_list = GNUNET_new_array (shortest_trail_length, - struct GNUNET_PeerIdentity); - - for (i = 0; i < shortest_trail_length; i++,trail_element = trail_element->next) - { - trail_list[i] = trail_element->peer; - } - - GNUNET_assert(shortest_trail_length != -1); - - *trail_length = shortest_trail_length; - return trail_list; -} - - -/** - * Check if @a trail_1 and @a trail_2 have any common element. If yes then join - * them at common element. @a trail_1 always preceeds @a trail_2 in joined trail. - * - * @param trail_1 Trail from source to me, NOT including endpoints. - * @param trail_1_len Total number of peers @a trail_1 - * @param trail_2 Trail from me to current predecessor, NOT including endpoints. - * @param trail_2_len Total number of peers @a trail_2 - * @param joined_trail_len Total number of peers in combined trail of @a trail_1 - * @a trail_2. - * @return Joined trail. - */ -static struct GNUNET_PeerIdentity * -check_for_duplicate_entries (const struct GNUNET_PeerIdentity *trail_1, - unsigned int trail_1_len, - const struct GNUNET_PeerIdentity *trail_2, - unsigned int trail_2_len, - unsigned int *joined_trail_len) -{ - struct GNUNET_PeerIdentity *joined_trail; - unsigned int i; - unsigned int j; - unsigned int k; - - for (i = 0; i < trail_1_len; i++) - { - for (j = 0; j < trail_2_len; j++) - { - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&trail_1[i], - &trail_2[j])) - continue; - - *joined_trail_len = i + (trail_2_len - j); - joined_trail = GNUNET_new_array (*joined_trail_len, - struct GNUNET_PeerIdentity); - - - /* Copy all the elements from 0 to i into joined_trail. */ - for(k = 0; k < ( i+1); k++) - { - joined_trail[k] = trail_1[k]; - } - - /* Increment j as entry stored is same as entry stored at i*/ - j = j+1; - - /* Copy all the elements from j to trail_2_len-1 to joined trail.*/ - while(k <= (*joined_trail_len - 1)) - { - joined_trail[k] = trail_2[j]; - j++; - k++; - } - - return joined_trail; - } - } - - /* Here you should join the trails. */ - *joined_trail_len = trail_1_len + trail_2_len + 1; - joined_trail = GNUNET_new_array (*joined_trail_len, - struct GNUNET_PeerIdentity); - - - for(i = 0; i < trail_1_len;i++) - { - joined_trail[i] = trail_1[i]; - } - - joined_trail[i] = my_identity; - i++; - - for (j = 0; i < *joined_trail_len; i++,j++) - { - joined_trail[i] = trail_2[j]; - } - - return joined_trail; -} - - -/** - * Return the trail from source to my current predecessor. Check if source - * is already part of the this trail, if yes then return the shorten trail. - * - * @param current_trail Trail from source to me, NOT including the endpoints. - * @param current_trail_length Number of peers in @a current_trail. - * @param trail_src_to_curr_pred_length[out] Number of peers in trail from - * source to my predecessor, NOT including - * the endpoints. - * @return Trail from source to my predecessor. - */ -static struct GNUNET_PeerIdentity * -get_trail_src_to_curr_pred (struct GNUNET_PeerIdentity source_peer, - const struct GNUNET_PeerIdentity *trail_src_to_me, - unsigned int trail_src_to_me_len, - unsigned int *trail_src_to_curr_pred_length) -{ - struct GNUNET_PeerIdentity *trail_me_to_curr_pred; - struct GNUNET_PeerIdentity *trail_src_to_curr_pred; - unsigned int trail_me_to_curr_pred_length; - struct FingerInfo *current_predecessor; - int i; - unsigned int j; - unsigned int len; - - current_predecessor = &finger_table[PREDECESSOR_FINGER_ID]; - - /* Check if trail_src_to_me contains current_predecessor. */ - for (i = 0; i < trail_src_to_me_len; i++) - { - if (0 != GNUNET_CRYPTO_cmp_peer_identity(&trail_src_to_me[i], - ¤t_predecessor->finger_identity)) - continue; - - - *trail_src_to_curr_pred_length = i; - - if(0 == i) - return NULL; - - trail_src_to_curr_pred = GNUNET_new_array (*trail_src_to_curr_pred_length, - struct GNUNET_PeerIdentity); - for (j = 0; j < i; j++) - trail_src_to_curr_pred[j] = trail_src_to_me[j]; - return trail_src_to_curr_pred; - } - - - trail_me_to_curr_pred = get_shortest_trail (current_predecessor, - &trail_me_to_curr_pred_length); - - /* Check if trail contains the source_peer. */ - for (i = trail_me_to_curr_pred_length - 1; i >= 0; i--) - { - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&source_peer, - &trail_me_to_curr_pred[i])) - continue; - - /* Source is NOT part of trail. */ - i++; - - /* Source is the last element in the trail to reach to my pred. - Source is direct friend of the pred. */ - if (trail_me_to_curr_pred_length == i) - { - *trail_src_to_curr_pred_length = 0; - GNUNET_free_non_null (trail_me_to_curr_pred); - return NULL; - } - - *trail_src_to_curr_pred_length = trail_me_to_curr_pred_length - i; - trail_src_to_curr_pred = GNUNET_new_array (*trail_src_to_curr_pred_length, - struct GNUNET_PeerIdentity); - - - for (j = 0; j < *trail_src_to_curr_pred_length; i++,j++) - trail_src_to_curr_pred[j] = trail_me_to_curr_pred[i]; - GNUNET_free_non_null (trail_me_to_curr_pred); - return trail_src_to_curr_pred; - } - - trail_src_to_curr_pred = check_for_duplicate_entries (trail_src_to_me, - trail_src_to_me_len, - trail_me_to_curr_pred, - trail_me_to_curr_pred_length, - &len); - *trail_src_to_curr_pred_length = len; - GNUNET_free_non_null(trail_me_to_curr_pred); - return trail_src_to_curr_pred; -} - - -/** - * Add finger as your predecessor. To add, first generate a new trail id, invert - * the trail to get the trail from me to finger, add an entry in your routing - * table, send add trail message to peers which are part of trail from me to - * finger and add finger in finger table. - * - * @param finger - * @param trail - * @param trail_length - */ -static void -update_predecessor (const struct GNUNET_PeerIdentity *finger, - const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length) -{ - struct GNUNET_HashCode trail_to_new_predecessor_id; - struct GNUNET_PeerIdentity *trail_to_new_predecessor; - struct FriendInfo *target_friend; - - /* Generate trail id for trail from me to new predecessor = finger. */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, - &trail_to_new_predecessor_id, - sizeof (trail_to_new_predecessor_id)); - - if (0 == trail_length) - { - trail_to_new_predecessor = NULL; - GDS_ROUTING_add (&trail_to_new_predecessor_id, - &my_identity, - finger); - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - finger); - if (NULL == target_friend) - { - GNUNET_break (0); - return; - } - } - else - { - /* Invert the trail to get the trail from me to finger, NOT including the - endpoints.*/ - GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail[trail_length-1])); - trail_to_new_predecessor = invert_trail (trail, - trail_length); - - /* Add an entry in your routing table. */ - GDS_ROUTING_add (&trail_to_new_predecessor_id, - &my_identity, - &trail_to_new_predecessor[0]); - - GNUNET_assert (NULL != (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail_to_new_predecessor[0]))); - } - - /* Add entry in routing table of all peers that are part of trail from me - to finger, including finger. */ - GDS_NEIGHBOURS_send_add_trail (&my_identity, - finger, - &trail_to_new_predecessor_id, - trail_to_new_predecessor, - trail_length, - target_friend); - - add_new_finger (finger, - trail_to_new_predecessor, - trail_length, - &trail_to_new_predecessor_id, - PREDECESSOR_FINGER_ID); - GNUNET_free_non_null (trail_to_new_predecessor); -} - - -/** - * Check if you already have a predecessor. If not then add finger as your - * predecessor. If you have predecessor, then compare two peer identites. - * If finger is correct predecessor, then remove the old entry, add finger in - * finger table and send add_trail message to add the trail in the routing - * table of all peers which are part of trail to reach from me to finger. - * @param finger New peer which may be our predecessor. - * @param trail List of peers to reach from @finger to me. - * @param trail_length Total number of peer in @a trail. - */ -static void -compare_and_update_predecessor (const struct GNUNET_PeerIdentity *finger, - const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length) -{ - struct FingerInfo *current_predecessor; - const struct GNUNET_PeerIdentity *closest_peer; - uint64_t predecessor_value; - unsigned int is_predecessor = 1; - - current_predecessor = &finger_table[PREDECESSOR_FINGER_ID]; - GNUNET_assert (0 != GNUNET_CRYPTO_cmp_peer_identity (finger, - &my_identity)); - - /* No predecessor. Add finger as your predecessor. */ - if (GNUNET_NO == current_predecessor->is_present) - { - update_predecessor (finger, - trail, - trail_length); - return; - } - - if (0 == GNUNET_CRYPTO_cmp_peer_identity (¤t_predecessor->finger_identity, - finger)) - { - return; - } - - predecessor_value = compute_finger_identity_value (PREDECESSOR_FINGER_ID); - closest_peer = select_closest_peer (finger, - ¤t_predecessor->finger_identity, - predecessor_value, - is_predecessor); - - /* Finger is the closest predecessor. Remove the existing one and add the new - one. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (closest_peer, - finger)) - { - remove_existing_finger (current_predecessor, - PREDECESSOR_FINGER_ID); - update_predecessor (finger, - trail, - trail_length); - return; - } -} - - -/** - * Check format of a p2p verify successor messages. - * - * @param cls closure - * @param vsm the message - * @return #GNUNET_OK if @a vsm is well-formed - */ -static int -check_dht_p2p_verify_successor (void *cls, - const struct PeerVerifySuccessorMessage *vsm) -{ - size_t msize; - - msize = ntohs (vsm->header.size); - if ((msize - sizeof (struct PeerVerifySuccessorMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for p2p verify successor messages. - * - * @param cls closure - * @param vsm the message - */ -static void -handle_dht_p2p_verify_successor (void *cls, - const struct PeerVerifySuccessorMessage *vsm) -{ - struct FriendInfo *friend = cls; - struct GNUNET_HashCode trail_id; - struct GNUNET_PeerIdentity successor; - struct GNUNET_PeerIdentity source_peer; - struct GNUNET_PeerIdentity *trail; - const struct GNUNET_PeerIdentity *next_hop; - struct FingerInfo current_predecessor; - struct FriendInfo *target_friend; - unsigned int trail_src_to_curr_pred_len = 0; - struct GNUNET_PeerIdentity *trail_src_to_curr_pred; - unsigned int trail_length; - size_t msize; - - msize = ntohs (vsm->header.size); - trail_length = (msize - sizeof (struct PeerVerifySuccessorMessage))/ - sizeof (struct GNUNET_PeerIdentity); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - - trail_id = vsm->trail_id; - source_peer = vsm->source_peer; - successor = vsm->successor; - trail = (struct GNUNET_PeerIdentity *)&vsm[1]; - - /* I am NOT the successor of source_peer. Pass the message to next_hop on - * the trail. */ - if (0 != (GNUNET_CRYPTO_cmp_peer_identity (&successor, - &my_identity))) - { - next_hop = GDS_ROUTING_get_next_hop (&trail_id, - GDS_ROUTING_SRC_TO_DEST); - if (NULL == next_hop) - return; - - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - next_hop); - if (NULL == target_friend) - { - GNUNET_break_op(0); - return; - } - GDS_NEIGHBOURS_send_verify_successor_message (&source_peer, - &successor, - &trail_id, - trail, - trail_length, - target_friend); - return; - } - - /* I am the destination of this message. */ - /* Check if the source_peer could be our predecessor and if yes then update - * it. */ - compare_and_update_predecessor (&source_peer, - trail, - trail_length); - current_predecessor = finger_table[PREDECESSOR_FINGER_ID]; - - /* Is source of this message NOT my predecessor. */ - if (0 != (GNUNET_CRYPTO_cmp_peer_identity (¤t_predecessor.finger_identity, - &source_peer))) - { - trail_src_to_curr_pred - = get_trail_src_to_curr_pred (source_peer, - trail, - trail_length, - &trail_src_to_curr_pred_len); - } - else - { - trail_src_to_curr_pred_len = trail_length; - trail_src_to_curr_pred = GNUNET_new_array (trail_src_to_curr_pred_len, - struct GNUNET_PeerIdentity); - - for (unsigned int i = 0; i < trail_src_to_curr_pred_len; i++) - { - trail_src_to_curr_pred[i] = trail[i]; - } - } - - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - friend->id))); - GDS_NEIGHBOURS_send_verify_successor_result (&source_peer, - &my_identity, - ¤t_predecessor.finger_identity, - &trail_id, - trail_src_to_curr_pred, - trail_src_to_curr_pred_len, - GDS_ROUTING_DEST_TO_SRC, - target_friend); - GNUNET_free_non_null (trail_src_to_curr_pred); -} - - -/** - * If the trail from me to my probable successor contains a friend not - * at index 0, then we can shorten the trail. - * - * @param probable_successor Peer which is our probable successor - * @param trail_me_to_probable_successor Peers in path from me to my probable - * successor, NOT including the endpoints. - * @param trail_me_to_probable_successor_len Total number of peers in - * @a trail_me_to_probable_succesor. - * @return Updated trail, if any friend found. - * Else the trail_me_to_probable_successor. - */ -const struct GNUNET_PeerIdentity * -check_trail_me_to_probable_succ (const struct GNUNET_PeerIdentity *probable_successor, - const struct GNUNET_PeerIdentity *trail_me_to_probable_successor, - unsigned int trail_me_to_probable_successor_len, - unsigned int *trail_to_new_successor_length) -{ - unsigned int i; - unsigned int j; - struct GNUNET_PeerIdentity *trail_to_new_successor; - - /* Probable successor is a friend */ - if (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - probable_successor)) - { - trail_to_new_successor = NULL; - *trail_to_new_successor_length = 0; - return trail_to_new_successor; - } - - /* Is there any friend of yours in this trail. */ - if (trail_me_to_probable_successor_len > 1) - { - for (i = trail_me_to_probable_successor_len - 1; i > 0; i--) - { - if (NULL == GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail_me_to_probable_successor[i])) - continue; - - *trail_to_new_successor_length = (trail_me_to_probable_successor_len - i); - trail_to_new_successor = GNUNET_new_array (*trail_to_new_successor_length, - struct GNUNET_PeerIdentity); - for (j = 0; j < *trail_to_new_successor_length; i++,j++) - { - trail_to_new_successor[j] = trail_me_to_probable_successor[i]; - } - - return trail_to_new_successor; - } - } - - *trail_to_new_successor_length = trail_me_to_probable_successor_len; - return trail_me_to_probable_successor; -} - - -// TODO: Move up -struct SendNotifyContext -{ - struct GNUNET_PeerIdentity source_peer; - struct GNUNET_PeerIdentity successor; - struct GNUNET_PeerIdentity *successor_trail; - unsigned int successor_trail_length; - struct GNUNET_HashCode succesor_trail_id; - struct FriendInfo *target_friend; - unsigned int num_retries_scheduled; -}; - - -void -send_notify_new_successor (void *cls); - - -/** - * Check if the peer which sent us verify successor result message is still ours - * successor or not. If not, then compare existing successor and probable successor. - * In case probable successor is the correct successor, remove the existing - * successor. Add probable successor as new successor. Send notify new successor - * message to new successor. - * @param curr_succ Peer to which we sent the verify successor message. It may - * or may not be our real current successor, as we may have few iterations of - * find finger trail task. - * @param probable_successor Peer which should be our successor accroding to @a - * curr_succ - * @param trail List of peers to reach from me to @a probable successor, NOT including - * endpoints. - * @param trail_length Total number of peers in @a trail. - */ -static void -compare_and_update_successor (const struct GNUNET_PeerIdentity *curr_succ, - const struct GNUNET_PeerIdentity *probable_successor, - const struct GNUNET_PeerIdentity *trail, - unsigned int trail_length) -{ - struct FingerInfo *current_successor; - const struct GNUNET_PeerIdentity *closest_peer; - struct GNUNET_HashCode trail_id; - const struct GNUNET_PeerIdentity *trail_me_to_probable_succ; - struct FriendInfo *target_friend; - unsigned int trail_me_to_probable_succ_len; - unsigned int is_predecessor = 0; - uint64_t successor_value; - struct SendNotifyContext *notify_ctx; - - current_successor = &finger_table[0]; - successor_value = compute_finger_identity_value(0); - - /* If probable successor is same as current_successor, do nothing. */ - if(0 == GNUNET_CRYPTO_cmp_peer_identity (probable_successor, - ¤t_successor->finger_identity)) - { - if ((NULL != GDS_stats)) - { - char *my_id_str; - uint64_t succ; - char *key; - uint64_t my_id; - GNUNET_memcpy (&my_id, &my_identity, sizeof(uint64_t)); - my_id_str = GNUNET_strdup (GNUNET_i2s_full (&my_identity)); - GNUNET_memcpy (&succ, - ¤t_successor->finger_identity, - sizeof(uint64_t)); - succ = GNUNET_ntohll(succ); - GNUNET_asprintf (&key, - "XDHT:%s:", - my_id_str); - GNUNET_free (my_id_str); - - GNUNET_STATISTICS_set (GDS_stats, key, succ, 0); - GNUNET_free (key); - } - if (send_verify_successor_task == NULL) - send_verify_successor_task = - GNUNET_SCHEDULER_add_delayed(verify_successor_next_send_time, - &send_verify_successor_message, - NULL); - return; - } - closest_peer = select_closest_peer (probable_successor, - ¤t_successor->finger_identity, - successor_value, - is_predecessor); - - /* If the current_successor in the finger table is closest, then do nothing. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (closest_peer, - ¤t_successor->finger_identity)) - { - //FIXME: Is this a good place to return the stats. - if ((NULL != GDS_stats)) - { - char *my_id_str; - uint64_t succ; - char *key; - - my_id_str = GNUNET_strdup (GNUNET_i2s_full (&my_identity)); - GNUNET_memcpy(&succ, ¤t_successor->finger_identity, sizeof(uint64_t)); - GNUNET_asprintf (&key, "XDHT:%s:", my_id_str); - GNUNET_free (my_id_str); - GNUNET_STATISTICS_set (GDS_stats, key, succ, 0); - GNUNET_free (key); - } - - if(0 == successor_times) - { -// successor_times = 3; - verify_successor_next_send_time = - GNUNET_TIME_STD_BACKOFF (verify_successor_next_send_time); - } - else - successor_times--; - - - if (send_verify_successor_task == NULL) - send_verify_successor_task = - GNUNET_SCHEDULER_add_delayed (verify_successor_next_send_time, - &send_verify_successor_message, - NULL); - return; - } - - /* Probable successor is the closest peer.*/ - if(trail_length > 0) - { - GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail[0])); - } - else - { - GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - probable_successor)); - } - - trail_me_to_probable_succ_len = 0; - trail_me_to_probable_succ = check_trail_me_to_probable_succ (probable_successor, - trail, - trail_length, - &trail_me_to_probable_succ_len); - - /* Remove the existing successor. */ - remove_existing_finger (current_successor, 0); - /* Generate a new trail id to reach to your new successor. */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, - &trail_id, - sizeof (trail_id)); - - if (trail_me_to_probable_succ_len > 0) - { - GDS_ROUTING_add (&trail_id, - &my_identity, - &trail_me_to_probable_succ[0]); - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &trail_me_to_probable_succ[0]))); - } - else - { - GDS_ROUTING_add (&trail_id, - &my_identity, - probable_successor); - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - probable_successor))); - } - - add_new_finger (probable_successor, - trail_me_to_probable_succ, - trail_me_to_probable_succ_len, - &trail_id, - 0); - - notify_ctx = GNUNET_new (struct SendNotifyContext); - - notify_ctx->source_peer = my_identity; - notify_ctx->successor = *probable_successor; - notify_ctx->successor_trail = GNUNET_new_array (trail_me_to_probable_succ_len, - struct GNUNET_PeerIdentity); - GNUNET_memcpy (notify_ctx->successor_trail, - trail_me_to_probable_succ, - sizeof(struct GNUNET_PeerIdentity) * trail_me_to_probable_succ_len); - notify_ctx->successor_trail_length = trail_me_to_probable_succ_len; - notify_ctx->succesor_trail_id = trail_id; - notify_ctx->target_friend = target_friend; - notify_ctx->num_retries_scheduled = 0; - - // TODO: Check if we should verify before schedule if already scheduled. - GNUNET_SCHEDULER_add_now (&send_notify_new_successor, - notify_ctx); -} - - -void -send_notify_new_successor (void *cls) -{ - struct SendNotifyContext *ctx = cls; - - GDS_NEIGHBOURS_send_notify_new_successor (&ctx->source_peer, - &ctx->successor, - ctx->successor_trail, - ctx->successor_trail_length, - &ctx->succesor_trail_id, - ctx->target_friend); - - if ( (0 == ctx->num_retries_scheduled) && - (send_notify_new_successor_retry_task != NULL) ) - { - // Result from previous notify successos hasn't arrived, so the retry task - // hasn't been cancelled! Already a new notify successor must be called. - // We will cancel the retry request. - struct SendNotifyContext *old_notify_ctx; - - old_notify_ctx = GNUNET_SCHEDULER_cancel(send_notify_new_successor_retry_task); - GNUNET_free (old_notify_ctx->successor_trail); - GNUNET_free (old_notify_ctx); - send_notify_new_successor_retry_task = NULL; - } - - ctx->num_retries_scheduled++; - send_notify_new_successor_retry_task - = GNUNET_SCHEDULER_add_delayed (notify_successor_retry_time, - &send_notify_new_successor, - cls); -} - - -/** - * Check integrity of verify successor result messages. - * - * @param cls closure - * @param vsrm the message - * @return #GNUNET_OK if @a vrsm is well-formed - */ -static int -check_dht_p2p_verify_successor_result (void *cls, - const struct PeerVerifySuccessorResultMessage *vsrm) -{ - size_t msize; - - msize = ntohs (vsrm->header.size); - if ((msize - sizeof (struct PeerVerifySuccessorResultMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for p2p verify successor result messages. - * - * @param cls closure - * @param vsrm the message - */ -static void -handle_dht_p2p_verify_successor_result (void *cls, - const struct PeerVerifySuccessorResultMessage *vsrm) -{ - enum GDS_ROUTING_trail_direction trail_direction; - struct GNUNET_PeerIdentity querying_peer; - struct GNUNET_HashCode trail_id; - const struct GNUNET_PeerIdentity *next_hop; - struct FriendInfo *target_friend; - struct GNUNET_PeerIdentity probable_successor; - struct GNUNET_PeerIdentity current_successor; - const struct GNUNET_PeerIdentity *trail; - unsigned int trail_length; - size_t msize; - - msize = ntohs (vsrm->header.size); - trail_length = (msize - sizeof (struct PeerVerifySuccessorResultMessage)) - / sizeof (struct GNUNET_PeerIdentity); - - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - - trail = (const struct GNUNET_PeerIdentity *) &vsrm[1]; - querying_peer = vsrm->querying_peer; - trail_direction = ntohl (vsrm->trail_direction); - trail_id = vsrm->trail_id; - probable_successor = vsrm->probable_successor; - current_successor = vsrm->current_successor; - - /* Am I the querying_peer? */ - if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&querying_peer, - &my_identity))) - { - /* Cancel Retry Task */ - if (NULL != send_verify_successor_retry_task) - { - struct VerifySuccessorContext *ctx; - - ctx = GNUNET_SCHEDULER_cancel (send_verify_successor_retry_task); - GNUNET_free (ctx); - send_verify_successor_retry_task = NULL; - } - compare_and_update_successor (¤t_successor, - &probable_successor, - trail, - trail_length); - return; - } - - /*If you are not the querying peer then pass on the message */ - if(NULL == (next_hop = - GDS_ROUTING_get_next_hop (&trail_id, - trail_direction))) - { - /* Here it may happen that source peer has found a new successor, and removed - the trail, Hence no entry found in the routing table. Fail silently.*/ - DEBUG (" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u", - GNUNET_i2s (&my_identity), - GNUNET_h2s (&trail_id), - __LINE__); - GNUNET_break_op(0); - return; - } - if (NULL == (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, next_hop))) - { - GNUNET_break_op(0); - return; - } - GDS_NEIGHBOURS_send_verify_successor_result (&querying_peer, - &vsrm->current_successor, - &probable_successor, - &trail_id, - trail, - trail_length, - trail_direction, - target_friend); -} - - -/** - * Check integrity of p2p notify new successor messages. - * - * @param cls closure - * @param nsm the message - * @return #GNUNET_OK if @a nsm is well-formed - */ -static int -check_dht_p2p_notify_new_successor (void *cls, - const struct PeerNotifyNewSuccessorMessage *nsm) -{ - size_t msize; - - msize = ntohs (nsm->header.size); - if ((msize - sizeof (struct PeerNotifyNewSuccessorMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for p2p notify new successor messages. - * - * @param cls closure - * @param nsm the message - */ -static void -handle_dht_p2p_notify_new_successor (void *cls, - const struct PeerNotifyNewSuccessorMessage *nsm) -{ - struct FriendInfo *friend = cls; - const struct GNUNET_PeerIdentity *trail; - struct GNUNET_PeerIdentity source; - struct GNUNET_PeerIdentity new_successor; - struct GNUNET_HashCode trail_id; - struct GNUNET_PeerIdentity next_hop; - struct FriendInfo *target_friend; - int my_index; - size_t msize; - uint32_t trail_length; - - msize = ntohs (nsm->header.size); - trail_length = (msize - sizeof (struct PeerNotifyNewSuccessorMessage))/ - sizeof (struct GNUNET_PeerIdentity); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - trail = (const struct GNUNET_PeerIdentity *) &nsm[1]; - source = nsm->source_peer; - new_successor = nsm->new_successor; - trail_id = nsm->trail_id; - - /* I am the new_successor to source_peer. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &new_successor)) - { - if (trail_length > 0) - GNUNET_assert(0 == GNUNET_CRYPTO_cmp_peer_identity (&trail[trail_length - 1], - friend->id)); - else - GNUNET_assert(0 == GNUNET_CRYPTO_cmp_peer_identity (&source, - friend->id)); - - compare_and_update_predecessor (&source, - trail, - trail_length); - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - friend->id); - GNUNET_assert (NULL != target_friend); - GDS_NEIGHBOURS_send_notify_succcessor_confirmation (&trail_id, - GDS_ROUTING_DEST_TO_SRC, - target_friend); - return; - } - - GNUNET_assert(trail_length > 0); - /* I am part of trail to reach to successor. */ - my_index = search_my_index (trail, trail_length); - if (-1 == my_index) - { - DEBUG ("No entry found in trail\n"); - GNUNET_break_op (0); - return; - } - if((trail_length + 1) == my_index) - { - DEBUG ("Found twice in trail.\n"); - GNUNET_break_op (0); - return; - } - if ((trail_length-1) == my_index) - next_hop = new_successor; - else - next_hop = trail[my_index + 1]; - - GDS_ROUTING_add (&trail_id, - friend->id, - &next_hop); - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_hop); - if (NULL == target_friend) - { - GNUNET_break(0); - return; - } - GDS_NEIGHBOURS_send_notify_new_successor (&source, - &new_successor, - trail, - trail_length, - &trail_id, - target_friend); -} - - -/** - * Core handler for P2P notify successor message - * - * @param cls closure - * @param notify_confirmation the message - */ -static void -handle_dht_p2p_notify_succ_confirmation (void *cls, - const struct PeerNotifyConfirmationMessage *notify_confirmation) -{ - enum GDS_ROUTING_trail_direction trail_direction; - struct GNUNET_HashCode trail_id; - struct FriendInfo *target_friend; - const struct GNUNET_PeerIdentity *next_hop; - - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - ntohs (notify_confirmation->header.size), - GNUNET_NO); - trail_direction = ntohl (notify_confirmation->trail_direction); - trail_id = notify_confirmation->trail_id; - - next_hop = GDS_ROUTING_get_next_hop (&trail_id, - trail_direction); - if (NULL == next_hop) - { - /* The source of notify new successor, might have found even a better - successor. In that case it send a trail teardown message, and hence, - the next hop is NULL. */ - //Fixme: Add some print to confirm the above theory. - return; - } - - /* I peer which sent the notify successor message to the successor. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (next_hop, - &my_identity)) - { - /* - * Schedule another round of verify sucessor with your current successor - * which may or may not be source of this message. This message is used - * only to ensure that we have a path setup to reach to our successor. - */ - - // TODO: cancel schedule of notify_successor_retry_task - if (send_notify_new_successor_retry_task != NULL) - { - struct SendNotifyContext *notify_ctx; - notify_ctx = GNUNET_SCHEDULER_cancel(send_notify_new_successor_retry_task); - GNUNET_free (notify_ctx->successor_trail); - GNUNET_free (notify_ctx); - send_notify_new_successor_retry_task = NULL; - } - if (send_verify_successor_task == NULL) - { - verify_successor_next_send_time.rel_value_us = - DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us); - send_verify_successor_task - = GNUNET_SCHEDULER_add_delayed(verify_successor_next_send_time, - &send_verify_successor_message, - NULL); - } - } - else - { - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - next_hop); - if (NULL == target_friend) - { - DEBUG ("\n friend not found, line number = %d", - __LINE__); - return; - } - GDS_NEIGHBOURS_send_notify_succcessor_confirmation (&trail_id, - GDS_ROUTING_DEST_TO_SRC, - target_friend); - } -} - - -/** - * Check integrity of P2P trail rejection message - * - * @param cls closure - * @param trail_rejection the message - * @return #GNUNET_OK if @a trail_rejection is well-formed - */ -static int -check_dht_p2p_trail_setup_rejection (void *cls, - const struct PeerTrailRejectionMessage *trail_rejection) -{ - size_t msize; - - msize = ntohs (trail_rejection->header.size); - if ((msize - sizeof (struct PeerTrailRejectionMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handler for P2P trail rejection message - * - * @param cls closure - * @param trail_rejection the message - */ -static void -handle_dht_p2p_trail_setup_rejection (void *cls, - const struct PeerTrailRejectionMessage *trail_rejection) -{ - struct FriendInfo *friend = cls; - unsigned int trail_length; - const struct GNUNET_PeerIdentity *trail_peer_list; - struct FriendInfo *target_friend; - struct GNUNET_TIME_Relative congestion_timeout; - struct GNUNET_HashCode trail_id; - struct GNUNET_PeerIdentity next_peer; - struct GNUNET_PeerIdentity source; - uint64_t ultimate_destination_finger_value; - unsigned int is_predecessor; - struct Closest_Peer successor; - size_t msize; - - msize = ntohs (trail_rejection->header.size); - trail_length = (msize - sizeof (struct PeerTrailRejectionMessage))/ - sizeof (struct GNUNET_PeerIdentity); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - - trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_rejection[1]; - is_predecessor = ntohl (trail_rejection->is_predecessor); - congestion_timeout = trail_rejection->congestion_time; - source = trail_rejection->source_peer; - trail_id = trail_rejection->trail_id; - ultimate_destination_finger_value - = GNUNET_ntohll (trail_rejection->ultimate_destination_finger_value); - /* First set the congestion time of the friend that sent you this message. */ - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - friend->id); - if (NULL == target_friend) - { - DEBUG ("\nLINE = %d ,No friend found.",__LINE__); - GNUNET_break(0); - return; - } - target_friend->congestion_timestamp - = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), - congestion_timeout); - - /* I am the source peer which wants to setup the trail. Do nothing. - * send_find_finger_trail_task is scheduled periodically.*/ - if(0 == (GNUNET_CRYPTO_cmp_peer_identity (&my_identity, &source))) - return; - - /* If I am congested then pass this message to peer before me in trail. */ - if (GNUNET_YES == GDS_ROUTING_threshold_reached()) - { - /* First remove yourself from the trail. */ - unsigned int new_trail_length = trail_length - 1; - struct GNUNET_PeerIdentity trail[new_trail_length]; - - GNUNET_memcpy (trail, - trail_peer_list, - new_trail_length * sizeof(struct GNUNET_PeerIdentity)); - if (0 == trail_length) - next_peer = source; - else - next_peer = trail[new_trail_length-1]; - - target_friend - = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_peer); - if (NULL == target_friend) - { - DEBUG ("\nLINE = %d ,No friend found.", - __LINE__); - GNUNET_break(0); - return; - } - GDS_NEIGHBOURS_send_trail_rejection (&source, - ultimate_destination_finger_value, - &my_identity, - is_predecessor, - trail, - new_trail_length, - &trail_id, - target_friend, - CONGESTION_TIMEOUT); - return; - } - - successor = find_local_best_known_next_hop (ultimate_destination_finger_value, - is_predecessor); - - /* Am I the final destination? */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&successor.best_known_destination, - &my_identity)) - { - /*Here you are already part of trail. Copy the trail removing yourself. */ - unsigned int new_trail_length = trail_length - 1; - struct GNUNET_PeerIdentity trail[new_trail_length]; - - GNUNET_memcpy (trail, - trail_peer_list, - new_trail_length * sizeof(struct GNUNET_PeerIdentity)); - - if (0 == new_trail_length) - next_peer = source; - else - { - next_peer = trail[new_trail_length-1]; - } - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_peer); - - if (NULL == target_friend) - { - DEBUG ("\nLINE = %d ,No friend found.", - __LINE__); - GNUNET_break(0); - return; - } - GDS_NEIGHBOURS_send_trail_setup_result (&source, - &my_identity, - target_friend, - new_trail_length, - trail, - is_predecessor, - ultimate_destination_finger_value, - &trail_id); - return; - } - /* Here I was already part of trail. So no need to add. */ - target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &successor.next_hop); - if (NULL == target_friend) - { - DEBUG ("\nLINE = %d ,No friend found.",__LINE__); - GNUNET_break (0); - return; - } - GDS_NEIGHBOURS_send_trail_setup (&source, - ultimate_destination_finger_value, - &successor.best_known_destination, - target_friend, - trail_length, - trail_peer_list, - is_predecessor, - &trail_id, - &successor.trail_id); -} - - -/** - * Core handler for trail teardown message. - * - * @param cls closure - * @param trail_teardown the message - */ -static void -handle_dht_p2p_trail_teardown (void *cls, - const struct PeerTrailTearDownMessage *trail_teardown) -{ - enum GDS_ROUTING_trail_direction trail_direction; - struct GNUNET_HashCode trail_id; - const struct GNUNET_PeerIdentity *next_hop; - size_t msize; - - msize = ntohs (trail_teardown->header.size); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - trail_direction = ntohl (trail_teardown->trail_direction); - trail_id = trail_teardown->trail_id; - - /* Check if peer is the real peer from which we should get this message.*/ - /* Get the prev_hop for this trail by getting the next hop in opposite direction. */ -#if 0 - GNUNET_assert (NULL != (prev_hop = - GDS_ROUTING_get_next_hop (trail_id, ! trail_direction))); - if (0 != GNUNET_CRYPTO_cmp_peer_identity (prev_hop, - friend->id)) - { - GNUNET_break (0); - return; - } -#endif - - next_hop = GDS_ROUTING_get_next_hop (&trail_id, - trail_direction); - if (NULL == next_hop) - { - DEBUG(" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u", - GNUNET_i2s (&my_identity), - GNUNET_h2s (&trail_id), - __LINE__); - GNUNET_break (0); - return; - } - - /* I am the next hop, which means I am the final destination. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (next_hop, &my_identity)) - { - GNUNET_assert (GNUNET_YES == - GDS_ROUTING_remove_trail (&trail_id)); - return; - } - /* If not final destination, then send a trail teardown message to next hop.*/ - GNUNET_assert (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - next_hop)); - GNUNET_assert (GNUNET_YES == - GDS_ROUTING_remove_trail (&trail_id)); - GDS_NEIGHBOURS_send_trail_teardown (&trail_id, - trail_direction, - next_hop); -} - - -/** - * Check validity of p2p add trail message. - * - * @param cls closure - * @param add_trail the message - * @return #GNUNET_OK if @a add_trail is well-formed - */ -static int -check_dht_p2p_add_trail (void *cls, - const struct PeerAddTrailMessage *add_trail) -{ - size_t msize; - - msize = ntohs (add_trail->header.size); - if ((msize - sizeof (struct PeerAddTrailMessage)) % - sizeof (struct GNUNET_PeerIdentity) != 0) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Core handle for p2p add trail message. - * - * @param cls closure - * @param add_trail the message - */ -static void -handle_dht_p2p_add_trail (void *cls, - const struct PeerAddTrailMessage *add_trail) -{ - struct FriendInfo *friend = cls; - const struct GNUNET_PeerIdentity *trail; - struct GNUNET_HashCode trail_id; - struct GNUNET_PeerIdentity destination_peer; - struct GNUNET_PeerIdentity source_peer; - struct GNUNET_PeerIdentity next_hop; - unsigned int trail_length; - unsigned int my_index; - size_t msize; - - msize = ntohs (add_trail->header.size); - /* In this message we pass the whole trail from source to destination as we - * are adding that trail.*/ - //FIXME: failed when run with 1000 pears. check why. - trail_length = (msize - sizeof (struct PeerAddTrailMessage))/ - sizeof (struct GNUNET_PeerIdentity); - GNUNET_STATISTICS_update (GDS_stats, - gettext_noop ("# Bytes received from other peers"), - msize, - GNUNET_NO); - - trail = (const struct GNUNET_PeerIdentity *) &add_trail[1]; - destination_peer = add_trail->destination_peer; - source_peer = add_trail->source_peer; - trail_id = add_trail->trail_id; - - /* I am not the destination of the trail. */ - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &destination_peer)) - { - struct FriendInfo *target_friend; - - /* Get my location in the trail. */ - my_index = search_my_index (trail, trail_length); - if (-1 == my_index) - { - GNUNET_break_op (0); - return; - } - if((trail_length + 1) == my_index) - { - DEBUG ("Found twice in trail.\n"); - GNUNET_break_op (0); - return; - } - if ((trail_length - 1) == my_index) - { - next_hop = destination_peer; - } - else - { - next_hop = trail[my_index + 1]; - } - /* Add in your routing table. */ - GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (&trail_id, - friend->id, - &next_hop)); - //GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (trail_id, next_hop, *peer)); - GNUNET_assert (NULL != - (target_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - &next_hop))); - GDS_NEIGHBOURS_send_add_trail (&source_peer, - &destination_peer, - &trail_id, - trail, - trail_length, - target_friend); - return; - } - /* I am the destination. Add an entry in routing table. */ - GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (&trail_id, - friend->id, - &my_identity)); -} - - -/** - * Free the finger trail in which the first friend to reach to a finger is - * disconnected_friend. Also remove entry from routing table for that particular - * trail id. - * @param disconnected_friend PeerIdentity of friend which got disconnected - * @param remove_finger Finger whose trail we need to check if it has - * disconnected_friend as the first hop. - * @return Total number of trails in which disconnected_friend was the first - * hop. - */ -static int -remove_matching_trails (const struct GNUNET_PeerIdentity *disconnected_friend, - struct FingerInfo *finger) -{ - const struct GNUNET_PeerIdentity *next_hop; - struct FriendInfo *remove_friend; - struct Trail *current_trail; - unsigned int matching_trails_count = 0; - int i; - - /* Iterate over all the trails of finger. */ - for (i = 0; i < finger->trails_count; i++) - { - current_trail = &finger->trail_list[i]; - if (GNUNET_NO == current_trail->is_present) - continue; - - /* First friend to reach to finger is disconnected_peer. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (¤t_trail->trail_head->peer, - disconnected_friend)) - { - remove_friend = - GNUNET_CONTAINER_multipeermap_get (friend_peermap, - disconnected_friend); - GNUNET_assert (NULL != remove_friend); - next_hop = GDS_ROUTING_get_next_hop (¤t_trail->trail_id, - GDS_ROUTING_SRC_TO_DEST); - - /* Here it may happen that as all the peers got disconnected, the entry in - routing table for that particular trail has been removed, because the - previously disconnected peer was either a next hop or prev hop of that - peer. */ - if (NULL != next_hop) - { - GNUNET_assert (0 == (GNUNET_CRYPTO_cmp_peer_identity (disconnected_friend, - next_hop))); - GNUNET_assert (GNUNET_YES == - GDS_ROUTING_remove_trail (¤t_trail->trail_id)); - } - matching_trails_count++; - free_trail (current_trail); - current_trail->is_present = GNUNET_NO; - } - } - return matching_trails_count; -} - - -/** - * Iterate over finger_table entries. - * 0. Ignore finger which is my_identity or if no valid entry present at - * that finger index. - * 1. If disconnected_friend is a finger, then remove the routing entry from - your own table. Free the trail. - * 2. Check if disconnected_friend is the first friend in the trail to reach to a finger. - * 2.1 Remove all the trails and entry from routing table in which disconnected - * friend is the first friend in the trail. If disconnected_friend is the - * first friend in all the trails to reach finger, then remove the finger. - * @param disconnected_friend Peer identity of friend which got disconnected. - */ -static void -remove_matching_fingers (const struct GNUNET_PeerIdentity *disconnected_peer) -{ - struct FingerInfo *current_finger; - int removed_trails_count; - int i; - - /* Iterate over finger table entries. */ - for (i = 0; i < MAX_FINGERS; i++) - { - current_finger = &finger_table[i]; - - /* No finger stored at this trail index or I am the finger. */ - if ((GNUNET_NO == current_finger->is_present) || - (0 == GNUNET_CRYPTO_cmp_peer_identity (¤t_finger->finger_identity, - &my_identity))) - continue; - - /* Is disconnected_peer a finger? */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (disconnected_peer, - ¤t_finger->finger_identity)) - { - remove_existing_finger (current_finger, i); - } - - /* If finger is a friend but not disconnected_friend, then continue. */ - if (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap, - ¤t_finger->finger_identity)) - continue; - - /* Iterate over the list of trails to reach remove_finger. Check if - * disconnected_friend is the first friend in any of the trail. */ - removed_trails_count = remove_matching_trails (disconnected_peer, - current_finger); - current_finger->trails_count = - current_finger->trails_count - removed_trails_count; - if (0 == current_finger->trails_count) - { - current_finger->is_present = GNUNET_NO; - memset (&finger_table[i], - 0, - sizeof (finger_table[i])); - } - } -} - - -/** - * Method called whenever a peer disconnects. - * - * @param cls closure - * @param peer peer identity this notification is about - * @param internal_cls our `struct FriendInfo` for @a peer - */ -static void -handle_core_disconnect (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *internal_cls) -{ - struct FriendInfo *remove_friend = internal_cls; - - /* If disconnected to own identity, then return. */ - if (NULL == remove_friend) - return; - remove_matching_fingers (peer); - GNUNET_assert (GNUNET_SYSERR != - GDS_ROUTING_remove_trail_by_peer (peer)); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (friend_peermap, - peer, - remove_friend)); - if (0 != GNUNET_CONTAINER_multipeermap_size (friend_peermap)) - return; - - if (NULL != find_finger_trail_task) - { - GNUNET_SCHEDULER_cancel (find_finger_trail_task); - find_finger_trail_task = NULL; - } - else - GNUNET_break (0); -} - - -/** - * Method called whenever a peer connects. - * - * @param cls closure - * @param peer_identity peer identity this notification is about - * @param mq message queue for sending data to @a peer - * @return our `struct FriendInfo` for this peer - */ -static void * -handle_core_connect (void *cls, - const struct GNUNET_PeerIdentity *peer_identity, - struct GNUNET_MQ_Handle *mq) -{ - struct FriendInfo *friend; - - /* Check for connect to self message */ - if (0 == memcmp (&my_identity, - peer_identity, - sizeof (struct GNUNET_PeerIdentity))) - return NULL; - friend = GNUNET_new (struct FriendInfo); - friend->id = peer_identity; - friend->mq = mq; - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (friend_peermap, - friend->id, - friend, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - - /* FIXME: now we are not making a distinction between fingers which are friends - * also.But later, we should add a congestion timestamp on the friend, so that it is - * selected after some time out. This is to ensure that both peers have added - * each other as their friend. */ - /* Got a first connection, good time to start with FIND FINGER TRAIL requests...*/ - if (NULL == find_finger_trail_task) - { - find_finger_trail_task - = GNUNET_SCHEDULER_add_now (&send_find_finger_trail_message, - NULL); - } - return friend; -} - - -/** - * To be called on core init/fail. - * - * @param cls service closure - * @param identity the public identity of this peer - */ -static void -core_init (void *cls, - const struct GNUNET_PeerIdentity *identity) -{ - my_identity = *identity; -} - - -/** - * Initialize finger table entries. - */ -static void -finger_table_init () -{ - memset (&finger_table, 0, sizeof (finger_table)); -} - - -/** - * Initialize neighbours subsystem. - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -int -GDS_NEIGHBOURS_init (void) -{ - struct GNUNET_MQ_MessageHandler core_handlers[] = { - GNUNET_MQ_hd_var_size (dht_p2p_put, - GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT, - struct PeerPutMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_get, - GNUNET_MESSAGE_TYPE_XDHT_P2P_GET, - struct PeerGetMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_get_result, - GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT, - struct PeerGetResultMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_trail_setup, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP, - struct PeerTrailSetupMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_trail_setup_result, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT, - struct PeerTrailSetupResultMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_verify_successor, - GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR, - struct PeerVerifySuccessorMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_verify_successor_result, - GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT, - struct PeerVerifySuccessorResultMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_notify_new_successor, - GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR, - struct PeerNotifyNewSuccessorMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_trail_setup_rejection, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION, - struct PeerTrailRejectionMessage, - NULL), - GNUNET_MQ_hd_fixed_size (dht_p2p_trail_teardown, - GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN, - struct PeerTrailTearDownMessage, - NULL), - GNUNET_MQ_hd_var_size (dht_p2p_add_trail, - GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL, - struct PeerAddTrailMessage, - NULL), - GNUNET_MQ_hd_fixed_size (dht_p2p_notify_succ_confirmation, - GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_SUCCESSOR_CONFIRMATION, - struct PeerNotifyConfirmationMessage, - NULL), - GNUNET_MQ_handler_end () - }; - - core_api = GNUNET_CORE_connect (GDS_cfg, - NULL, - &core_init, - &handle_core_connect, - &handle_core_disconnect, - core_handlers); - if (NULL == core_api) - return GNUNET_SYSERR; - friend_peermap = GNUNET_CONTAINER_multipeermap_create (256, - GNUNET_YES); - finger_table_init (); - successor_times = 10; - fingers_round_count = 5; - find_finger_trail_task_next_send_time.rel_value_us = - DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us); - - verify_successor_next_send_time.rel_value_us = - DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us); - - verify_successor_retry_time.rel_value_us = - DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us); - - notify_successor_retry_time.rel_value_us = - DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us + - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us); - - return GNUNET_OK; -} - - -/** - * Free the memory held up by trails of a finger. - */ -static void -delete_finger_table_entries() -{ - for (unsigned int i = 0; i < MAX_FINGERS; i++) - { - if (GNUNET_YES != finger_table[i].is_present) - continue; - for (unsigned int j = 0; j < finger_table[i].trails_count; j++) - free_trail(&finger_table[i].trail_list[j]); - } -} - - -/** - * Shutdown neighbours subsystem. - */ -void -GDS_NEIGHBOURS_done (void) -{ - if (NULL == core_api) - return; - - GNUNET_CORE_disconnect (core_api); - core_api = NULL; - - delete_finger_table_entries(); - GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friend_peermap)); - GNUNET_CONTAINER_multipeermap_destroy (friend_peermap); - friend_peermap = NULL; - - if (NULL != find_finger_trail_task) - { - GNUNET_SCHEDULER_cancel (find_finger_trail_task); - find_finger_trail_task = NULL; - } - - if (NULL != send_verify_successor_task) - { - GNUNET_SCHEDULER_cancel (send_verify_successor_task); - send_verify_successor_task = NULL; - } - if (NULL != send_verify_successor_retry_task) - { - struct VerifySuccessorContext *ctx; - - ctx = GNUNET_SCHEDULER_cancel (send_verify_successor_retry_task); - GNUNET_free (ctx); - send_verify_successor_retry_task = NULL; - } - if (NULL != send_notify_new_successor_retry_task) - { - struct SendNotifyContext *notify_ctx; - - notify_ctx = GNUNET_SCHEDULER_cancel (send_notify_new_successor_retry_task); - GNUNET_free (notify_ctx->successor_trail); - GNUNET_free (notify_ctx); - send_notify_new_successor_retry_task = NULL; - } -} - - -/** - * Get my identity - * - * @return my identity - */ -struct GNUNET_PeerIdentity * -GDS_NEIGHBOURS_get_id (void) -{ - return &my_identity; -} - -/* end of gnunet-service-xdht_neighbours.c */ diff --git a/src/dht/gnunet-service-xdht_neighbours.h b/src/dht/gnunet-service-xdht_neighbours.h deleted file mode 100644 index 2fb118448..000000000 --- a/src/dht/gnunet-service-xdht_neighbours.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009, 2010, 2011 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_neighbours.h - * @brief GNUnet DHT routing code - * @author Supriti Singh - */ - -#ifndef GNUNET_SERVICE_XDHT_NEIGHBOURS_H -#define GNUNET_SERVICE_XDHT_NEIGHBOURS_H - -#include "gnunet_util_lib.h" -#include "gnunet_block_lib.h" -#include "gnunet_dht_service.h" - - -/** - * Construct a trail teardown message and forward it to target friend. - * @param trail_id Unique identifier of the trail. - * @param trail_direction Direction of trail. - * @param target_friend Friend to get this message. - */ -void -GDS_NEIGHBOURS_send_trail_teardown (const struct GNUNET_HashCode *trail_id, - unsigned int trail_direction, - const struct GNUNET_PeerIdentity *peer); - - -#endif diff --git a/src/dht/gnunet-service-xdht_routing.c b/src/dht/gnunet-service-xdht_routing.c deleted file mode 100644 index ec7361579..000000000 --- a/src/dht/gnunet-service-xdht_routing.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 - 2014 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_routing.c - * @brief GNUnet DHT tracking of requests for routing replies - * @author Supriti Singh - */ -#include "platform.h" -#include "gnunet-service-dht_neighbours.h" -#include "gnunet-service-xdht_neighbours.h" -#include "gnunet-service-xdht_routing.h" -#include "gnunet-service-dht.h" - - -/** - * FIXME: Check if its better to store pointer to friend rather than storing - * peer identity next_hop or prev_hop. - * keep entries in destnation and source peer also. so when we send the trail - * teardown message then we don't know the source but if source gets the message - * then it shold remove that trail id from its finger table. But how does - * source know what is the desination finger ? It will whenevr contact a trail - * will do a lookup in routing table and if no trail id present the remove - * that trail of the finger and if only one trail then remove the finger. - * because of this use case of trail teardown I think trail compression - * and trail teardown should not be merged. - * 2. store a pointer to friendInfo in place o peer identity. - */ -/** - * Maximum number of entries in routing table. - */ -#define ROUTING_TABLE_THRESHOLD 80000 - -/** - * FIXME: Store friend pointer instead of peer identifier. - * Routing table entry . - */ -struct RoutingTrail -{ - /** - * Global Unique identifier of the trail. - */ - struct GNUNET_HashCode trail_id; - - /** - * The peer to which this request should be passed to. - */ - struct GNUNET_PeerIdentity next_hop; - - /** - * Peer just before next hop in the trail. - */ - struct GNUNET_PeerIdentity prev_hop; -}; - -/** - * Routing table of the peer - */ -static struct GNUNET_CONTAINER_MultiHashMap *routing_table; - -/** - * Update the prev. hop of the trail. Call made by trail compression where - * if you are the first friend now in the trail then you need to update - * your prev. hop. - * @param trail_id - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case no matching entry found in routing table. - */ -int -GDS_ROUTING_update_trail_prev_hop (const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *prev_hop) -{ - struct RoutingTrail *trail; - - trail = GNUNET_CONTAINER_multihashmap_get (routing_table, - trail_id); - - if (NULL == trail) - return GNUNET_SYSERR; - trail->prev_hop = *prev_hop; - return GNUNET_OK; -} - - -/** - * Update the next hop of the trail. Call made by trail compression where - * if you are source of the trail and now you have a new first friend, then - * you should update the trail. - * @param trail_id - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case no matching entry found in routing table. - */ -int -GDS_ROUTING_update_trail_next_hop (const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *next_hop) -{ - struct RoutingTrail *trail; - - trail = GNUNET_CONTAINER_multihashmap_get (routing_table, - trail_id); - if (NULL == trail) - return GNUNET_SYSERR; - trail->next_hop = *next_hop; - return GNUNET_OK; -} - - -/** - * Get the next hop for trail corresponding to trail_id - * - * @param trail_id Trail id to be searched. - * @return Next_hop if found - * NULL If next hop not found. - */ -const struct GNUNET_PeerIdentity * -GDS_ROUTING_get_next_hop (const struct GNUNET_HashCode *trail_id, - enum GDS_ROUTING_trail_direction trail_direction) -{ - struct RoutingTrail *trail; - - trail = GNUNET_CONTAINER_multihashmap_get (routing_table, - trail_id); - if (NULL == trail) - { - /* If a friend got disconnected and we removed all the entry from the - routing table, then trail will be deleted and my identity will not know - and when it tries to reach to that finger it fails. thats why - assertion always fails in*/ - return NULL; - } - switch (trail_direction) - { - case GDS_ROUTING_SRC_TO_DEST: - return &trail->next_hop; - case GDS_ROUTING_DEST_TO_SRC: - return &trail->prev_hop; - } - return NULL; -} - - -/** - * Remove trail with trail_id - * @param trail_id Trail id to be removed - * @return #GNUNET_YES success - * #GNUNET_NO if entry not found. - */ -int -GDS_ROUTING_remove_trail (const struct GNUNET_HashCode *remove_trail_id) -{ - struct RoutingTrail *remove_entry; - - remove_entry = GNUNET_CONTAINER_multihashmap_get (routing_table, - remove_trail_id); - if (NULL == remove_entry) - return GNUNET_NO; - - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (routing_table, - remove_trail_id, - remove_entry)) - { - GNUNET_free (remove_entry); - return GNUNET_YES; - } - return GNUNET_NO; -} - - -/** - * Iterate over routing table and remove entries with value as part of any trail. - * - * @param cls closure - * @param key current public key - * @param value value in the hash map - * @return #GNUNET_YES if we should continue to iterate, - * #GNUNET_NO if not. - */ -static int -remove_matching_trails (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct RoutingTrail *remove_trail = value; - struct GNUNET_PeerIdentity *disconnected_peer = cls; - struct GNUNET_HashCode trail_id = *key; - struct GNUNET_PeerIdentity my_identity; - - /* If disconnected_peer is next_hop, then send a trail teardown message through - * prev_hop in direction from destination to source. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->next_hop, - disconnected_peer)) - { - my_identity = *GDS_NEIGHBOURS_get_id (); - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &remove_trail->prev_hop)) - { - GDS_NEIGHBOURS_send_trail_teardown (&trail_id, - GDS_ROUTING_DEST_TO_SRC, - &remove_trail->prev_hop); - } - } - - /* If disconnected_peer is prev_hop, then send a trail teardown through - * next_hop in direction from Source to Destination. */ - if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->prev_hop, - disconnected_peer)) - { - my_identity = *GDS_NEIGHBOURS_get_id (); - - if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity, - &remove_trail->next_hop)) - { - GDS_NEIGHBOURS_send_trail_teardown (&trail_id, - GDS_ROUTING_SRC_TO_DEST, - &remove_trail->next_hop); - } - } - - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (routing_table, - &trail_id, - remove_trail)); - GNUNET_free (remove_trail); - return GNUNET_YES; -} - -#if 0 -/** - * TEST FUNCTION - * Remove after using. - */ -void -GDS_ROUTING_test_print (void) -{ - struct GNUNET_CONTAINER_MultiHashMapIterator *iter; - struct RoutingTrail *trail; - struct GNUNET_PeerIdentity print_peer; - struct GNUNET_HashCode key_ret; - int i; - - struct GNUNET_PeerIdentity my_identity = *GDS_NEIGHBOURS_get_id(); - print_peer = my_identity; - FPRINTF (stderr,_("\nSUPU ***PRINTING ROUTING TABLE ***** of =%s"),GNUNET_i2s(&print_peer)); - iter =GNUNET_CONTAINER_multihashmap_iterator_create (routing_table); - for (i = 0; i < GNUNET_CONTAINER_multihashmap_size(routing_table); i++) - { - if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_iterator_next (iter, - &key_ret, - (const void **)&trail)) - { - FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->trail_id = %s"), - __FILE__, __func__,__LINE__, GNUNET_h2s(&trail->trail_id)); - GNUNET_memcpy (&print_peer, &trail->next_hop, sizeof (struct GNUNET_PeerIdentity)); - FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->next_hop = %s"), - __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer)); - GNUNET_memcpy (&print_peer, &trail->prev_hop, sizeof (struct GNUNET_PeerIdentity)); - FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->prev_hop = %s"), - __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer)); - } - } -} -#endif - -/** - * Remove every trail where peer is either next_hop or prev_hop. Also send a - * trail teardown message in direction of hop which is not disconnected. - * @param peer Peer identity. Trail containing this peer should be removed. - */ -int -GDS_ROUTING_remove_trail_by_peer (const struct GNUNET_PeerIdentity *peer) -{ - int ret; - - - /* No entries in my routing table. */ - if (0 == GNUNET_CONTAINER_multihashmap_size(routing_table)) - return GNUNET_YES; - - ret = GNUNET_CONTAINER_multihashmap_iterate (routing_table, - &remove_matching_trails, - (void *)peer); - return ret; -} - - -/** - * Add a new entry in routing table - * @param new_trail_id - * @param prev_hop - * @param next_hop - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case new_trail_id already exists in the network - * but with different prev_hop/next_hop - */ -int -GDS_ROUTING_add (const struct GNUNET_HashCode *new_trail_id, - const struct GNUNET_PeerIdentity *prev_hop, - const struct GNUNET_PeerIdentity *next_hop) -{ - struct RoutingTrail *new_entry; - - new_entry = GNUNET_new (struct RoutingTrail); - new_entry->trail_id = *new_trail_id; - new_entry->next_hop = *next_hop; - new_entry->prev_hop = *prev_hop; - - // FIXME: this leaks memory if the put fails! - return GNUNET_CONTAINER_multihashmap_put (routing_table, - &new_entry->trail_id, - new_entry, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); -} - - -/** - * Check if the size of routing table has crossed ROUTING_TABLE_THRESHOLD. - * It means that I don't have any more space in my routing table and I can not - * be part of any more trails till there is free space in my routing table. - * @return #GNUNET_YES, if threshold crossed else #GNUNET_NO. - */ -int -GDS_ROUTING_threshold_reached (void) -{ - return (GNUNET_CONTAINER_multihashmap_size(routing_table) > - ROUTING_TABLE_THRESHOLD) ? GNUNET_YES:GNUNET_NO; -} - - -/** - * Initialize routing subsystem. - */ -void -GDS_ROUTING_init (void) -{ - routing_table = GNUNET_CONTAINER_multihashmap_create (ROUTING_TABLE_THRESHOLD * 4 / 3, - GNUNET_NO); -} - - -/** - * Shutdown routing subsystem. - */ -void -GDS_ROUTING_done (void) -{ - GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (routing_table)); - GNUNET_CONTAINER_multihashmap_destroy (routing_table); -} - -/* end of gnunet-service-xdht_routing.c */ diff --git a/src/dht/gnunet-service-xdht_routing.h b/src/dht/gnunet-service-xdht_routing.h deleted file mode 100644 index 69ab1ff78..000000000 --- a/src/dht/gnunet-service-xdht_routing.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2011 - 2014 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file dht/gnunet-service-xdht_routing.h - * @brief GNUnet DHT tracking of requests for routing replies - * @author Christian Grothoff - */ -#ifndef GNUNET_SERVICE_XDHT_ROUTING_H -#define GNUNET_SERVICE_XDHT_ROUTING_H - -#include "gnunet_util_lib.h" -#include "gnunet_block_lib.h" -#include "gnunet_dht_service.h" - -/** - * To understand the direction in which trial should be read. - */ -enum GDS_ROUTING_trail_direction -{ - GDS_ROUTING_SRC_TO_DEST, - GDS_ROUTING_DEST_TO_SRC -}; - - -/** - * Update the prev. hop of the trail. Call made by trail teardown where - * if you are the first friend now in the trail then you need to update - * your prev. hop. - * @param trail_id - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case no matching entry found in routing table. - */ -int -GDS_ROUTING_update_trail_prev_hop (const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *prev_hop); - - -/** - * Update the next hop of the trail. Call made by trail compression where - * if you are source of the trail and now you have a new first friend, then - * you should update the trail. - * @param trail_id - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case no matching entry found in routing table. - */ -int -GDS_ROUTING_update_trail_next_hop (const struct GNUNET_HashCode *trail_id, - const struct GNUNET_PeerIdentity *next_hop); - -/** - * Get the next hop for trail corresponding to trail_id - * @param trail_id Trail id to be searched. - * @return Next_hop if found - * NULL If next hop not found. - */ -const struct GNUNET_PeerIdentity * -GDS_ROUTING_get_next_hop (const struct GNUNET_HashCode *trail_id, - enum GDS_ROUTING_trail_direction trail_direction); - - -/** - * Remove every trail where peer is either next_hop or prev_hop - * @param peer Peer to be searched. - */ -int -GDS_ROUTING_remove_trail_by_peer (const struct GNUNET_PeerIdentity *peer); - - -/** - * Remove trail with trail_id - * - * @param trail_id Trail id to be removed - * @return #GNUNET_YES success - * #GNUNET_NO if entry not found. - */ -int -GDS_ROUTING_remove_trail (const struct GNUNET_HashCode *remove_trail_id); - - -/** - * Add a new entry in routing table - * @param new_trail_id - * @param prev_hop - * @param next_hop - * @return #GNUNET_OK success - * #GNUNET_SYSERR in case new_trail_id already exists in the network - * but with different prev_hop/next_hop - */ -int -GDS_ROUTING_add (const struct GNUNET_HashCode *new_trail_id, - const struct GNUNET_PeerIdentity *prev_hop, - const struct GNUNET_PeerIdentity *next_hop); - - -/** - * Check if the size of routing table has crossed threshold. - * @return #GNUNET_YES, if threshold crossed - * #GNUNET_NO, if size is within threshold - */ -int -GDS_ROUTING_threshold_reached (void); - -#if 0 -/** - * Test function. Remove afterwards. - */ -void -GDS_ROUTING_test_print (void); -#endif - -/** - * Initialize routing subsystem. - */ -void -GDS_ROUTING_init (void); - -/** - * Shutdown routing subsystem. - */ -void -GDS_ROUTING_done (void); - -#endif