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.
81 * Information we keep per trail.
87 * MDLL entry in the list of all trails with the same predecessor.
89 struct Trail *prev_succ;
92 * MDLL entry in the list of all trails with the same predecessor.
94 struct Trail *next_succ;
97 * MDLL entry in the list of all trails with the same predecessor.
99 struct Trail *prev_pred;
102 * MDLL entry in the list of all trails with the same predecessor.
104 struct Trail *next_pred;
107 * Our predecessor in the trail, NULL if we are initiator (?).
109 struct FriendInfo *pred;
112 * Our successor in the trail, NULL if we are the last peer.
114 struct FriendInfo *succ;
117 * Identifier of the trail with the predecessor.
119 struct GNUNET_HashCode pred_id;
122 * Identifier of the trail with the successor.
124 struct GNUNET_HashCode succ_id;
127 * When does this trail expire.
129 struct GNUNET_TIME_Absolute expiration_time;
132 * Location of this trail in the heap.
134 struct GNUNET_CONTAINER_HeapNode *hn;
137 * If this peer started the to create a Finger (and thus @e pred is
138 * NULL), this is the Finger we are trying to intialize.
140 struct Finger **finger;
146 * Entry in #friends_peermap.
153 struct GNUNET_PeerIdentity id;
158 struct Trail *pred_head;
163 struct Trail *pred_tail;
168 struct Trail *succ_head;
173 struct Trail *succ_tail;
176 * Core handle for sending messages to this friend.
178 struct GNUNET_MQ_Handle *mq;
202 struct FingerTable *ft;
207 struct GNUNET_HashCode destination;
210 * #GNUNET_YES if a response has been received. Otherwise #GNUNET_NO.
219 * Array of our fingers, unsorted.
221 struct Finger **fingers;
224 * Array of sorted fingers (sorted by destination, valid fingers first).
226 struct Finger **sorted_fingers;
229 * Size of the finger array.
231 unsigned int finger_array_size;
234 * Number of valid entries in @e sorted_fingers (contiguous from offset 0)
236 unsigned int number_valid_fingers;
239 * Which offset in @e fingers will we redo next.
241 unsigned int walk_offset;
244 * Is the finger array sorted?
251 /*********************** end of the db structure part ***********************/
254 GNUNET_NETWORK_STRUCT_BEGIN
257 * Setup a finger using the underlay topology ("social network").
259 struct RandomWalkMessage
262 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK
264 struct GNUNET_MessageHeader header;
267 * Number of hops this message has taken so far, we stop at
270 uint16_t hops_taken GNUNET_PACKED;
273 * Layer for the request, in NBO.
275 uint16_t layer GNUNET_PACKED;
278 * Unique (random) identifier this peer will use to
279 * identify the trail (in future messages).
281 struct GNUNET_HashCode trail_id;
286 * Response to a `struct RandomWalkMessage`.
288 struct RandomWalkResponseMessage
291 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
293 struct GNUNET_MessageHeader header;
296 * Zero, for alignment.
298 uint32_t reserved GNUNET_PACKED;
301 * Unique (random) identifier from the
302 * `struct RandomWalkMessage`.
304 struct GNUNET_HashCode trail_id;
307 * Random location in the respective layer where the
308 * random path of the finger setup terminated.
310 struct GNUNET_HashCode location;
315 * Response to an event that causes a trail to die.
317 struct TrailDestroyMessage
320 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY
322 struct GNUNET_MessageHeader header;
325 * Zero, for alignment.
327 uint32_t reserved GNUNET_PACKED;
330 * Unique (random) identifier this peer will use to
331 * identify the finger (in future messages).
333 struct GNUNET_HashCode trail_id;
339 * Send a message along a trail.
341 struct FindSuccessorMessage
344 * Type: #GNUNET_MESSAGE_TYPE_WDHT_FIND_SUCCESSOR
346 struct GNUNET_MessageHeader header;
349 * Zero, for alignment.
351 uint32_t reserved GNUNET_PACKED;
354 * Unique (random) identifier this peer will use to
355 * identify the finger (in future messages).
357 struct GNUNET_HashCode trail_id;
360 * Key for which we would like close values returned.
361 * identify the finger (in future messages).
363 struct GNUNET_HashCode key;
369 * Send a message along a trail.
371 struct TrailRouteMessage
374 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE
376 struct GNUNET_MessageHeader header;
379 * #GNUNET_YES if the path should be recorded, #GNUNET_NO if not; in NBO.
381 uint16_t record_path GNUNET_PACKED;
384 * Length of the recorded trail, 0 if @e record_path is #GNUNET_NO; in NBO.
386 uint16_t path_length GNUNET_PACKED;
389 * Unique (random) identifier this peer will use to
390 * identify the finger (in future messages).
392 struct GNUNET_HashCode trail_id;
395 * Path the message has taken so far (excluding sender).
397 /* struct GNUNET_PeerIdentity path[path_length]; */
399 /* followed by payload (another `struct GNUNET_MessageHeader`) to
400 send along the trail */
407 struct PeerPutMessage
410 * Type: #GNUNET_MESSAGE_TYPE_WDHT_PUT
412 struct GNUNET_MessageHeader header;
417 uint32_t options GNUNET_PACKED;
422 uint32_t block_type GNUNET_PACKED;
427 uint32_t hop_count GNUNET_PACKED;
430 * Replication level for this message
431 * In the current implementation, this value is not used.
433 uint32_t desired_replication_level GNUNET_PACKED;
436 * Length of the PUT path that follows (if tracked).
438 uint32_t put_path_length GNUNET_PACKED;
441 * When does the content expire?
443 struct GNUNET_TIME_AbsoluteNBO expiration_time;
446 * The key to store the value under.
448 struct GNUNET_HashCode key GNUNET_PACKED;
450 /* put path (if tracked) */
459 struct PeerGetMessage
462 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET
464 struct GNUNET_MessageHeader header;
469 uint32_t options GNUNET_PACKED;
472 * Desired content type.
474 uint32_t block_type GNUNET_PACKED;
479 uint32_t hop_count GNUNET_PACKED;
482 * Desired replication level for this request.
483 * In the current implementation, this value is not used.
485 uint32_t desired_replication_level GNUNET_PACKED;
488 * Total number of peers in get path.
490 unsigned int get_path_length;
493 * The key we are looking for.
495 struct GNUNET_HashCode key;
498 /* struct GNUNET_PeerIdentity[]*/
505 struct PeerGetResultMessage
508 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT
510 struct GNUNET_MessageHeader header;
513 * The type for the data in NBO.
515 uint32_t type GNUNET_PACKED;
518 * Number of peers recorded in the outgoing path from source to the
519 * stored location of this message.
521 uint32_t put_path_length GNUNET_PACKED;
524 * When does the content expire?
526 struct GNUNET_TIME_AbsoluteNBO expiration_time;
529 * The key of the corresponding GET request.
531 struct GNUNET_HashCode key;
533 /* put path (if tracked) */
539 GNUNET_NETWORK_STRUCT_END
543 * Contains all the layered IDs of this peer.
545 struct GNUNET_PeerIdentity layered_id[NUMBER_LAYERED_ID];
548 * Task to timeout trails that have expired.
550 static struct GNUNET_SCHEDULER_Task *trail_timeout_task;
553 * Task to perform random walks.
555 static struct GNUNET_SCHEDULER_Task *random_walk_task;
558 * Identity of this peer.
560 static struct GNUNET_PeerIdentity my_identity;
563 * Peer map of all the friends of a peer
565 static struct GNUNET_CONTAINER_MultiPeerMap *friends_peermap;
570 static struct FingerTable fingers[NUMBER_LAYERED_ID];
573 * Tail map, mapping tail identifiers to `struct Trail`s
575 static struct GNUNET_CONTAINER_MultiHashMap *trail_map;
578 * Tail heap, organizing trails by expiration time.
580 static struct GNUNET_CONTAINER_Heap *trail_heap;
585 static struct GNUNET_CORE_Handle *core_api;
589 * Handle the put request from the client.
591 * @param key Key for the content
592 * @param block_type Type of the block
593 * @param options Routing options
594 * @param desired_replication_level Desired replication count
595 * @param expiration_time When does the content expire
596 * @param data Content to store
597 * @param data_size Size of content @a data in bytes
600 GDS_NEIGHBOURS_handle_put (const struct GNUNET_HashCode *key,
601 enum GNUNET_BLOCK_Type block_type,
602 enum GNUNET_DHT_RouteOption options,
603 uint32_t desired_replication_level,
604 struct GNUNET_TIME_Absolute expiration_time,
608 GDS_DATACACHE_handle_put (expiration_time,
615 GDS_CLIENTS_process_put (options,
627 * Handle the get request from the client file. If I am destination do
628 * datacache put and return. Else find the target friend and forward message
631 * @param key Key for the content
632 * @param block_type Type of the block
633 * @param options Routing options
634 * @param desired_replication_level Desired replication count
637 GDS_NEIGHBOURS_handle_get (const struct GNUNET_HashCode *key,
638 enum GNUNET_BLOCK_Type block_type,
639 enum GNUNET_DHT_RouteOption options,
640 uint32_t desired_replication_level)
642 // find closest finger(s) on all layers
643 // use TrailRoute with PeerGetMessage embedded to contact peer
648 * Delete a trail, it died (timeout, link failure, etc.).
650 * @param trail trail to delete from all data structures
651 * @param inform_pred should we notify the predecessor?
652 * @param inform_succ should we inform the successor?
655 delete_trail (struct Trail *trail,
659 struct FriendInfo *friend;
660 struct GNUNET_MQ_Envelope *env;
661 struct TrailDestroyMessage *tdm;
662 struct Finger *finger;
664 friend = trail->pred;
667 if (GNUNET_YES == inform_pred)
669 env = GNUNET_MQ_msg (tdm,
670 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
671 tdm->trail_id = trail->pred_id;
672 GNUNET_MQ_send (friend->mq,
675 GNUNET_CONTAINER_MDLL_remove (pred,
680 friend = trail->succ;
683 if (GNUNET_YES == inform_succ)
685 env = GNUNET_MQ_msg (tdm,
686 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
687 tdm->trail_id = trail->pred_id;
688 GNUNET_MQ_send (friend->mq,
691 GNUNET_CONTAINER_MDLL_remove (succ,
696 GNUNET_break (trail ==
697 GNUNET_CONTAINER_heap_remove_node (trail->hn));
698 finger = *trail->finger;
701 *trail->finger = NULL;
702 GNUNET_free (finger);
712 forward_message_on_trail (struct FriendInfo *next_target,
713 const struct GNUNET_HashCode *trail_id,
715 const struct GNUNET_PeerIdentity *predecessor,
716 const struct GNUNET_PeerIdentity *path,
717 uint16_t path_length,
718 const struct GNUNET_MessageHeader *payload)
720 struct GNUNET_MQ_Envelope *env;
721 struct TrailRouteMessage *trm;
722 struct GNUNET_PeerIdentity *new_path;
724 uint16_t payload_len;
726 payload_len = ntohs (payload->size);
729 plen = path_length + 1;
730 if (plen >= (GNUNET_SERVER_MAX_MESSAGE_SIZE
732 - sizeof (struct TrailRouteMessage))
733 / sizeof (struct GNUNET_PeerIdentity))
735 /* Should really not have paths this long... */
743 GNUNET_break_op (0 == path_length);
747 env = GNUNET_MQ_msg_extra (trm,
749 plen * sizeof (struct GNUNET_PeerIdentity),
750 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE);
751 trm->record_path = htons (have_path);
752 trm->path_length = htons (plen);
753 trm->trail_id = *trail_id;
754 new_path = (struct GNUNET_PeerIdentity *) &trm[1];
759 path_length * sizeof (struct GNUNET_PeerIdentity));
760 new_path[path_length] = *predecessor;
762 memcpy (&new_path[plen],
765 GNUNET_MQ_send (next_target->mq,
771 * Send the get result to requesting client.
773 * @param trail_id trail identifying where to send the result to, NULL for us
774 * @param options routing options (from GET request)
775 * @param key Key of the requested data.
776 * @param type Block type
777 * @param put_path_length Number of peers in @a put_path
778 * @param put_path Path taken to put the data at its stored location.
779 * @param expiration When will this result expire?
780 * @param data Payload to store
781 * @param data_size Size of the @a data
784 GDS_NEIGHBOURS_send_get_result (const struct GNUNET_HashCode *trail_id,
785 enum GNUNET_DHT_RouteOption options,
786 const struct GNUNET_HashCode *key,
787 enum GNUNET_BLOCK_Type type,
788 unsigned int put_path_length,
789 const struct GNUNET_PeerIdentity *put_path,
790 struct GNUNET_TIME_Absolute expiration,
794 struct GNUNET_MessageHeader *payload;
797 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
801 /* TODO: inform statistics */
804 if (NULL == trail->pred)
806 /* result is for *us* (local client) */
807 GDS_CLIENTS_handle_reply (expiration,
810 put_path_length, put_path,
817 payload = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader) + data_size);
818 payload->size = data_size;
819 payload->type = GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT;
821 forward_message_on_trail (trail->pred,
823 0 /* FIXME: put something right */,
832 * Method called whenever a peer disconnects.
835 * @param peer peer identity this notification is about
838 handle_core_disconnect (void *cls,
839 const struct GNUNET_PeerIdentity *peer)
841 struct FriendInfo *remove_friend;
844 /* If disconnected to own identity, then return. */
845 if (0 == memcmp (&my_identity,
847 sizeof (struct GNUNET_PeerIdentity)))
850 if (NULL == (remove_friend =
851 GNUNET_CONTAINER_multipeermap_get (friends_peermap,
858 GNUNET_assert (GNUNET_YES ==
859 GNUNET_CONTAINER_multipeermap_remove (friends_peermap,
862 while (NULL != (t = remove_friend->succ_head))
866 while (NULL != (t = remove_friend->pred_head))
870 GNUNET_MQ_destroy (remove_friend->mq);
871 GNUNET_free (remove_friend);
873 GNUNET_CONTAINER_multipeermap_size (friends_peermap))
875 GNUNET_SCHEDULER_cancel (random_walk_task);
876 random_walk_task = NULL;
882 * Function called with a random friend to be returned.
884 * @param cls a `struct FriendInfo **` with where to store the result
885 * @param peer the peer identity of the friend (ignored)
886 * @param value the `struct FriendInfo *` that was selected at random
887 * @return #GNUNET_OK (all good)
890 pick_random_helper (void *cls,
891 const struct GNUNET_PeerIdentity *peer,
894 struct FriendInfo **fi = cls;
895 struct FriendInfo *v = value;
903 * Pick random friend from friends for random walk.
905 * @return NULL if we have no friends
907 static struct FriendInfo *
908 pick_random_friend ()
910 struct FriendInfo *ret;
914 GNUNET_CONTAINER_multipeermap_get_random (friends_peermap,
923 * One of our trails might have timed out, check and
924 * possibly initiate cleanup.
930 trail_timeout_callback (void *cls,
931 const struct GNUNET_SCHEDULER_TaskContext *tc)
934 struct GNUNET_TIME_Relative left;
936 trail_timeout_task = NULL;
937 while (NULL != (trail = GNUNET_CONTAINER_heap_peek (trail_heap)))
939 left = GNUNET_TIME_absolute_get_remaining (trail->expiration_time);
940 if (0 != left.rel_value_us)
947 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (left,
948 &trail_timeout_callback,
954 * Initiate a random walk.
960 do_random_walk (void *cls,
961 const struct GNUNET_SCHEDULER_TaskContext *tc)
963 static unsigned int walk_layer;
964 struct FriendInfo *friend;
965 struct GNUNET_MQ_Envelope *env;
966 struct RandomWalkMessage *rwm;
967 struct FingerTable *ft;
968 struct Finger *finger;
971 random_walk_task = NULL;
972 friend = pick_random_friend ();
974 trail = GNUNET_new (struct Trail);
975 /* We create the random walk so, no predecessor */
976 trail->succ = friend;
977 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
980 GNUNET_CONTAINER_multihashmap_put (trail_map,
983 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
989 GNUNET_CONTAINER_MDLL_insert (succ,
993 trail->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
994 trail->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
996 trail->expiration_time.abs_value_us);
997 if (NULL == trail_timeout_task)
998 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
999 &trail_timeout_callback,
1001 env = GNUNET_MQ_msg (rwm,
1002 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1003 rwm->hops_taken = htonl (0);
1004 rwm->trail_id = trail->succ_id;
1005 GNUNET_MQ_send (friend->mq,
1007 /* clean up 'old' entry (implicitly via trail cleanup) */
1008 ft = &fingers[walk_layer];
1010 if ( (NULL != ft->fingers) &&
1011 (NULL != (finger = ft->fingers[ft->walk_offset])) )
1012 delete_trail (finger->trail,
1015 if (ft->finger_array_size < 42)
1017 // FIXME: must have finger array of the right size here,
1018 // FIXME: growing / shrinking are tricky -- with pointers
1022 GNUNET_assert (NULL == ft->fingers[ft->walk_offset]);
1024 finger = GNUNET_new (struct Finger);
1025 finger->trail = trail;
1026 trail->finger = &ft->fingers[ft->walk_offset];
1028 ft->fingers[ft->walk_offset] = finger;
1029 ft->is_sorted = GNUNET_NO;
1030 ft->walk_offset = (ft->walk_offset + 1) % ft->finger_array_size;
1032 walk_layer = (walk_layer + 1) % NUMBER_LAYERED_ID;
1033 random_walk_task = GNUNET_SCHEDULER_add_delayed (RANDOM_WALK_DELAY,
1040 * Method called whenever a peer connects.
1042 * @param cls closure
1043 * @param peer_identity peer identity this notification is about
1046 handle_core_connect (void *cls,
1047 const struct GNUNET_PeerIdentity *peer_identity)
1049 struct FriendInfo *friend;
1051 /* Check for connect to self message */
1052 if (0 == memcmp (&my_identity,
1054 sizeof (struct GNUNET_PeerIdentity)))
1057 /* If peer already exists in our friend_peermap, then exit. */
1059 GNUNET_CONTAINER_multipeermap_contains (friends_peermap,
1066 friend = GNUNET_new (struct FriendInfo);
1067 friend->id = *peer_identity;
1068 friend->mq = GNUNET_CORE_mq_create (core_api,
1070 GNUNET_assert (GNUNET_OK ==
1071 GNUNET_CONTAINER_multipeermap_put (friends_peermap,
1074 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1075 if (NULL == random_walk_task)
1077 /* random walk needs to be started -- we have a first connection */
1078 random_walk_task = GNUNET_SCHEDULER_add_now (&do_random_walk,
1085 * To be called on core init/fail.
1087 * @param cls service closure
1088 * @param identity the public identity of this peer
1091 core_init (void *cls,
1092 const struct GNUNET_PeerIdentity *identity)
1094 my_identity = *identity;
1099 * Handle a `struct RandomWalkMessage` from a
1100 * #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK message.
1102 * @param cls closure (NULL)
1103 * @param peer sender identity
1104 * @param message the setup message
1105 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1108 handle_dht_p2p_random_walk (void *cls,
1109 const struct GNUNET_PeerIdentity *peer,
1110 const struct GNUNET_MessageHeader *message)
1112 const struct RandomWalkMessage *m;
1114 struct FriendInfo *pred;
1116 m = (const struct RandomWalkMessage *) message;
1117 pred = GNUNET_CONTAINER_multipeermap_get (friends_peermap,
1119 t = GNUNET_new (struct Trail);
1120 t->pred_id = m->trail_id;
1123 GNUNET_CONTAINER_multihashmap_put (trail_map,
1126 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1128 GNUNET_break_op (0);
1130 return GNUNET_SYSERR;
1132 GNUNET_CONTAINER_MDLL_insert (pred,
1136 t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1137 t->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1139 t->expiration_time.abs_value_us);
1140 if (NULL == trail_timeout_task)
1141 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1142 &trail_timeout_callback,
1145 if (ntohl (m->hops_taken) > GDS_NSE_get ())
1147 /* We are the last hop, generate response */
1148 struct GNUNET_MQ_Envelope *env;
1149 struct RandomWalkResponseMessage *rwrm;
1152 env = GNUNET_MQ_msg (rwrm,
1153 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
1154 rwrm->reserved = htonl (0);
1155 rwrm->trail_id = m->trail_id;
1156 layer = ntohs (m->layer);
1158 (void) GDS_DATACACHE_get_random_key (&rwrm->location);
1161 struct FingerTable *ft;
1163 if (layer > NUMBER_LAYERED_ID)
1165 GNUNET_break_op (0);
1166 // FIXME: clean up 't'...
1167 return GNUNET_SYSERR;
1169 ft = &fingers[layer-1];
1170 if (0 == ft->number_valid_fingers)
1172 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1179 f = ft->fingers[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1180 ft->number_valid_fingers)];
1181 rwrm->location = f->destination;
1184 GNUNET_MQ_send (pred->mq,
1189 struct GNUNET_MQ_Envelope *env;
1190 struct RandomWalkMessage *rwm;
1191 struct FriendInfo *succ;
1193 /* extend the trail by another random hop */
1194 succ = pick_random_friend ();
1195 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1199 GNUNET_CONTAINER_multihashmap_put (trail_map,
1202 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1205 GNUNET_CONTAINER_MDLL_remove (pred,
1212 GNUNET_CONTAINER_MDLL_insert (succ,
1216 env = GNUNET_MQ_msg (rwm,
1217 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1218 rwm->hops_taken = htons (1 + ntohs (m->hops_taken));
1219 rwm->layer = m->layer;
1220 rwm->trail_id = t->succ_id;
1221 GNUNET_MQ_send (succ->mq,
1229 * Handle a `struct RandomWalkResponseMessage` from a GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
1232 * @param cls closure (NULL)
1233 * @param peer sender identity
1234 * @param message the setup response message
1235 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1238 handle_dht_p2p_random_walk_response (void *cls,
1239 const struct GNUNET_PeerIdentity *peer,
1240 const struct GNUNET_MessageHeader *message)
1242 const struct RandomWalkResponseMessage *rwrm;
1244 rwrm = (const struct RandomWalkResponseMessage *) message;
1245 // 1) lookup trail => find Finger entry => fill in 'destination' and mark valid, move to end of sorted array,
1246 //mark unsorted, update links from 'trails'
1249 * 1 check if we are the correct layer
1250 * 1.a if true : add the returned value (finger) in the db structure
1251 * 1.b if true : do nothing
1253 /* FIXME: add the value in db structure 1.a */
1260 * Handle a `struct TrailDestroyMessage`.
1262 * @param cls closure (NULL)
1263 * @param peer sender identity
1264 * @param message the finger destroy message
1265 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1268 handle_dht_p2p_trail_destroy (void *cls,
1269 const struct GNUNET_PeerIdentity *peer,
1270 const struct GNUNET_MessageHeader *message)
1272 const struct TrailDestroyMessage *tdm;
1273 struct Trail *trail;
1275 tdm = (const struct TrailDestroyMessage *) message;
1276 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1278 delete_trail (trail,
1279 ( (NULL != trail->succ) &&
1282 sizeof (struct GNUNET_PeerIdentity))) ),
1283 ( (NULL != trail->pred) &&
1286 sizeof (struct GNUNET_PeerIdentity))) ));
1292 * Handle a `struct FindSuccessorMessage` from a #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND
1295 * @param cls closure (NULL)
1296 * @param trail_id path to the originator
1297 * @param message the finger setup message
1298 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1301 handle_dht_p2p_successor_find (void *cls,
1302 const struct GNUNET_HashCode *trail_id,
1303 const struct GNUNET_MessageHeader *message)
1305 const struct FindSuccessorMessage *fsm;
1307 fsm = (const struct FindSuccessorMessage *) message;
1308 // locate trail (for sending reply), if not exists, fail nicely.
1309 // otherwise, go to datacache and return 'top k' elements closest to 'key'
1310 // as "PUT" messages via the trail (need to extend DB API!)
1312 GDS_DATACACHE_get_successors (trail_id,
1320 * Handle a `struct PeerGetMessage`.
1322 * @param cls closure (NULL)
1323 * @param trail_id path to the originator
1324 * @param message the peer get message
1325 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1328 handle_dht_p2p_peer_get (void *cls,
1329 const struct GNUNET_HashCode *trail_id,
1330 const struct GNUNET_MessageHeader *message)
1332 const struct PeerGetMessage *pgm;
1334 // FIXME: note: never called like this, message embedded with trail route!
1335 pgm = (const struct PeerGetMessage *) message;
1336 // -> lookup in datacache (figure out way to remember trail!)
1339 * 1 extract the result
1341 * 3 send it using the good trail
1343 * What do i do when i don't have the key/value?
1351 * Handle a `struct PeerGetResultMessage`.
1353 * @param cls closure (NULL)
1354 * @param trail_id path to the originator
1355 * @param message the peer get result message
1356 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1359 handle_dht_p2p_peer_get_result (void *cls,
1360 const struct GNUNET_HashCode *trail_id,
1361 const struct GNUNET_MessageHeader *message)
1363 const struct PeerGetResultMessage *pgrm;
1365 pgrm = (const struct PeerGetResultMessage *) message;
1366 // pretty much: parse, & pass to client (there is some call for that...)
1369 GDS_CLIENTS_process_get (options,
1374 (void) GDS_DATACACHE_handle_get (trail_id,
1387 * Handle a `struct PeerPutMessage`.
1389 * @param cls closure (NULL)
1390 * @param trail_id path to the originator
1391 * @param message the peer put message
1392 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1395 handle_dht_p2p_peer_put (void *cls,
1396 const struct GNUNET_HashCode *trail_id,
1397 const struct GNUNET_MessageHeader *message)
1399 const struct PeerGetResultMessage *pgrm;
1401 pgrm = (const struct PeerGetResultMessage *) message;
1402 // parse & store in datacache, this is in response to us asking for successors.
1405 * 1 check the size of the message
1406 * 2 use the API to add the value in the "database". Check on the xdht file, how to do it.
1407 * 3 Did i a have to return a notification or did i have to return GNUNET_[OK|SYSERR]?
1410 GDS_DATACACHE_handle_put (expiration_time,
1416 GDS_CLIENTS_process_put (options,
1432 * Handler for a message we received along some trail.
1434 * @param cls closure
1435 * @param trail_id trail identifier
1436 * @param message the message we got
1437 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1440 (*TrailHandlerCallback)(void *cls,
1441 const struct GNUNET_HashCode *trail_id,
1442 const struct GNUNET_MessageHeader *message);
1446 * Definition of a handler for a message received along some trail.
1451 * NULL for end-of-list.
1453 TrailHandlerCallback callback;
1456 * Closure for @e callback.
1461 * Message type this handler addresses.
1463 uint16_t message_type;
1466 * Use 0 for variable-size.
1468 uint16_t message_size;
1473 * Handle a `struct TrailRouteMessage`.
1475 * @param cls closure (NULL)
1476 * @param peer sender identity
1477 * @param message the finger destroy message
1478 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1481 handle_dht_p2p_trail_route (void *cls,
1482 const struct GNUNET_PeerIdentity *peer,
1483 const struct GNUNET_MessageHeader *message)
1485 static const struct TrailHandler handlers[] = {
1486 { &handle_dht_p2p_successor_find, NULL,
1487 GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND,
1488 sizeof (struct FindSuccessorMessage) },
1489 { NULL, NULL, 0, 0 }
1492 const struct TrailRouteMessage *trm;
1493 const struct GNUNET_PeerIdentity *path;
1494 uint16_t path_length;
1495 const struct GNUNET_MessageHeader *payload;
1496 const struct TrailHandler *th;
1497 struct Trail *trail;
1500 /* Parse and check message is well-formed */
1501 msize = ntohs (message->size);
1502 if (msize < sizeof (struct TrailRouteMessage))
1504 GNUNET_break_op (0);
1507 trm = (const struct TrailRouteMessage *) message;
1508 path_length = ntohs (trm->path_length);
1509 if (msize < sizeof (struct TrailRouteMessage) +
1510 path_length * sizeof (struct GNUNET_PeerIdentity) +
1511 sizeof (struct GNUNET_MessageHeader) )
1513 GNUNET_break_op (0);
1516 path = (const struct GNUNET_PeerIdentity *) &trm[1];
1517 payload = (const struct GNUNET_MessageHeader *) &path[path_length];
1518 if (msize != (ntohs (payload->size) +
1519 sizeof (struct TrailRouteMessage) +
1520 path_length * sizeof (struct GNUNET_PeerIdentity)))
1522 GNUNET_break_op (0);
1526 /* Is this message for us? */
1527 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1529 if ( (NULL != trail->pred) &&
1532 sizeof (struct GNUNET_PeerIdentity))) )
1534 /* forward to 'successor' */
1535 if (NULL != trail->succ)
1537 forward_message_on_trail (trail->succ,
1539 ntohs (trm->record_path),
1549 /* forward to 'predecessor' */
1550 GNUNET_break_op ( (NULL != trail->succ) &&
1553 sizeof (struct GNUNET_PeerIdentity))) );
1554 if (NULL != trail->pred)
1556 forward_message_on_trail (trail->pred,
1558 ntohs (trm->record_path),
1567 /* Message is for us, dispatch to handler */
1569 for (i=0; NULL != handlers[i].callback; i++)
1572 if (ntohs (payload->type) == th->message_type)
1574 if ( (0 == th->message_size) ||
1575 (ntohs (payload->size) == th->message_size) )
1576 th->callback (th->cls,
1580 GNUNET_break_op (0);
1584 GNUNET_break_op (NULL != th);
1590 * Initialize neighbours subsystem.
1591 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1594 GDS_NEIGHBOURS_init (void)
1596 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1597 { &handle_dht_p2p_random_walk,
1598 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK,
1599 sizeof (struct RandomWalkMessage) },
1600 { &handle_dht_p2p_random_walk_response,
1601 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE,
1602 sizeof (struct RandomWalkResponseMessage) },
1603 { &handle_dht_p2p_trail_destroy,
1604 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY,
1605 sizeof (struct TrailDestroyMessage) },
1606 { &handle_dht_p2p_trail_route,
1607 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE,
1613 GNUNET_CORE_connect (GDS_cfg, NULL,
1615 &handle_core_connect,
1616 &handle_core_disconnect,
1621 if (NULL == core_api)
1622 return GNUNET_SYSERR;
1623 friends_peermap = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
1624 trail_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
1625 trail_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1631 * Shutdown neighbours subsystem.
1634 GDS_NEIGHBOURS_done (void)
1636 if (NULL == core_api)
1638 GNUNET_CORE_disconnect (core_api);
1640 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap));
1641 GNUNET_CONTAINER_multipeermap_destroy (friends_peermap);
1642 friends_peermap = NULL;
1643 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (trail_map));
1644 GNUNET_CONTAINER_multihashmap_destroy (trail_map);
1646 GNUNET_CONTAINER_heap_destroy (trail_heap);
1648 if (NULL != trail_timeout_task)
1650 GNUNET_SCHEDULER_cancel (trail_timeout_task);
1651 trail_timeout_task = NULL;
1659 * @return my identity
1661 struct GNUNET_PeerIdentity
1662 GDS_NEIGHBOURS_get_my_id (void)
1667 /* end of gnunet-service-wdht_neighbours.c */