2 This file is part of GNUnet.
3 Copyright (C) 2009-2015 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.
21 * @file dht/gnunet-service-wdht_neighbours.c
22 * @brief GNUnet DHT service's finger and friend table management code
23 * @author Supriti Singh
26 #include "gnunet_util_lib.h"
27 #include "gnunet_block_lib.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_ats_service.h"
32 #include "gnunet_core_service.h"
33 #include "gnunet_datacache_lib.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_dht_service.h"
36 #include "gnunet_statistics_service.h"
37 #include "gnunet-service-wdht.h"
38 #include "gnunet-service-wdht_clients.h"
39 #include "gnunet-service-wdht_datacache.h"
40 #include "gnunet-service-wdht_neighbours.h"
41 #include "gnunet-service-wdht_nse.h"
48 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
51 * Trail timeout. After what time do trails always die?
53 #define TRAIL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42)
56 * Random walk delay. How often do we walk the overlay?
58 #define RANDOM_WALK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42)
61 * The number of layered ID to use.
63 #define NUMBER_LAYERED_ID 8
66 * The number of random walk to launch at the beginning of the initialization
68 /* FIXME: find a better value */
69 #define NUMBER_RANDOM_WALK 20
72 /******************* The db structure and related functions *******************/
75 * Entry in #friends_peermap.
85 * Information we keep per trail.
91 * Identifier of the trail with the predecessor.
93 struct GNUNET_HashCode pred_id;
96 * Identifier of the trail with the successor.
98 struct GNUNET_HashCode succ_id;
101 * When does this trail expire.
103 struct GNUNET_TIME_Absolute expiration_time;
106 * MDLL entry in the list of all trails with the same predecessor.
108 struct Trail *prev_succ;
111 * MDLL entry in the list of all trails with the same predecessor.
113 struct Trail *next_succ;
116 * MDLL entry in the list of all trails with the same predecessor.
118 struct Trail *prev_pred;
121 * MDLL entry in the list of all trails with the same predecessor.
123 struct Trail *next_pred;
126 * Our predecessor in the trail, NULL if we are initiator (?).
128 struct FriendInfo *pred;
131 * Our successor in the trail, NULL if we are the last peer.
133 struct FriendInfo *succ;
136 * Location of this trail in the heap.
138 struct GNUNET_CONTAINER_HeapNode *hn;
141 * If this peer started the to create a Finger (and thus @e pred is
142 * NULL), this is the finger table of the finger we are trying to
145 struct FingerTable *ft;
148 * If this peer started the trail to create a Finger (and thus @e
149 * pred is NULL), this is the offset of the finger we are trying to
150 * intialize in the unsorted array.
152 unsigned int finger_off;
158 * Entry in #friends_peermap.
165 struct GNUNET_PeerIdentity id;
170 struct Trail *pred_head;
175 struct Trail *pred_tail;
180 struct Trail *succ_head;
185 struct Trail *succ_tail;
188 * Core handle for sending messages to this friend.
190 struct GNUNET_MQ_Handle *mq;
208 struct FingerTable *ft;
213 struct GNUNET_HashCode destination;
216 * #GNUNET_YES if a response has been received. Otherwise #GNUNET_NO.
225 * Array of our fingers, unsorted.
227 struct Finger **fingers;
230 * Size of the finger array.
232 unsigned int finger_array_size;
235 * Number of valid entries in @e fingers
237 unsigned int number_valid_fingers;
240 * Which offset in @e fingers will we redo next.
242 unsigned int walk_offset;
245 * Is the finger array sorted?
252 /*********************** end of the db structure part ***********************/
255 GNUNET_NETWORK_STRUCT_BEGIN
258 * Setup a finger using the underlay topology ("social network").
260 struct RandomWalkMessage
263 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK
265 struct GNUNET_MessageHeader header;
268 * Number of hops this message has taken so far, we stop at
271 uint16_t hops_taken GNUNET_PACKED;
274 * Layer for the request, in NBO.
276 uint16_t layer GNUNET_PACKED;
279 * Unique (random) identifier this peer will use to
280 * identify the trail (in future messages).
282 struct GNUNET_HashCode trail_id;
287 * Response to a `struct RandomWalkMessage`.
289 struct RandomWalkResponseMessage
292 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
294 struct GNUNET_MessageHeader header;
297 * Zero, for alignment.
299 uint32_t reserved GNUNET_PACKED;
302 * Unique (random) identifier from the
303 * `struct RandomWalkMessage`.
305 struct GNUNET_HashCode trail_id;
308 * Random location in the respective layer where the
309 * random path of the finger setup terminated.
311 struct GNUNET_HashCode location;
316 * Response to an event that causes a trail to die.
318 struct TrailDestroyMessage
321 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY
323 struct GNUNET_MessageHeader header;
326 * Zero, for alignment.
328 uint32_t reserved GNUNET_PACKED;
331 * Unique (random) identifier this peer will use to
332 * identify the finger (in future messages).
334 struct GNUNET_HashCode trail_id;
340 * Send a message along a trail.
342 struct FindSuccessorMessage
345 * Type: #GNUNET_MESSAGE_TYPE_WDHT_FIND_SUCCESSOR
347 struct GNUNET_MessageHeader header;
350 * Zero, for alignment.
352 uint32_t reserved GNUNET_PACKED;
355 * Unique (random) identifier this peer will use to
356 * identify the finger (in future messages).
358 struct GNUNET_HashCode trail_id;
361 * Key for which we would like close values returned.
362 * identify the finger (in future messages).
364 struct GNUNET_HashCode key;
370 * Send a message along a trail.
372 struct TrailRouteMessage
375 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE
377 struct GNUNET_MessageHeader header;
380 * #GNUNET_YES if the path should be recorded, #GNUNET_NO if not; in NBO.
382 uint16_t record_path GNUNET_PACKED;
385 * Length of the recorded trail, 0 if @e record_path is #GNUNET_NO; in NBO.
387 uint16_t path_length GNUNET_PACKED;
390 * Unique (random) identifier this peer will use to
391 * identify the finger (in future messages).
393 struct GNUNET_HashCode trail_id;
396 * Path the message has taken so far (excluding sender).
398 /* struct GNUNET_PeerIdentity path[path_length]; */
400 /* followed by payload (another `struct GNUNET_MessageHeader`) to
401 send along the trail */
408 struct PeerPutMessage
411 * Type: #GNUNET_MESSAGE_TYPE_WDHT_PUT
413 struct GNUNET_MessageHeader header;
418 uint32_t options GNUNET_PACKED;
423 uint32_t block_type GNUNET_PACKED;
428 uint32_t hop_count GNUNET_PACKED;
431 * Replication level for this message
432 * In the current implementation, this value is not used.
434 uint32_t desired_replication_level GNUNET_PACKED;
437 * Length of the PUT path that follows (if tracked).
439 uint32_t put_path_length GNUNET_PACKED;
442 * When does the content expire?
444 struct GNUNET_TIME_AbsoluteNBO expiration_time;
447 * The key to store the value under.
449 struct GNUNET_HashCode key GNUNET_PACKED;
451 /* put path (if tracked) */
460 struct PeerGetMessage
463 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET
465 struct GNUNET_MessageHeader header;
470 uint32_t options GNUNET_PACKED;
473 * Desired content type.
475 uint32_t block_type GNUNET_PACKED;
480 uint32_t hop_count GNUNET_PACKED;
483 * Desired replication level for this request.
484 * In the current implementation, this value is not used.
486 uint32_t desired_replication_level GNUNET_PACKED;
489 * Total number of peers in get path.
491 unsigned int get_path_length;
494 * The key we are looking for.
496 struct GNUNET_HashCode key;
499 /* struct GNUNET_PeerIdentity[]*/
506 struct PeerGetResultMessage
509 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT
511 struct GNUNET_MessageHeader header;
514 * The type for the data in NBO.
516 uint32_t type GNUNET_PACKED;
519 * Number of peers recorded in the outgoing path from source to the
520 * stored location of this message.
522 uint32_t put_path_length GNUNET_PACKED;
525 * When does the content expire?
527 struct GNUNET_TIME_AbsoluteNBO expiration_time;
530 * The key of the corresponding GET request.
532 struct GNUNET_HashCode key;
534 /* put path (if tracked) */
540 GNUNET_NETWORK_STRUCT_END
544 * Contains all the layered IDs of this peer.
546 struct GNUNET_PeerIdentity layered_id[NUMBER_LAYERED_ID];
549 * Task to timeout trails that have expired.
551 static struct GNUNET_SCHEDULER_Task *trail_timeout_task;
554 * Task to perform random walks.
556 static struct GNUNET_SCHEDULER_Task *random_walk_task;
559 * Identity of this peer.
561 static struct GNUNET_PeerIdentity my_identity;
564 * Peer map of all the friends of a peer
566 static struct GNUNET_CONTAINER_MultiPeerMap *friends_peermap;
571 static struct FingerTable fingers[NUMBER_LAYERED_ID];
574 * Tail map, mapping tail identifiers to `struct Trail`s
576 static struct GNUNET_CONTAINER_MultiHashMap *trail_map;
579 * Tail heap, organizing trails by expiration time.
581 static struct GNUNET_CONTAINER_Heap *trail_heap;
586 static struct GNUNET_CORE_Handle *core_api;
590 * Handle the put request from the client.
592 * @param key Key for the content
593 * @param block_type Type of the block
594 * @param options Routing options
595 * @param desired_replication_level Desired replication count
596 * @param expiration_time When does the content expire
597 * @param data Content to store
598 * @param data_size Size of content @a data in bytes
601 GDS_NEIGHBOURS_handle_put (const struct GNUNET_HashCode *key,
602 enum GNUNET_BLOCK_Type block_type,
603 enum GNUNET_DHT_RouteOption options,
604 uint32_t desired_replication_level,
605 struct GNUNET_TIME_Absolute expiration_time,
609 GDS_DATACACHE_handle_put (expiration_time,
616 GDS_CLIENTS_process_put (options,
628 * Handle the get request from the client file. If I am destination do
629 * datacache put and return. Else find the target friend and forward message
632 * @param key Key for the content
633 * @param block_type Type of the block
634 * @param options Routing options
635 * @param desired_replication_level Desired replication count
638 GDS_NEIGHBOURS_handle_get (const struct GNUNET_HashCode *key,
639 enum GNUNET_BLOCK_Type block_type,
640 enum GNUNET_DHT_RouteOption options,
641 uint32_t desired_replication_level)
643 // find closest finger(s) on all layers
644 // use TrailRoute with PeerGetMessage embedded to contact peer
649 * Delete a trail, it died (timeout, link failure, etc.).
651 * @param trail trail to delete from all data structures
652 * @param inform_pred should we notify the predecessor?
653 * @param inform_succ should we inform the successor?
656 delete_trail (struct Trail *trail,
660 struct FriendInfo *friend;
661 struct GNUNET_MQ_Envelope *env;
662 struct TrailDestroyMessage *tdm;
663 struct Finger *finger;
665 friend = trail->pred;
668 if (GNUNET_YES == inform_pred)
670 env = GNUNET_MQ_msg (tdm,
671 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
672 tdm->trail_id = trail->pred_id;
673 GNUNET_MQ_send (friend->mq,
676 GNUNET_CONTAINER_MDLL_remove (pred,
681 friend = trail->succ;
684 if (GNUNET_YES == inform_succ)
686 env = GNUNET_MQ_msg (tdm,
687 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
688 tdm->trail_id = trail->pred_id;
689 GNUNET_MQ_send (friend->mq,
692 GNUNET_CONTAINER_MDLL_remove (succ,
697 GNUNET_break (trail ==
698 GNUNET_CONTAINER_heap_remove_node (trail->hn));
699 finger = trail->ft->fingers[trail->finger_off];
702 trail->ft->fingers[trail->finger_off] = NULL;
703 trail->ft->number_valid_fingers--;
704 GNUNET_free (finger);
714 forward_message_on_trail (struct FriendInfo *next_target,
715 const struct GNUNET_HashCode *trail_id,
717 const struct GNUNET_PeerIdentity *predecessor,
718 const struct GNUNET_PeerIdentity *path,
719 uint16_t path_length,
720 const struct GNUNET_MessageHeader *payload)
722 struct GNUNET_MQ_Envelope *env;
723 struct TrailRouteMessage *trm;
724 struct GNUNET_PeerIdentity *new_path;
726 uint16_t payload_len;
728 payload_len = ntohs (payload->size);
731 plen = path_length + 1;
732 if (plen >= (GNUNET_SERVER_MAX_MESSAGE_SIZE
734 - sizeof (struct TrailRouteMessage))
735 / sizeof (struct GNUNET_PeerIdentity))
737 /* Should really not have paths this long... */
745 GNUNET_break_op (0 == path_length);
749 env = GNUNET_MQ_msg_extra (trm,
751 plen * sizeof (struct GNUNET_PeerIdentity),
752 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE);
753 trm->record_path = htons (have_path);
754 trm->path_length = htons (plen);
755 trm->trail_id = *trail_id;
756 new_path = (struct GNUNET_PeerIdentity *) &trm[1];
761 path_length * sizeof (struct GNUNET_PeerIdentity));
762 new_path[path_length] = *predecessor;
764 memcpy (&new_path[plen],
767 GNUNET_MQ_send (next_target->mq,
773 * Send the get result to requesting client.
775 * @param trail_id trail identifying where to send the result to, NULL for us
776 * @param options routing options (from GET request)
777 * @param key Key of the requested data.
778 * @param type Block type
779 * @param put_path_length Number of peers in @a put_path
780 * @param put_path Path taken to put the data at its stored location.
781 * @param expiration When will this result expire?
782 * @param data Payload to store
783 * @param data_size Size of the @a data
786 GDS_NEIGHBOURS_send_get_result (const struct GNUNET_HashCode *trail_id,
787 enum GNUNET_DHT_RouteOption options,
788 const struct GNUNET_HashCode *key,
789 enum GNUNET_BLOCK_Type type,
790 unsigned int put_path_length,
791 const struct GNUNET_PeerIdentity *put_path,
792 struct GNUNET_TIME_Absolute expiration,
796 struct GNUNET_MessageHeader *payload;
799 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
803 /* TODO: inform statistics */
806 if (NULL == trail->pred)
808 /* result is for *us* (local client) */
809 GDS_CLIENTS_handle_reply (expiration,
812 put_path_length, put_path,
819 payload = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader) + data_size);
820 payload->size = data_size;
821 payload->type = GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT;
823 forward_message_on_trail (trail->pred,
825 0 /* FIXME: put something right */,
829 GNUNET_free (payload);
834 * Method called whenever a peer disconnects.
837 * @param peer peer identity this notification is about
840 handle_core_disconnect (void *cls,
841 const struct GNUNET_PeerIdentity *peer)
843 struct FriendInfo *remove_friend;
846 /* If disconnected to own identity, then return. */
847 if (0 == memcmp (&my_identity,
849 sizeof (struct GNUNET_PeerIdentity)))
852 if (NULL == (remove_friend =
853 GNUNET_CONTAINER_multipeermap_get (friends_peermap,
860 GNUNET_assert (GNUNET_YES ==
861 GNUNET_CONTAINER_multipeermap_remove (friends_peermap,
864 while (NULL != (t = remove_friend->succ_head))
868 while (NULL != (t = remove_friend->pred_head))
872 GNUNET_MQ_destroy (remove_friend->mq);
873 GNUNET_free (remove_friend);
875 GNUNET_CONTAINER_multipeermap_size (friends_peermap))
877 GNUNET_SCHEDULER_cancel (random_walk_task);
878 random_walk_task = NULL;
884 * Function called with a random friend to be returned.
886 * @param cls a `struct FriendInfo **` with where to store the result
887 * @param peer the peer identity of the friend (ignored)
888 * @param value the `struct FriendInfo *` that was selected at random
889 * @return #GNUNET_OK (all good)
892 pick_random_helper (void *cls,
893 const struct GNUNET_PeerIdentity *peer,
896 struct FriendInfo **fi = cls;
897 struct FriendInfo *v = value;
905 * Pick random friend from friends for random walk.
907 * @return NULL if we have no friends
909 static struct FriendInfo *
910 pick_random_friend ()
912 struct FriendInfo *ret;
916 GNUNET_CONTAINER_multipeermap_get_random (friends_peermap,
925 * One of our trails might have timed out, check and
926 * possibly initiate cleanup.
932 trail_timeout_callback (void *cls,
933 const struct GNUNET_SCHEDULER_TaskContext *tc)
936 struct GNUNET_TIME_Relative left;
938 trail_timeout_task = NULL;
939 while (NULL != (trail = GNUNET_CONTAINER_heap_peek (trail_heap)))
941 left = GNUNET_TIME_absolute_get_remaining (trail->expiration_time);
942 if (0 != left.rel_value_us)
949 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (left,
950 &trail_timeout_callback,
956 * Compute how big our finger arrays should be (at least).
958 * @return size of the finger array, never 0
961 get_desired_finger_array_size ()
963 /* FIXME: This is just a stub... */
969 * Initiate a random walk.
975 do_random_walk (void *cls,
976 const struct GNUNET_SCHEDULER_TaskContext *tc)
978 static unsigned int walk_layer;
979 struct FriendInfo *friend;
980 struct GNUNET_MQ_Envelope *env;
981 struct RandomWalkMessage *rwm;
982 struct FingerTable *ft;
983 struct Finger *finger;
987 random_walk_task = NULL;
988 friend = pick_random_friend ();
990 trail = GNUNET_new (struct Trail);
991 /* We create the random walk so, no predecessor */
992 trail->succ = friend;
993 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
996 GNUNET_CONTAINER_multihashmap_put (trail_map,
999 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1002 GNUNET_free (trail);
1005 GNUNET_CONTAINER_MDLL_insert (succ,
1009 trail->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1010 trail->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1012 trail->expiration_time.abs_value_us);
1013 if (NULL == trail_timeout_task)
1014 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1015 &trail_timeout_callback,
1017 env = GNUNET_MQ_msg (rwm,
1018 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1019 rwm->hops_taken = htonl (0);
1020 rwm->trail_id = trail->succ_id;
1021 GNUNET_MQ_send (friend->mq,
1023 /* clean up 'old' entry (implicitly via trail cleanup) */
1024 ft = &fingers[walk_layer];
1026 if ( (NULL != ft->fingers) &&
1027 (NULL != (finger = ft->fingers[ft->walk_offset])) )
1028 delete_trail (finger->trail,
1031 if (ft->finger_array_size < (nsize = get_desired_finger_array_size()) )
1032 GNUNET_array_grow (ft->fingers,
1033 ft->finger_array_size,
1035 GNUNET_assert (NULL == ft->fingers[ft->walk_offset]);
1037 trail->finger_off = ft->walk_offset;
1038 finger = GNUNET_new (struct Finger);
1039 finger->trail = trail;
1041 ft->fingers[ft->walk_offset] = finger;
1042 ft->is_sorted = GNUNET_NO;
1043 ft->number_valid_fingers++;
1044 ft->walk_offset = (ft->walk_offset + 1) % ft->finger_array_size;
1046 walk_layer = (walk_layer + 1) % NUMBER_LAYERED_ID;
1047 random_walk_task = GNUNET_SCHEDULER_add_delayed (RANDOM_WALK_DELAY,
1054 * Method called whenever a peer connects.
1056 * @param cls closure
1057 * @param peer_identity peer identity this notification is about
1060 handle_core_connect (void *cls,
1061 const struct GNUNET_PeerIdentity *peer_identity)
1063 struct FriendInfo *friend;
1065 /* Check for connect to self message */
1066 if (0 == memcmp (&my_identity,
1068 sizeof (struct GNUNET_PeerIdentity)))
1071 /* If peer already exists in our friend_peermap, then exit. */
1073 GNUNET_CONTAINER_multipeermap_contains (friends_peermap,
1080 friend = GNUNET_new (struct FriendInfo);
1081 friend->id = *peer_identity;
1082 friend->mq = GNUNET_CORE_mq_create (core_api,
1084 GNUNET_assert (GNUNET_OK ==
1085 GNUNET_CONTAINER_multipeermap_put (friends_peermap,
1088 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1089 if (NULL == random_walk_task)
1091 /* random walk needs to be started -- we have a first connection */
1092 random_walk_task = GNUNET_SCHEDULER_add_now (&do_random_walk,
1099 * To be called on core init/fail.
1101 * @param cls service closure
1102 * @param identity the public identity of this peer
1105 core_init (void *cls,
1106 const struct GNUNET_PeerIdentity *identity)
1108 my_identity = *identity;
1113 * Handle a `struct RandomWalkMessage` from a
1114 * #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK message.
1116 * @param cls closure (NULL)
1117 * @param peer sender identity
1118 * @param message the setup message
1119 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1122 handle_dht_p2p_random_walk (void *cls,
1123 const struct GNUNET_PeerIdentity *peer,
1124 const struct GNUNET_MessageHeader *message)
1126 const struct RandomWalkMessage *m;
1128 struct FriendInfo *pred;
1131 m = (const struct RandomWalkMessage *) message;
1132 layer = ntohs (m->layer);
1133 if (layer > NUMBER_LAYERED_ID)
1135 GNUNET_break_op (0);
1136 return GNUNET_SYSERR;
1138 pred = GNUNET_CONTAINER_multipeermap_get (friends_peermap,
1140 t = GNUNET_new (struct Trail);
1141 t->pred_id = m->trail_id;
1144 GNUNET_CONTAINER_multihashmap_put (trail_map,
1147 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1149 GNUNET_break_op (0);
1151 return GNUNET_SYSERR;
1153 GNUNET_CONTAINER_MDLL_insert (pred,
1157 t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1158 t->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1160 t->expiration_time.abs_value_us);
1161 if (NULL == trail_timeout_task)
1162 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1163 &trail_timeout_callback,
1166 if (ntohl (m->hops_taken) > GDS_NSE_get ())
1168 /* We are the last hop, generate response */
1169 struct GNUNET_MQ_Envelope *env;
1170 struct RandomWalkResponseMessage *rwrm;
1172 env = GNUNET_MQ_msg (rwrm,
1173 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
1174 rwrm->reserved = htonl (0);
1175 rwrm->trail_id = m->trail_id;
1177 (void) GDS_DATACACHE_get_random_key (&rwrm->location);
1180 struct FingerTable *ft;
1182 ft = &fingers[layer-1];
1183 if (0 == ft->number_valid_fingers)
1185 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1194 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1195 ft->number_valid_fingers);
1196 for (i=0; (NULL == (f = ft->fingers[i])) || (off > 0); i++)
1197 if (NULL != f) off--;
1198 rwrm->location = f->destination;
1201 GNUNET_MQ_send (pred->mq,
1206 struct GNUNET_MQ_Envelope *env;
1207 struct RandomWalkMessage *rwm;
1208 struct FriendInfo *succ;
1210 /* extend the trail by another random hop */
1211 succ = pick_random_friend ();
1212 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1216 GNUNET_CONTAINER_multihashmap_put (trail_map,
1219 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1222 GNUNET_CONTAINER_MDLL_remove (pred,
1229 GNUNET_CONTAINER_MDLL_insert (succ,
1233 env = GNUNET_MQ_msg (rwm,
1234 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1235 rwm->hops_taken = htons (1 + ntohs (m->hops_taken));
1236 rwm->layer = m->layer;
1237 rwm->trail_id = t->succ_id;
1238 GNUNET_MQ_send (succ->mq,
1246 * Handle a `struct RandomWalkResponseMessage` from a GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
1249 * @param cls closure (NULL)
1250 * @param peer sender identity
1251 * @param message the setup response message
1252 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1255 handle_dht_p2p_random_walk_response (void *cls,
1256 const struct GNUNET_PeerIdentity *peer,
1257 const struct GNUNET_MessageHeader *message)
1259 const struct RandomWalkResponseMessage *rwrm;
1261 rwrm = (const struct RandomWalkResponseMessage *) message;
1262 // 1) lookup trail => find Finger entry => fill in 'destination' and mark valid, move to end of sorted array,
1263 //mark unsorted, update links from 'trails'
1266 * 1 check if we are the correct layer
1267 * 1.a if true : add the returned value (finger) in the db structure
1268 * 1.b if true : do nothing
1270 /* FIXME: add the value in db structure 1.a */
1277 * Handle a `struct TrailDestroyMessage`.
1279 * @param cls closure (NULL)
1280 * @param peer sender identity
1281 * @param message the finger destroy message
1282 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1285 handle_dht_p2p_trail_destroy (void *cls,
1286 const struct GNUNET_PeerIdentity *peer,
1287 const struct GNUNET_MessageHeader *message)
1289 const struct TrailDestroyMessage *tdm;
1290 struct Trail *trail;
1292 tdm = (const struct TrailDestroyMessage *) message;
1293 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1295 delete_trail (trail,
1296 ( (NULL != trail->succ) &&
1299 sizeof (struct GNUNET_PeerIdentity))) ),
1300 ( (NULL != trail->pred) &&
1303 sizeof (struct GNUNET_PeerIdentity))) ));
1309 * Handle a `struct FindSuccessorMessage` from a #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND
1312 * @param cls closure (NULL)
1313 * @param trail_id path to the originator
1314 * @param message the finger setup message
1315 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1318 handle_dht_p2p_successor_find (void *cls,
1319 const struct GNUNET_HashCode *trail_id,
1320 const struct GNUNET_MessageHeader *message)
1322 const struct FindSuccessorMessage *fsm;
1324 fsm = (const struct FindSuccessorMessage *) message;
1325 // locate trail (for sending reply), if not exists, fail nicely.
1326 // otherwise, go to datacache and return 'top k' elements closest to 'key'
1327 // as "PUT" messages via the trail (need to extend DB API!)
1329 GDS_DATACACHE_get_successors (trail_id,
1337 * Handle a `struct PeerGetMessage`.
1339 * @param cls closure (NULL)
1340 * @param trail_id path to the originator
1341 * @param message the peer get message
1342 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1345 handle_dht_p2p_peer_get (void *cls,
1346 const struct GNUNET_HashCode *trail_id,
1347 const struct GNUNET_MessageHeader *message)
1349 const struct PeerGetMessage *pgm;
1351 // FIXME: note: never called like this, message embedded with trail route!
1352 pgm = (const struct PeerGetMessage *) message;
1353 // -> lookup in datacache (figure out way to remember trail!)
1356 * 1 extract the result
1358 * 3 send it using the good trail
1360 * What do i do when i don't have the key/value?
1368 * Handle a `struct PeerGetResultMessage`.
1370 * @param cls closure (NULL)
1371 * @param trail_id path to the originator
1372 * @param message the peer get result message
1373 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1376 handle_dht_p2p_peer_get_result (void *cls,
1377 const struct GNUNET_HashCode *trail_id,
1378 const struct GNUNET_MessageHeader *message)
1380 const struct PeerGetResultMessage *pgrm;
1382 pgrm = (const struct PeerGetResultMessage *) message;
1383 // pretty much: parse, & pass to client (there is some call for that...)
1386 GDS_CLIENTS_process_get (options,
1391 (void) GDS_DATACACHE_handle_get (trail_id,
1404 * Handle a `struct PeerPutMessage`.
1406 * @param cls closure (NULL)
1407 * @param trail_id path to the originator
1408 * @param message the peer put message
1409 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1412 handle_dht_p2p_peer_put (void *cls,
1413 const struct GNUNET_HashCode *trail_id,
1414 const struct GNUNET_MessageHeader *message)
1416 const struct PeerGetResultMessage *pgrm;
1418 pgrm = (const struct PeerGetResultMessage *) message;
1419 // parse & store in datacache, this is in response to us asking for successors.
1422 * 1 check the size of the message
1423 * 2 use the API to add the value in the "database". Check on the xdht file, how to do it.
1424 * 3 Did i a have to return a notification or did i have to return GNUNET_[OK|SYSERR]?
1427 GDS_DATACACHE_handle_put (expiration_time,
1433 GDS_CLIENTS_process_put (options,
1449 * Handler for a message we received along some trail.
1451 * @param cls closure
1452 * @param trail_id trail identifier
1453 * @param message the message we got
1454 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1457 (*TrailHandlerCallback)(void *cls,
1458 const struct GNUNET_HashCode *trail_id,
1459 const struct GNUNET_MessageHeader *message);
1463 * Definition of a handler for a message received along some trail.
1468 * NULL for end-of-list.
1470 TrailHandlerCallback callback;
1473 * Closure for @e callback.
1478 * Message type this handler addresses.
1480 uint16_t message_type;
1483 * Use 0 for variable-size.
1485 uint16_t message_size;
1490 * Handle a `struct TrailRouteMessage`.
1492 * @param cls closure (NULL)
1493 * @param peer sender identity
1494 * @param message the finger destroy message
1495 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1498 handle_dht_p2p_trail_route (void *cls,
1499 const struct GNUNET_PeerIdentity *peer,
1500 const struct GNUNET_MessageHeader *message)
1502 static const struct TrailHandler handlers[] = {
1503 { &handle_dht_p2p_successor_find, NULL,
1504 GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND,
1505 sizeof (struct FindSuccessorMessage) },
1506 { &handle_dht_p2p_peer_get, NULL,
1507 GNUNET_MESSAGE_TYPE_WDHT_GET,
1508 sizeof (struct FindSuccessorMessage) },
1509 { &handle_dht_p2p_peer_get_result, NULL,
1510 GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT,
1512 { &handle_dht_p2p_peer_put, NULL,
1513 GNUNET_MESSAGE_TYPE_WDHT_PUT,
1515 { NULL, NULL, 0, 0 }
1518 const struct TrailRouteMessage *trm;
1519 const struct GNUNET_PeerIdentity *path;
1520 uint16_t path_length;
1521 const struct GNUNET_MessageHeader *payload;
1522 const struct TrailHandler *th;
1523 struct Trail *trail;
1526 /* Parse and check message is well-formed */
1527 msize = ntohs (message->size);
1528 if (msize < sizeof (struct TrailRouteMessage))
1530 GNUNET_break_op (0);
1533 trm = (const struct TrailRouteMessage *) message;
1534 path_length = ntohs (trm->path_length);
1535 if (msize < sizeof (struct TrailRouteMessage) +
1536 path_length * sizeof (struct GNUNET_PeerIdentity) +
1537 sizeof (struct GNUNET_MessageHeader) )
1539 GNUNET_break_op (0);
1542 path = (const struct GNUNET_PeerIdentity *) &trm[1];
1543 payload = (const struct GNUNET_MessageHeader *) &path[path_length];
1544 if (msize != (ntohs (payload->size) +
1545 sizeof (struct TrailRouteMessage) +
1546 path_length * sizeof (struct GNUNET_PeerIdentity)))
1548 GNUNET_break_op (0);
1552 /* Is this message for us? */
1553 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1555 if ( (NULL != trail->pred) &&
1558 sizeof (struct GNUNET_PeerIdentity))) )
1560 /* forward to 'successor' */
1561 if (NULL != trail->succ)
1563 forward_message_on_trail (trail->succ,
1565 ntohs (trm->record_path),
1575 /* forward to 'predecessor' */
1576 GNUNET_break_op ( (NULL != trail->succ) &&
1579 sizeof (struct GNUNET_PeerIdentity))) );
1580 if (NULL != trail->pred)
1582 forward_message_on_trail (trail->pred,
1584 ntohs (trm->record_path),
1593 /* Message is for us, dispatch to handler */
1595 for (i=0; NULL != handlers[i].callback; i++)
1598 if (ntohs (payload->type) == th->message_type)
1600 if ( (0 == th->message_size) ||
1601 (ntohs (payload->size) == th->message_size) )
1602 th->callback (th->cls,
1606 GNUNET_break_op (0);
1610 GNUNET_break_op (NULL != th);
1616 * Initialize neighbours subsystem.
1617 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1620 GDS_NEIGHBOURS_init (void)
1622 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1623 { &handle_dht_p2p_random_walk,
1624 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK,
1625 sizeof (struct RandomWalkMessage) },
1626 { &handle_dht_p2p_random_walk_response,
1627 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE,
1628 sizeof (struct RandomWalkResponseMessage) },
1629 { &handle_dht_p2p_trail_destroy,
1630 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY,
1631 sizeof (struct TrailDestroyMessage) },
1632 { &handle_dht_p2p_trail_route,
1633 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE,
1639 GNUNET_CORE_connect (GDS_cfg, NULL,
1641 &handle_core_connect,
1642 &handle_core_disconnect,
1647 if (NULL == core_api)
1648 return GNUNET_SYSERR;
1649 friends_peermap = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
1650 trail_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
1651 trail_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1657 * Shutdown neighbours subsystem.
1660 GDS_NEIGHBOURS_done (void)
1662 if (NULL == core_api)
1664 GNUNET_CORE_disconnect (core_api);
1666 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap));
1667 GNUNET_CONTAINER_multipeermap_destroy (friends_peermap);
1668 friends_peermap = NULL;
1669 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (trail_map));
1670 GNUNET_CONTAINER_multihashmap_destroy (trail_map);
1672 GNUNET_CONTAINER_heap_destroy (trail_heap);
1674 if (NULL != trail_timeout_task)
1676 GNUNET_SCHEDULER_cancel (trail_timeout_task);
1677 trail_timeout_task = NULL;
1685 * @return my identity
1687 struct GNUNET_PeerIdentity
1688 GDS_NEIGHBOURS_get_my_id (void)
1693 /* end of gnunet-service-wdht_neighbours.c */