2 This file is part of GNUnet.
3 (C) 2009-2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file dht/gnunet-service-xdht_neighbours.c
23 * @brief GNUnet DHT service's finger and friend table management code
24 * @author Supriti Singh
28 #include "gnunet_util_lib.h"
29 #include "gnunet_block_lib.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_nse_service.h"
34 #include "gnunet_ats_service.h"
35 #include "gnunet_core_service.h"
36 #include "gnunet_datacache_lib.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_hello_lib.h"
39 #include "gnunet_dht_service.h"
40 #include "gnunet_statistics_service.h"
41 #include "gnunet-service-xdht.h"
42 #include "gnunet-service-xdht_clients.h"
43 #include "gnunet-service-xdht_datacache.h"
44 #include "gnunet-service-xdht_hello.h"
45 #include "gnunet-service-xdht_neighbours.h"
46 #include "gnunet-service-xdht_nse.h"
47 #include "gnunet-service-xdht_routing.h"
53 1. Add content and route replication later.
54 * 3. Algorithm to shorten the trail length - one possible solution could be
55 * when we are in trail seutp result part. each peer in the trail check if any of
56 * the corresponding peers is its friend list. Then it can shortcut the path.
57 * But this will have O(n) run time at each peer, where n = trail_length.\
58 * or rather O(n)+O(n-1)+..O(1) =O(n).
63 * Maximum possible fingers of a peer.
65 #define MAX_FINGERS 256
68 * Maximum allowed number of pending messages per friend peer.
70 #define MAXIMUM_PENDING_PER_FRIEND 64
73 * How long at least to wait before sending another find finger trail request.
75 #define DHT_MINIMUM_FIND_FINGER_TRAIL_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
78 * How long at most to wait before sending another find finger trail request.
80 #define DHT_MAXIMUM_FIND_FINGER_TRAIL_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 10)
83 * FIXME: Currently used in GDS_NEIGHBOURS_handle_trail_setup.
84 * I have just copied it from gnunet-service-dht_neighbours. Will it work here?
85 * How long at most to wait for transmission of a GET request to another peer?
87 #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
89 GNUNET_NETWORK_STRUCT_BEGIN
92 * 1) Bloomfilter is not required for X-Vine.
93 * Keep the field now but remove it when implementing PUT/GET.
94 * 2) also, check the field of put/get/result if all are required for
100 struct PeerPutMessage
103 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
105 struct GNUNET_MessageHeader header;
110 uint32_t options GNUNET_PACKED;
115 uint32_t type GNUNET_PACKED;
120 uint32_t hop_count GNUNET_PACKED;
123 * Replication level for this message
125 uint32_t desired_replication_level GNUNET_PACKED;
128 * Length of the PUT path that follows (if tracked).
130 uint32_t put_path_length GNUNET_PACKED;
133 * When does the content expire?
135 struct GNUNET_TIME_AbsoluteNBO expiration_time;
138 * Bloomfilter (for peer identities) to stop circular routes
140 char bloomfilter[DHT_BLOOM_SIZE];
143 * The key we are storing under.
145 struct GNUNET_HashCode key;
147 /* put path (if tracked) */
157 struct PeerResultMessage
160 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
162 struct GNUNET_MessageHeader header;
167 uint32_t type GNUNET_PACKED;
170 * Length of the PUT path that follows (if tracked).
172 uint32_t put_path_length GNUNET_PACKED;
175 * Length of the GET path that follows (if tracked).
177 uint32_t get_path_length GNUNET_PACKED;
180 * When does the content expire?
182 struct GNUNET_TIME_AbsoluteNBO expiration_time;
185 * The key of the corresponding GET request.
187 struct GNUNET_HashCode key;
189 /* put path (if tracked) */
191 /* get path (if tracked) */
201 struct PeerGetMessage
204 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
206 struct GNUNET_MessageHeader header;
211 uint32_t options GNUNET_PACKED;
214 * Desired content type.
216 uint32_t type GNUNET_PACKED;
221 uint32_t hop_count GNUNET_PACKED;
224 * Desired replication level for this request.
226 uint32_t desired_replication_level GNUNET_PACKED;
229 * Size of the extended query.
231 uint32_t xquery_size;
234 * Bloomfilter mutator.
239 * Bloomfilter (for peer identities) to stop circular routes
241 char bloomfilter[DHT_BLOOM_SIZE];
244 * The key we are looking for.
246 struct GNUNET_HashCode key;
252 * A destination can be either a friend or finger.
254 enum current_destination_type
265 * P2P Trail setup message
266 * TODO: Take reference from put_path and get_path to understand how to use size of trail list.
268 struct PeerTrailSetupMessage
271 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_SETUP
273 struct GNUNET_MessageHeader header;
276 * Source peer which wants to find trail to one of its finger.
278 struct GNUNET_PeerIdentity source_peer;
281 * Finger id to which we want to set up the trail to.
283 struct GNUNET_PeerIdentity destination_finger;
285 /* FIXME: Temporary field to handle current_destination properly.
286 If flag = 0, then this message's current_destination is a friend.
287 If flag = 1, then the message's current destination is a finger. */
290 enum current_destination_type current_destination_type;
293 * This field contains the peer to which this packet is forwarded.
295 struct GNUNET_PeerIdentity current_destination;
298 * Number of entries in trail list.
299 * FIXME: Is this data type correct?
300 * FIMXE: Is usage of GNUNET_PACKED correct?
302 uint32_t trail_length GNUNET_PACKED;
304 /* FIXME: Add this field later.
305 * The finger index in finger map.
306 unsigned int finger_index;*/
312 * P2P Trail setup Result message
314 struct PeerTrailSetupResultMessage
317 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_RESULT_SETUP
319 struct GNUNET_MessageHeader header;
322 * Finger to which we have found the path.
324 struct GNUNET_PeerIdentity finger;
327 * Peer which was looking for the trail to finger.
329 struct GNUNET_PeerIdentity destination_peer;
332 * This field contains the peer to which this packet is forwarded.
334 struct GNUNET_PeerIdentity current_destination;
337 * FIXME: Temporary field used to remember at which index we should read
338 * to get our next peer.
340 unsigned int current_index;
343 * Number of entries in trail list.
344 * FIXME: Is this data type correct?
345 * FIXME: Is usage of GNUNET_PACKED correct?
347 uint32_t trail_length GNUNET_PACKED;
351 GNUNET_NETWORK_STRUCT_END
355 * Linked list of messages to send to a particular other peer.
357 struct P2PPendingMessage
360 * Pointer to next item in the list
362 struct P2PPendingMessage *next;
365 * Pointer to previous item in the list
367 struct P2PPendingMessage *prev;
370 * When does this message time out?
372 struct GNUNET_TIME_Absolute timeout;
375 * Message importance level. FIXME: used? useful?
377 unsigned int importance;
380 * Actual message to be sent, allocated at the end of the struct:
381 * // msg = (cast) &pm[1];
382 * // memcpy (&pm[1], data, len);
384 const struct GNUNET_MessageHeader *msg;
390 * Linked List of peers which are part of trail to reach a particular Finger.
395 * Pointer to next item in the list
397 struct TrailPeerList *next;
400 * Pointer to previous item in the list
402 struct TrailPeerList *prev;
405 * An element in this trail list
407 struct GNUNET_PeerIdentity peer;
413 * Entry in friend_peermap.
418 * What is the identity of the peer?
420 struct GNUNET_PeerIdentity id;
423 * Count of outstanding messages for peer.
425 unsigned int pending_count;
429 * 1. We need some mechanism to check the interval of values for which
430 * a peer is responsible. If we can somehow maintain the peer id of
431 * next peer in the friend map, then we will be able to check. Or else
432 * we iterate over friend map twice will results in O(n^2) complexity.
433 * So, the tradeoff is between space and run time complexity.
434 * Peer id of next friend in friend peermap in 64 bit format.
436 uint64_t interval_end;
439 * Head of pending messages to be sent to this peer.
441 struct P2PPendingMessage *head;
444 * Tail of pending messages to be sent to this peer.
446 struct P2PPendingMessage *tail;
449 * TODO - How and where to use this?
450 * Core handle for sending messages to this peer.
452 struct GNUNET_CORE_TransmitHandle *th;
458 * Entry in finger_peermap.
463 * What is the identity of the finger peer?
465 struct GNUNET_PeerIdentity id;
468 * Start of the interval of keys for which this finger is responsible.
470 unsigned int interval_start;
473 * End of the interval of keys for which this finger is responsible.
475 unsigned int interval_end;
478 * List of peers in the trail.
480 const struct GNUNET_PeerIdentity *trail_peer_list;
485 unsigned int finger_index;
490 * Task that sends FIND FINGER TRAIL requests.
492 static GNUNET_SCHEDULER_TaskIdentifier find_finger_trail_task;
495 * Identity of this peer.
497 static struct GNUNET_PeerIdentity my_identity;
500 * FIXME: Not used anywhere in the code yet.
501 * Hash of the identity of this peer.
503 static struct GNUNET_HashCode my_identity_hash;
506 * Hash map of all the friends of a peer
508 static struct GNUNET_CONTAINER_MultiPeerMap *friend_peermap;
511 * Hash map of all the fingers of a peer
513 static struct GNUNET_CONTAINER_MultiPeerMap *finger_peermap;
516 * TODO: Ask whats the use of ATS.
519 static struct GNUNET_ATS_PerformanceHandle *atsAPI;
524 static struct GNUNET_CORE_Handle *core_api;
527 * The current finger index that we have found trail to.
529 static unsigned int current_finger_index;
533 * Called when core is ready to send a message we asked for
534 * out to the destination.
536 * @param cls the 'struct PeerInfo' of the target peer
537 * @param size number of bytes available in buf
538 * @param buf where the callee should write the message
539 * @return number of bytes written to buf
542 core_transmit_notify (void *cls, size_t size, void *buf)
544 struct FriendInfo *peer = cls;
546 struct P2PPendingMessage *pending;
551 while ((NULL != (pending = peer->head)) &&
552 (0 == GNUNET_TIME_absolute_get_remaining (pending->timeout).rel_value_us))
554 peer->pending_count--;
555 GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending);
556 GNUNET_free (pending);
560 /* no messages pending */
566 GNUNET_CORE_notify_transmit_ready (core_api, GNUNET_NO,
567 GNUNET_CORE_PRIO_BEST_EFFORT,
568 GNUNET_TIME_absolute_get_remaining
569 (pending->timeout), &peer->id,
570 ntohs (pending->msg->size),
571 &core_transmit_notify, peer);
572 GNUNET_break (NULL != peer->th);
576 while ((NULL != (pending = peer->head)) &&
577 (size - off >= (msize = ntohs (pending->msg->size))))
579 GNUNET_STATISTICS_update (GDS_stats,
581 ("# Bytes transmitted to other peers"), msize,
583 memcpy (&cbuf[off], pending->msg, msize);
585 peer->pending_count--;
586 GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending);
587 GNUNET_free (pending);
589 if (peer->head != NULL)
592 GNUNET_CORE_notify_transmit_ready (core_api, GNUNET_NO,
593 GNUNET_CORE_PRIO_BEST_EFFORT,
594 GNUNET_TIME_absolute_get_remaining
595 (pending->timeout), &peer->id, msize,
596 &core_transmit_notify, peer);
597 GNUNET_break (NULL != peer->th);
604 * Transmit all messages in the friend's message queue.
606 * @param peer message queue to process
609 process_friend_queue (struct FriendInfo *peer)
611 struct P2PPendingMessage *pending;
613 if (NULL == (pending = peer->head))
615 if (NULL != peer->th)
618 GNUNET_STATISTICS_update (GDS_stats,
620 ("# Bytes of bandwidth requested from core"),
621 ntohs (pending->msg->size), GNUNET_NO);
623 /* FIXME: Are we correctly initializing importance and pending. */
625 GNUNET_CORE_notify_transmit_ready (core_api, GNUNET_NO,
627 GNUNET_TIME_absolute_get_remaining
628 (pending->timeout), &peer->id,
629 ntohs (pending->msg->size),
630 &core_transmit_notify, peer);
631 GNUNET_break (NULL != peer->th);
637 * 1. trail_length is already incremented in the calling function
638 * i.e. in send_find_finger_trail, we send trail_length = 1, and then we
640 * 2. in handle_dht_p2p_trail_setup, we send trail_length = trail_length+1;
641 * and we already have added the id of current_destination in our peer_list so
642 * we need not to do anything else.
643 * Setup the trail message and forward it to a friend.
644 * @param source_peer Peer which wants to set up the trail to one of its finger.
645 * @param destination_finger Peer to which we want to set up the trail to.
646 * @param current_destination Current peer to which this message should be forwarded.
647 * @param trail_length Numbers of peers in the trail.
648 * @param trail_peer_list peers this request has traversed so far
651 GDS_NEIGHBOURS_handle_trail_setup(struct GNUNET_PeerIdentity *source_peer,
652 struct GNUNET_PeerIdentity *destination_finger,
653 struct FriendInfo *current_destination,
654 unsigned int trail_length,
655 struct GNUNET_PeerIdentity *trail_peer_list)
657 struct P2PPendingMessage *pending;
658 struct PeerTrailSetupMessage *tsm;
659 struct GNUNET_PeerIdentity *peer_list;
662 msize = sizeof(struct PeerTrailSetupMessage) +
663 (trail_length * sizeof(struct GNUNET_PeerIdentity));
665 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
671 if (current_destination->pending_count >= MAXIMUM_PENDING_PER_FRIEND)
673 GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P messages dropped due to full queue"),
677 pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize);
678 pending->importance = 0; /* FIXME */
679 pending->timeout = GNUNET_TIME_relative_to_absolute (GET_TIMEOUT);
680 tsm = (struct PeerTrailSetupMessage *) &pending[1];
681 pending->msg = &tsm->header;
682 tsm->header.size = htons (msize);
683 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_SETUP);
684 memcpy(&(tsm->destination_finger), destination_finger, sizeof (struct GNUNET_PeerIdentity));
685 memcpy(&(tsm->source_peer), source_peer, sizeof (struct GNUNET_PeerIdentity));
686 memcpy(&(tsm->current_destination),&(current_destination->id), sizeof (struct GNUNET_PeerIdentity));
687 tsm->current_destination_type = htonl(FRIEND);
688 tsm->trail_length = htonl(trail_length);
689 peer_list = (struct GNUNET_PeerIdentity *) &tsm[1];
691 if(NULL == trail_peer_list)
693 memcpy(peer_list, &(current_destination->id), sizeof(struct GNUNET_PeerIdentity));
697 memcpy(peer_list, trail_peer_list, trail_length * sizeof(struct GNUNET_PeerIdentity));
700 GNUNET_CONTAINER_DLL_insert_tail (current_destination->head, current_destination->tail, pending);
701 current_destination->pending_count++;
702 process_friend_queue (current_destination);
707 * Handle a tail setup result message.
708 * @param destination_peer Peer which will get the trail to one of its finger.
709 * @param source_finger Peer to which the trail has been setup to.
710 * @param current_destination Current peer to which this message should be forwarded.
711 * @param trail_length Numbers of peers in the trail.
712 * @param trail_peer_list peers this request has traversed so far
713 * @param current_trail_index Index in trail_peer_list.
716 GDS_NEIGHBOURS_handle_trail_setup_result(struct GNUNET_PeerIdentity *destination_peer,
717 struct GNUNET_PeerIdentity *source_finger,
718 struct FriendInfo *current_destination,
719 unsigned int trail_length,
720 const struct GNUNET_PeerIdentity *trail_peer_list,
721 unsigned int current_trial_index)
723 struct P2PPendingMessage *pending;
724 struct PeerTrailSetupResultMessage *tsrm;
725 struct GNUNET_PeerIdentity *peer_list;
728 msize = sizeof(struct PeerTrailSetupMessage) +
729 (trail_length * sizeof(struct GNUNET_PeerIdentity));
731 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
737 if (current_destination->pending_count >= MAXIMUM_PENDING_PER_FRIEND)
739 GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P messages dropped due to full queue"),
743 pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize);
744 pending->importance = 0; /* FIXME */
745 pending->timeout = GNUNET_TIME_relative_to_absolute (GET_TIMEOUT);
746 tsrm = (struct PeerTrailSetupResultMessage *) &pending[1];
747 pending->msg = &tsrm->header;
748 tsrm->header.size = htons (msize);
749 tsrm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_SETUP_RESULT);
750 memcpy(&(tsrm->current_destination), &(current_destination->id), sizeof(struct GNUNET_PeerIdentity));
751 memcpy(&(tsrm->destination_peer), destination_peer, sizeof(struct GNUNET_PeerIdentity));
752 memcpy(&(tsrm->finger), source_finger, sizeof(struct GNUNET_PeerIdentity));
753 tsrm->trail_length = htonl(trail_length);
754 tsrm->current_index = htonl(current_trial_index);
755 peer_list = (struct GNUNET_PeerIdentity *) &tsrm[1];
756 memcpy(peer_list, trail_peer_list, trail_length * sizeof(struct GNUNET_PeerIdentity));
758 /* Send the message to chosen friend. */
759 GNUNET_CONTAINER_DLL_insert_tail (current_destination->head, current_destination->tail, pending);
761 current_destination->pending_count++;
762 process_friend_queue (current_destination);
766 /**FIXME: Old implementation just to remove error
767 * TODO: Modify this function to handle our get request.
768 * Perform a GET operation. Forwards the given request to other
769 * peers. Does not lookup the key locally. May do nothing if this is
770 * the only peer in the network (or if we are the closest peer in the
773 * @param type type of the block
774 * @param options routing options
775 * @param desired_replication_level desired replication count
776 * @param hop_count how many hops did this request traverse so far?
777 * @param key key for the content
778 * @param xquery extended query
779 * @param xquery_size number of bytes in @a xquery
780 * @param reply_bf bloomfilter to filter duplicates
781 * @param reply_bf_mutator mutator for @a reply_bf
782 * @param peer_bf filter for peers not to select (again)
785 GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
786 enum GNUNET_DHT_RouteOption options,
787 uint32_t desired_replication_level,
788 uint32_t hop_count, const struct GNUNET_HashCode * key,
789 const void *xquery, size_t xquery_size,
790 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
791 uint32_t reply_bf_mutator,
792 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
797 /**FIXME: Old implementation just to remove error.
798 * TODO: Modify this function to handle our put request.
799 * Perform a PUT operation. Forwards the given request to other
800 * peers. Does not store the data locally. Does not give the
801 * data to local clients. May do nothing if this is the only
802 * peer in the network (or if we are the closest peer in the
805 * @param type type of the block
806 * @param options routing options
807 * @param desired_replication_level desired replication count
808 * @param expiration_time when does the content expire
809 * @param hop_count how many hops has this message traversed so far
810 * @param bf Bloom filter of peers this PUT has already traversed
811 * @param key key for the content
812 * @param put_path_length number of entries in @a put_path
813 * @param put_path peers this request has traversed so far (if tracked)
814 * @param data payload to store
815 * @param data_size number of bytes in @a data
818 GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type,
819 enum GNUNET_DHT_RouteOption options,
820 uint32_t desired_replication_level,
821 struct GNUNET_TIME_Absolute expiration_time,
823 struct GNUNET_CONTAINER_BloomFilter *bf,
824 const struct GNUNET_HashCode *key,
825 unsigned int put_path_length,
826 struct GNUNET_PeerIdentity *put_path,
827 const void *data, size_t data_size)
833 /**FIXME: Old implementation just to remove error.
834 * Handle a reply (route to origin). Only forwards the reply back to
835 * other peers waiting for it. Does not do local caching or
836 * forwarding to local clients.
838 * @param target neighbour that should receive the block (if still connected)
839 * @param type type of the block
840 * @param expiration_time when does the content expire
841 * @param key key for the content
842 * @param put_path_length number of entries in put_path
843 * @param put_path peers the original PUT traversed (if tracked)
844 * @param get_path_length number of entries in put_path
845 * @param get_path peers this reply has traversed so far (if tracked)
846 * @param data payload of the reply
847 * @param data_size number of bytes in data
850 GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
851 enum GNUNET_BLOCK_Type type,
852 struct GNUNET_TIME_Absolute expiration_time,
853 const struct GNUNET_HashCode * key,
854 unsigned int put_path_length,
855 const struct GNUNET_PeerIdentity *put_path,
856 unsigned int get_path_length,
857 const struct GNUNET_PeerIdentity *get_path,
858 const void *data, size_t data_size)
865 * Randomly choose one of your friends from the friends_peer map
868 static struct FriendInfo *
869 select_random_friend()
871 unsigned int current_size;
874 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
875 struct GNUNET_PeerIdentity key_ret;
876 struct FriendInfo *friend;
878 current_size = GNUNET_CONTAINER_multipeermap_size(friend_peermap);
880 /* Element stored at this index in friend_peermap should be selected friend. */
881 index = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, current_size);
883 /* Create an iterator for friend_peermap. */
884 iter = GNUNET_CONTAINER_multipeermap_iterator_create(friend_peermap);
886 /* Set the position of iterator to index. */
889 if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next(iter,NULL,NULL))
895 if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next(iter,&key_ret,(const void **)&friend))
905 * Compute finger_identity to which we want to setup the trail
906 * FIXME: If we maintain a index that is value of current_finger_index
907 * to which a particular entry in finger map corresponds then should we first
908 * check if there is already an entry for that index. If yes then don't
909 * search for trail to that finger.
910 * @return finger_identity
913 struct GNUNET_PeerIdentity *
914 compute_finger_identity()
916 struct GNUNET_PeerIdentity *finger_identity;
918 finger_identity = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
919 finger_identity = GNUNET_CRYPTO_compute_finger_identity(&my_identity,current_finger_index );
921 current_finger_index = (current_finger_index+1) % MAX_FINGERS;
923 /* Check if you already have an entry in finger_peermap for this finger_id.
924 If yes then again look for a new finger_id.
925 FIXME: Should we return NULL here?
926 if(NULL != GNUNET_CONTAINER_multipeermap_get(finger_peermap,finger_peer_id))
928 finger_peer_id = compute_finger_identity();
931 return finger_identity;
936 * TODO: Implement after testing friend/finger map.
937 * TODO: Handle the case when we already have a trail to our predecessor in
939 * This function will be needed when we are handling node joins/fails
940 * to maintain correct pointer to our predecessor and successor in the network.
941 * Find immediate predecessor in the network.
942 * @param me my own identity
943 * @return peer identity of immediate predecessor.
946 struct GNUNET_PeerIdentity *
947 find_immediate_predecessor()
949 /* Using your own peer identity, calculate your predecessor
950 * in the network. Try to setup path to this predecessor using
951 * the same logic as used for other fingers.
952 * If we already have a trail to our predecessor then send NULL and
953 * calling function should be able to handle that case.
960 * Task to send a find finger trail message. We attempt to find trail
961 * to our finger in the network.
963 * @param cls closure for this task
964 * @param tc the context under which the task is running
967 send_find_finger_trail_message (void *cls,
968 const struct GNUNET_SCHEDULER_TaskContext *tc)
970 struct GNUNET_PeerIdentity *finger_identity;
971 struct FriendInfo *friend;
972 struct GNUNET_TIME_Relative next_send_time;
974 /* We already have found trail to each of our possible fingers in the network. */
975 if (GNUNET_CONTAINER_multipeermap_size (finger_peermap) == MAX_FINGERS)
977 /* FIXME: I call find_immediate_predecessor when I have found trail to
978 * all the possible fingers in the network. But we need to find immediate
979 * predecessor when there is a node failure/join. It may happen before.
980 * Think of a better strategy to decide when to call this function.
981 * We can find trail to our immediate predecessor in the network.
983 finger_identity = find_immediate_predecessor();
985 if(NULL == finger_identity)
987 /* We already have a trail to reach to immediate predecessor. */
988 goto new_find_finger_trail_request;
993 /* Find the finger_peer_id for which we want to setup the trail */
994 finger_identity = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
995 finger_identity = compute_finger_identity();
997 if(finger_identity == NULL)
999 goto new_find_finger_trail_request;
1003 friend = GNUNET_malloc (sizeof (struct FriendInfo));
1004 friend = select_random_friend();
1006 /* We found a friend.*/
1009 GDS_NEIGHBOURS_handle_trail_setup(&my_identity,finger_identity,friend,1,NULL);
1012 /* FIXME: Should we be using current_finger_index to generate random interval.*/
1013 new_find_finger_trail_request:
1014 next_send_time.rel_value_us =
1015 DHT_MINIMUM_FIND_FINGER_TRAIL_INTERVAL.rel_value_us +
1016 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1017 DHT_MAXIMUM_FIND_FINGER_TRAIL_INTERVAL.rel_value_us /
1018 (current_finger_index + 1));
1020 find_finger_trail_task =
1021 GNUNET_SCHEDULER_add_delayed (next_send_time, &send_find_finger_trail_message,
1027 * Method called whenever a peer connects.
1029 * @param cls closure
1030 * @param peer peer identity this notification is about
1033 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
1035 struct FriendInfo *ret;
1037 /* Check for connect to self message */
1038 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042 "Connected to %s\n",
1045 /* If peer already exists in our friend_peermap, then exit. */
1047 GNUNET_CONTAINER_multipeermap_contains (friend_peermap,
1054 GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# peers connected"), 1,
1057 ret = GNUNET_new (struct FriendInfo);
1060 GNUNET_assert (GNUNET_OK ==
1061 GNUNET_CONTAINER_multipeermap_put (friend_peermap,
1063 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1065 /* got a first connection, good time to start with FIND FINGER TRAIL requests... */
1066 if (1 == GNUNET_CONTAINER_multipeermap_size (friend_peermap))
1067 find_finger_trail_task = GNUNET_SCHEDULER_add_now (&send_find_finger_trail_message, NULL);
1072 * FIXME: Implement after testing finger/friend table setup.
1073 * Method called whenever a peer disconnects.
1075 * @param cls closure
1076 * @param peer peer identity this notification is about
1079 handle_core_disconnect (void *cls,
1080 const struct GNUNET_PeerIdentity *peer)
1083 * 1. remove the friend from the friend map.
1084 * 2. remove the trail for the fingers for which this peer was the first hop.
1085 * 3. start send_find_finger_trail for these fingers to find a new trail
1087 * 4. Also when a node gets disconnected, how should we update pointers of its
1088 * immediate successor and predecessor in the network ?
1089 * 5. Also how do we distribute the keys in the network?
1090 * 6. Here is case where we started put operation but a peer got disconnected and
1091 we removed the entry from the table. How to handle such a case.
1097 * To be called on core init/fail.
1099 * @param cls service closure
1100 * @param identity the public identity of this peer
1103 core_init (void *cls,
1104 const struct GNUNET_PeerIdentity *identity)
1106 my_identity = *identity;
1107 GNUNET_CRYPTO_hash (identity,
1108 sizeof (struct GNUNET_PeerIdentity),
1114 * Core handler for p2p put requests.
1116 * @param cls closure
1117 * @param peer sender of the request
1118 * @param message message
1119 * @param peer peer identity this notification is about
1120 * @return #GNUNET_OK to keep the connection open,
1121 * #GNUNET_SYSERR to close it (signal serious error)
1124 handle_dht_p2p_put (void *cls,
1125 const struct GNUNET_PeerIdentity *peer,
1126 const struct GNUNET_MessageHeader *message)
1129 1. Search the friend,finger and check your own id to find the closest
1130 * predecessor the given key. --> find_predecessor()
1131 2. If self then datache_store
1132 3. If friend, then add to peer queue
1133 4. If finger, then add to the peer queue of the first hop.
1134 * in put message also maintain a field current_destination and use
1135 * same logic as trail setup to understand if you are just part of trail
1136 * to reach to a particular peer or you are endpoint of trail or just a friend.
1144 * Core handler for p2p get requests.
1146 * @param cls closure
1147 * @param peer sender of the request
1148 * @param message message
1149 * @return #GNUNET_OK to keep the connection open,
1150 * #GNUNET_SYSERR to close it (signal serious error)
1153 handle_dht_p2p_get (void *cls, const struct GNUNET_PeerIdentity *peer,
1154 const struct GNUNET_MessageHeader *message)
1161 * Core handler for p2p result messages.
1163 * @param cls closure
1164 * @param message message
1165 * @param peer peer identity this notification is about
1166 * @return #GNUNET_YES (do not cut p2p connection)
1169 handle_dht_p2p_result (void *cls, const struct GNUNET_PeerIdentity *peer,
1170 const struct GNUNET_MessageHeader *message)
1178 * 1. Where do we use mod MAX_FINGERS?
1179 * 2. You are not using mod when searching for the closest successor of a finger.
1180 * 3. * 6. When I change the logic for find_successor, then I need to compare the interval
1181 * of two fingers. for that do I need to maintain a finger index and calculate
1183 * @param destination
1184 * @param flag Set the value of flag to 0, if next_hop = friend/1 if next_hop = finger.
1185 * @param current_destination We should set this field to finger id/friend id chosen to be next_hop.
1188 static struct GNUNET_PeerIdentity *
1189 find_successor(struct GNUNET_PeerIdentity *destination,
1190 struct GNUNET_PeerIdentity *current_destination,
1191 enum current_destination_type *type)
1194 * 1. Compare your identity with destination identity.
1195 * 2. Iterate over friend_map to find the peer identity with identity >= destination
1196 * 3. Iterate over finger_map to find the peer identity with identity >= destination
1197 * 4. Compare id,friend and finger to select one which is the least and still >= destination.
1198 * 5. If friend/my_identity then flag = 0
1199 * 6. If finger, then flag = 1.
1200 * 7. Set the current_destination value with chosen friend/finger/my_identity
1201 * 8. If finger, then search in your own finger table send the next hop to reach that finger.
1203 unsigned int friend_index;
1204 unsigned int finger_index;
1205 struct GNUNET_CONTAINER_MultiPeerMapIterator *friend_iter;
1206 struct GNUNET_CONTAINER_MultiPeerMapIterator *finger_iter;
1207 struct GNUNET_PeerIdentity key_ret;
1208 struct FriendInfo *friend;
1209 struct FingerInfo *finger;
1210 struct GNUNET_PeerIdentity *current_successor;
1212 /* FIXME: Temporary field used to understand if we got a friend or finger
1213 as next successor. find something better. */
1215 int finger_peer = 0;
1216 int friend_peer = 1;
1219 current_successor = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1221 /* initialize current_successor with your own identity. */
1222 memcpy(current_successor,&my_identity,sizeof(struct GNUNET_PeerIdentity));
1225 friend_iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap);
1227 /*iterate over friend map till you reach a peer id such that destination <= peer id */
1228 for (friend_index = 0; friend_index < GNUNET_CONTAINER_multipeermap_size (friend_peermap); friend_index++)
1230 if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next(friend_iter,&key_ret,(const void **)&friend))
1232 if(0 > GNUNET_CRYPTO_cmp_peer_identity(&friend->id,destination) ||
1233 (0 == GNUNET_CRYPTO_cmp_peer_identity(&friend->id,destination)))
1235 /* If yes then check if finger <= current_successor */
1236 if(0 < GNUNET_CRYPTO_cmp_peer_identity(&friend->id,current_successor) ||
1237 (0 == GNUNET_CRYPTO_cmp_peer_identity(&friend->id,current_successor)))
1239 memcpy(current_successor,friend,sizeof(struct GNUNET_PeerIdentity));
1240 successor = friend_peer;
1247 finger_iter = GNUNET_CONTAINER_multipeermap_iterator_create (finger_peermap);
1248 /* iterate over finger map till you reach a peer id such that destination <= peer id */
1249 for (finger_index = 0; finger_index < GNUNET_CONTAINER_multipeermap_size (finger_peermap); finger_index++)
1251 if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next(finger_iter,&key_ret,(const void **)&finger))
1253 if(0 > GNUNET_CRYPTO_cmp_peer_identity(&finger->id,destination) ||
1254 (0 == GNUNET_CRYPTO_cmp_peer_identity(&finger->id,destination)))
1256 /* If yes then check if finger <= current_friend_successor */
1257 if(0 < GNUNET_CRYPTO_cmp_peer_identity(&finger->id,current_successor)
1258 || (0 == GNUNET_CRYPTO_cmp_peer_identity(&finger->id,current_successor)))
1260 memcpy(current_successor,finger,sizeof(struct GNUNET_PeerIdentity));
1261 successor = finger_peer;
1267 memcpy(current_destination,current_successor,sizeof(struct GNUNET_PeerIdentity));
1269 if(successor == finger_peer)
1275 /* The successor is either my_identity or friend. */
1279 return current_successor;
1284 * @param cls closure
1285 * @param message message
1286 * @param peer peer identity this notification is about
1287 * @return #GNUNET_YES
1290 handle_dht_p2p_trail_setup(void *cls, const struct GNUNET_PeerIdentity *peer,
1291 const struct GNUNET_MessageHeader *message)
1293 struct PeerTrailSetupMessage *trail_setup;
1294 struct GNUNET_PeerIdentity *next_hop;
1295 struct FriendInfo *target_friend;
1297 uint32_t trail_length;
1298 enum current_destination_type peer_type;
1299 struct GNUNET_PeerIdentity *trail_peer_list;
1300 uint32_t current_trail_index;
1301 struct GNUNET_PeerIdentity *next_peer;
1303 /* parse and validate message. */
1304 msize = ntohs (message->size);
1305 if (msize < sizeof (struct PeerTrailSetupMessage))
1307 GNUNET_break_op (0);
1311 trail_setup = (struct PeerTrailSetupMessage *) message;
1312 trail_length = ntohl (trail_setup->trail_length);
1313 peer_type = ntohl (trail_setup->current_destination_type);
1314 trail_peer_list = (struct GNUNET_PeerIdentity *) &trail_setup[1];
1317 sizeof (struct PeerTrailSetupMessage) +
1318 trail_length * sizeof (struct GNUNET_PeerIdentity)) ||
1320 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
1322 GNUNET_break_op (0);
1327 GNUNET_STATISTICS_update (GDS_stats,
1328 gettext_noop ("# TRAIL SETUP requests received"), 1,
1330 GNUNET_STATISTICS_update (GDS_stats,
1331 gettext_noop ("# TRAIL SETUP bytes received"), msize,
1334 if(peer_type == FRIEND)
1336 if(0 == (GNUNET_CRYPTO_cmp_peer_identity(&(trail_setup->current_destination),&my_identity)))
1338 next_hop = find_successor(&(trail_setup->destination_finger),&(trail_setup->current_destination),&(peer_type));
1341 return GNUNET_SYSERR;
1345 if(0 != (GNUNET_CRYPTO_cmp_peer_identity(&(trail_setup->current_destination),&my_identity)))
1347 /* I am part of trail. */
1348 next_hop = GDS_ROUTING_search(&(trail_setup->source_peer),&(trail_setup->destination_finger));
1351 call find_successor and compare the two peer ids
1352 and choose whichever is closest to the destination finger. */
1356 /* I am the current_destination finger */
1357 next_hop = find_successor(&(trail_setup->destination_finger),&(trail_setup->current_destination),&(peer_type));
1361 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, next_hop);
1363 /* Add yourself to list of peers that trail setup message have traversed so far
1364 and increment trail length. */
1365 struct GNUNET_PeerIdentity *peer_list;
1366 peer_list = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity) * trail_length);
1367 memcpy(peer_list, trail_peer_list, trail_length * sizeof (struct GNUNET_PeerIdentity));
1368 peer_list[trail_length] = *next_hop;
1371 /* Check if you are next hop, if yes then you have reached the final destination. */
1372 if(0 == (GNUNET_CRYPTO_cmp_peer_identity(next_hop,&my_identity)))
1374 /* FIXME: Trail length should be const. */
1375 current_trail_index = trail_length - 1;
1376 next_peer = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity)); //FIXME: Do we need to allocate the memory?
1377 memcpy(next_peer, &peer_list[trail_length-1], sizeof (struct GNUNET_PeerIdentity));
1378 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, next_peer);
1380 GDS_NEIGHBOURS_handle_trail_setup_result(&(trail_setup->source_peer),
1381 &(trail_setup->destination_finger),
1382 target_friend, trail_length,
1383 peer_list,current_trail_index);
1387 if(peer_type == FINGER)
1389 GDS_ROUTING_add(&(trail_setup->source_peer),&(trail_setup->current_destination),next_hop);
1392 GDS_NEIGHBOURS_handle_trail_setup(&(trail_setup->source_peer),
1393 &(trail_setup->destination_finger),
1395 trail_setup->trail_length,
1402 * FIXME : Add interval field.
1403 * Add an entry in finger table.
1404 * @param finger Finger to be added to finger table
1405 * @param peer_list peers this request has traversed so far
1406 * @param trail_length Numbers of peers in the trail.
1409 void finger_table_add(struct GNUNET_PeerIdentity *finger,
1410 const struct GNUNET_PeerIdentity *peer_list,
1411 unsigned int trail_length)
1413 struct FingerInfo *finger_entry;
1415 finger_entry = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
1416 memcpy(&(finger_entry->id), finger, sizeof(struct GNUNET_PeerIdentity));
1417 memcpy(&(finger_entry->trail_peer_list), peer_list, sizeof(struct GNUNET_PeerIdentity)
1423 * Core handle for p2p trail construction result messages.
1424 * @param cls closure
1425 * @param message message
1426 * @param peer peer identity this notification is about
1427 * @return #GNUNET_YES
1430 handle_dht_p2p_trail_setup_result(void *cls, const struct GNUNET_PeerIdentity *peer,
1431 const struct GNUNET_MessageHeader *message)
1433 struct PeerTrailSetupResultMessage *trail_result;
1435 uint32_t trail_length;
1436 const struct GNUNET_PeerIdentity *trail_peer_list;
1437 uint32_t current_trail_index;
1438 struct GNUNET_PeerIdentity *next_peer;
1439 struct FriendInfo *target_friend;
1441 msize = ntohs (message->size);
1442 if (msize < sizeof (struct PeerTrailSetupMessage))
1444 GNUNET_break_op (0);
1448 trail_result = (struct PeerTrailSetupResultMessage *) message;
1449 trail_length = ntohl (trail_result->trail_length);
1450 current_trail_index = ntohl(trail_result->current_index);
1451 trail_peer_list = (struct GNUNET_PeerIdentity *) &trail_result[1];
1454 sizeof (struct PeerTrailSetupResultMessage) +
1455 trail_length * sizeof (struct GNUNET_PeerIdentity)) ||
1457 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
1459 GNUNET_break_op (0);
1463 if(0 == (GNUNET_CRYPTO_cmp_peer_identity (&(trail_result->current_destination), &my_identity)))
1465 /* Am I the destination? */
1466 if( 0 == (GNUNET_CRYPTO_cmp_peer_identity(&(trail_result->destination_peer), &my_identity)))
1468 finger_table_add(&(trail_result->finger), trail_peer_list,trail_length);
1473 next_peer = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1474 current_trail_index = current_trail_index - 1;
1475 memcpy(next_peer, &(trail_peer_list[trail_length-1]), sizeof (struct GNUNET_PeerIdentity));
1476 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap, next_peer);
1478 GDS_NEIGHBOURS_handle_trail_setup_result(&(trail_result->destination_peer),
1479 &(trail_result->finger),
1480 target_friend, trail_length,
1481 trail_peer_list,current_trail_index);
1486 return GNUNET_SYSERR;
1491 * Initialize neighbours subsystem.
1492 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1495 GDS_NEIGHBOURS_init()
1497 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1498 {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_P2P_GET, 0},
1499 {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_P2P_PUT, 0},
1500 {&handle_dht_p2p_result, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, 0},
1501 {&handle_dht_p2p_trail_setup, GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_SETUP, 0},
1502 {&handle_dht_p2p_trail_setup_result, GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_SETUP_RESULT, 0},
1506 /*ASK: What is ATS? Why do we need it? */
1507 atsAPI = GNUNET_ATS_performance_init (GDS_cfg, NULL, NULL);
1509 GNUNET_CORE_connect (GDS_cfg, NULL, &core_init, &handle_core_connect,
1510 &handle_core_disconnect, NULL, GNUNET_NO, NULL,
1511 GNUNET_NO, core_handlers);
1512 if (core_api == NULL)
1513 return GNUNET_SYSERR;
1515 friend_peermap = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
1516 finger_peermap = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
1523 * Shutdown neighbours subsystem.
1526 GDS_NEIGHBOURS_done ()
1528 if (NULL == core_api)
1531 GNUNET_CORE_disconnect (core_api);
1533 GNUNET_ATS_performance_done (atsAPI);
1536 /* FIXME: Once handle_core_disconnect is implemented, both below assertion should not
1538 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friend_peermap));
1539 GNUNET_CONTAINER_multipeermap_destroy (friend_peermap);
1540 friend_peermap = NULL;
1542 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (finger_peermap));
1543 GNUNET_CONTAINER_multipeermap_destroy (finger_peermap);
1544 finger_peermap = NULL;
1546 if (GNUNET_SCHEDULER_NO_TASK != find_finger_trail_task)
1548 GNUNET_SCHEDULER_cancel (find_finger_trail_task);
1549 find_finger_trail_task = GNUNET_SCHEDULER_NO_TASK;
1555 * Get the ID of the local node.
1557 * @return identity of the local node
1559 struct GNUNET_PeerIdentity *
1560 GDS_NEIGHBOURS_get_id ()
1562 return &my_identity;
1566 /* end of gnunet-service-xdht_neighbours.c */