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_SUCCESSOR_FIND
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
645 // NOTE: actually more complicated, see paper!
650 * Delete a trail, it died (timeout, link failure, etc.).
652 * @param trail trail to delete from all data structures
653 * @param inform_pred should we notify the predecessor?
654 * @param inform_succ should we inform the successor?
657 delete_trail (struct Trail *trail,
661 struct FriendInfo *friend;
662 struct GNUNET_MQ_Envelope *env;
663 struct TrailDestroyMessage *tdm;
664 struct Finger *finger;
666 friend = trail->pred;
669 if (GNUNET_YES == inform_pred)
671 env = GNUNET_MQ_msg (tdm,
672 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
673 tdm->trail_id = trail->pred_id;
674 GNUNET_MQ_send (friend->mq,
677 GNUNET_CONTAINER_MDLL_remove (pred,
682 friend = trail->succ;
685 if (GNUNET_YES == inform_succ)
687 env = GNUNET_MQ_msg (tdm,
688 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
689 tdm->trail_id = trail->pred_id;
690 GNUNET_MQ_send (friend->mq,
693 GNUNET_CONTAINER_MDLL_remove (succ,
698 GNUNET_break (trail ==
699 GNUNET_CONTAINER_heap_remove_node (trail->hn));
700 finger = trail->ft->fingers[trail->finger_off];
703 trail->ft->fingers[trail->finger_off] = NULL;
704 trail->ft->number_valid_fingers--;
705 GNUNET_free (finger);
712 * Forward the given payload message along the trail.
714 * @param next_target which direction along the trail should we forward
715 * @param trail_id which trail should we forward along
716 * @param have_path do we track the forwarding path?
717 * @param predecessor which peer do we tack on to the path?
718 * @param path path the message has taken so far along the trail
719 * @param path_length number of entries in @a path
720 * @param payload payload of the message
723 forward_message_on_trail (struct FriendInfo *next_target,
724 const struct GNUNET_HashCode *trail_id,
726 const struct GNUNET_PeerIdentity *predecessor,
727 const struct GNUNET_PeerIdentity *path,
728 uint16_t path_length,
729 const struct GNUNET_MessageHeader *payload)
731 struct GNUNET_MQ_Envelope *env;
732 struct TrailRouteMessage *trm;
733 struct GNUNET_PeerIdentity *new_path;
735 uint16_t payload_len;
737 payload_len = ntohs (payload->size);
740 plen = path_length + 1;
741 if (plen >= (GNUNET_SERVER_MAX_MESSAGE_SIZE
743 - sizeof (struct TrailRouteMessage))
744 / sizeof (struct GNUNET_PeerIdentity))
746 /* Should really not have paths this long... */
754 GNUNET_break_op (0 == path_length);
758 env = GNUNET_MQ_msg_extra (trm,
760 plen * sizeof (struct GNUNET_PeerIdentity),
761 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE);
762 trm->record_path = htons (have_path);
763 trm->path_length = htons (plen);
764 trm->trail_id = *trail_id;
765 new_path = (struct GNUNET_PeerIdentity *) &trm[1];
770 path_length * sizeof (struct GNUNET_PeerIdentity));
771 new_path[path_length] = *predecessor;
773 memcpy (&new_path[plen],
776 GNUNET_MQ_send (next_target->mq,
782 * Send the get result to requesting client.
784 * @param trail_id trail identifying where to send the result to, NULL for us
785 * @param options routing options (from GET request)
786 * @param key Key of the requested data.
787 * @param type Block type
788 * @param put_path_length Number of peers in @a put_path
789 * @param put_path Path taken to put the data at its stored location.
790 * @param expiration When will this result expire?
791 * @param data Payload to store
792 * @param data_size Size of the @a data
795 GDS_NEIGHBOURS_send_get_result (const struct GNUNET_HashCode *trail_id,
796 enum GNUNET_DHT_RouteOption options,
797 const struct GNUNET_HashCode *key,
798 enum GNUNET_BLOCK_Type type,
799 unsigned int put_path_length,
800 const struct GNUNET_PeerIdentity *put_path,
801 struct GNUNET_TIME_Absolute expiration,
805 struct GNUNET_MessageHeader *payload;
808 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
812 /* TODO: inform statistics */
815 if (NULL == trail->pred)
817 /* result is for *us* (local client) */
818 GDS_CLIENTS_handle_reply (expiration,
821 put_path_length, put_path,
828 payload = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader) + data_size);
829 payload->size = data_size;
830 payload->type = GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT;
832 forward_message_on_trail (trail->pred,
834 0 /* FIXME: put something right */,
838 GNUNET_free (payload);
843 * Method called whenever a peer disconnects.
846 * @param peer peer identity this notification is about
849 handle_core_disconnect (void *cls,
850 const struct GNUNET_PeerIdentity *peer)
852 struct FriendInfo *remove_friend;
855 /* If disconnected to own identity, then return. */
856 if (0 == memcmp (&my_identity,
858 sizeof (struct GNUNET_PeerIdentity)))
861 if (NULL == (remove_friend =
862 GNUNET_CONTAINER_multipeermap_get (friends_peermap,
869 GNUNET_assert (GNUNET_YES ==
870 GNUNET_CONTAINER_multipeermap_remove (friends_peermap,
873 while (NULL != (t = remove_friend->succ_head))
877 while (NULL != (t = remove_friend->pred_head))
881 GNUNET_MQ_destroy (remove_friend->mq);
882 GNUNET_free (remove_friend);
884 GNUNET_CONTAINER_multipeermap_size (friends_peermap))
886 GNUNET_SCHEDULER_cancel (random_walk_task);
887 random_walk_task = NULL;
893 * Function called with a random friend to be returned.
895 * @param cls a `struct FriendInfo **` with where to store the result
896 * @param peer the peer identity of the friend (ignored)
897 * @param value the `struct FriendInfo *` that was selected at random
898 * @return #GNUNET_OK (all good)
901 pick_random_helper (void *cls,
902 const struct GNUNET_PeerIdentity *peer,
905 struct FriendInfo **fi = cls;
906 struct FriendInfo *v = value;
914 * Pick random friend from friends for random walk.
916 * @return NULL if we have no friends
918 static struct FriendInfo *
919 pick_random_friend ()
921 struct FriendInfo *ret;
925 GNUNET_CONTAINER_multipeermap_get_random (friends_peermap,
934 * One of our trails might have timed out, check and
935 * possibly initiate cleanup.
941 trail_timeout_callback (void *cls,
942 const struct GNUNET_SCHEDULER_TaskContext *tc)
945 struct GNUNET_TIME_Relative left;
947 trail_timeout_task = NULL;
948 while (NULL != (trail = GNUNET_CONTAINER_heap_peek (trail_heap)))
950 left = GNUNET_TIME_absolute_get_remaining (trail->expiration_time);
951 if (0 != left.rel_value_us)
958 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (left,
959 &trail_timeout_callback,
965 * Compute how big our finger arrays should be (at least).
967 * @return size of the finger array, never 0
970 get_desired_finger_array_size ()
972 /* FIXME: This is just a stub... */
978 * Initiate a random walk.
984 do_random_walk (void *cls,
985 const struct GNUNET_SCHEDULER_TaskContext *tc)
987 static unsigned int walk_layer;
988 struct FriendInfo *friend;
989 struct GNUNET_MQ_Envelope *env;
990 struct RandomWalkMessage *rwm;
991 struct FingerTable *ft;
992 struct Finger *finger;
996 random_walk_task = NULL;
997 friend = pick_random_friend ();
999 trail = GNUNET_new (struct Trail);
1000 /* We create the random walk so, no predecessor */
1001 trail->succ = friend;
1002 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1005 GNUNET_CONTAINER_multihashmap_put (trail_map,
1008 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1011 GNUNET_free (trail);
1014 GNUNET_CONTAINER_MDLL_insert (succ,
1018 trail->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1019 trail->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1021 trail->expiration_time.abs_value_us);
1022 if (NULL == trail_timeout_task)
1023 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1024 &trail_timeout_callback,
1026 env = GNUNET_MQ_msg (rwm,
1027 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1028 rwm->hops_taken = htonl (0);
1029 rwm->trail_id = trail->succ_id;
1030 GNUNET_MQ_send (friend->mq,
1032 /* clean up 'old' entry (implicitly via trail cleanup) */
1033 ft = &fingers[walk_layer];
1035 if ( (NULL != ft->fingers) &&
1036 (NULL != (finger = ft->fingers[ft->walk_offset])) )
1037 delete_trail (finger->trail,
1040 if (ft->finger_array_size < (nsize = get_desired_finger_array_size()) )
1041 GNUNET_array_grow (ft->fingers,
1042 ft->finger_array_size,
1044 GNUNET_assert (NULL == ft->fingers[ft->walk_offset]);
1046 trail->finger_off = ft->walk_offset;
1047 finger = GNUNET_new (struct Finger);
1048 finger->trail = trail;
1050 ft->fingers[ft->walk_offset] = finger;
1051 ft->is_sorted = GNUNET_NO;
1052 ft->number_valid_fingers++;
1053 ft->walk_offset = (ft->walk_offset + 1) % ft->finger_array_size;
1055 walk_layer = (walk_layer + 1) % NUMBER_LAYERED_ID;
1056 random_walk_task = GNUNET_SCHEDULER_add_delayed (RANDOM_WALK_DELAY,
1063 * Method called whenever a peer connects.
1065 * @param cls closure
1066 * @param peer_identity peer identity this notification is about
1069 handle_core_connect (void *cls,
1070 const struct GNUNET_PeerIdentity *peer_identity)
1072 struct FriendInfo *friend;
1074 /* Check for connect to self message */
1075 if (0 == memcmp (&my_identity,
1077 sizeof (struct GNUNET_PeerIdentity)))
1080 /* If peer already exists in our friend_peermap, then exit. */
1082 GNUNET_CONTAINER_multipeermap_contains (friends_peermap,
1089 friend = GNUNET_new (struct FriendInfo);
1090 friend->id = *peer_identity;
1091 friend->mq = GNUNET_CORE_mq_create (core_api,
1093 GNUNET_assert (GNUNET_OK ==
1094 GNUNET_CONTAINER_multipeermap_put (friends_peermap,
1097 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1098 if (NULL == random_walk_task)
1100 /* random walk needs to be started -- we have a first connection */
1101 random_walk_task = GNUNET_SCHEDULER_add_now (&do_random_walk,
1108 * To be called on core init/fail.
1110 * @param cls service closure
1111 * @param identity the public identity of this peer
1114 core_init (void *cls,
1115 const struct GNUNET_PeerIdentity *identity)
1117 my_identity = *identity;
1122 * Handle a `struct RandomWalkMessage` from a
1123 * #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK message.
1125 * @param cls closure (NULL)
1126 * @param peer sender identity
1127 * @param message the setup message
1128 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1131 handle_dht_p2p_random_walk (void *cls,
1132 const struct GNUNET_PeerIdentity *peer,
1133 const struct GNUNET_MessageHeader *message)
1135 const struct RandomWalkMessage *m;
1137 struct FriendInfo *pred;
1140 m = (const struct RandomWalkMessage *) message;
1141 layer = ntohs (m->layer);
1142 if (layer > NUMBER_LAYERED_ID)
1144 GNUNET_break_op (0);
1145 return GNUNET_SYSERR;
1147 pred = GNUNET_CONTAINER_multipeermap_get (friends_peermap,
1149 t = GNUNET_new (struct Trail);
1150 t->pred_id = m->trail_id;
1153 GNUNET_CONTAINER_multihashmap_put (trail_map,
1156 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1158 GNUNET_break_op (0);
1160 return GNUNET_SYSERR;
1162 GNUNET_CONTAINER_MDLL_insert (pred,
1166 t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1167 t->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1169 t->expiration_time.abs_value_us);
1170 if (NULL == trail_timeout_task)
1171 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1172 &trail_timeout_callback,
1175 if (ntohl (m->hops_taken) > GDS_NSE_get ())
1177 /* We are the last hop, generate response */
1178 struct GNUNET_MQ_Envelope *env;
1179 struct RandomWalkResponseMessage *rwrm;
1181 env = GNUNET_MQ_msg (rwrm,
1182 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
1183 rwrm->reserved = htonl (0);
1184 rwrm->trail_id = m->trail_id;
1186 (void) GDS_DATACACHE_get_random_key (&rwrm->location);
1189 struct FingerTable *ft;
1191 ft = &fingers[layer-1];
1192 if (0 == ft->number_valid_fingers)
1194 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1203 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1204 ft->number_valid_fingers);
1205 for (i=0; (NULL == (f = ft->fingers[i])) || (off > 0); i++)
1206 if (NULL != f) off--;
1207 rwrm->location = f->destination;
1210 GNUNET_MQ_send (pred->mq,
1215 struct GNUNET_MQ_Envelope *env;
1216 struct RandomWalkMessage *rwm;
1217 struct FriendInfo *succ;
1219 /* extend the trail by another random hop */
1220 succ = pick_random_friend ();
1221 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1225 GNUNET_CONTAINER_multihashmap_put (trail_map,
1228 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1231 GNUNET_CONTAINER_MDLL_remove (pred,
1238 GNUNET_CONTAINER_MDLL_insert (succ,
1242 env = GNUNET_MQ_msg (rwm,
1243 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1244 rwm->hops_taken = htons (1 + ntohs (m->hops_taken));
1245 rwm->layer = m->layer;
1246 rwm->trail_id = t->succ_id;
1247 GNUNET_MQ_send (succ->mq,
1255 * Handle a `struct RandomWalkResponseMessage` from a GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
1258 * @param cls closure (NULL)
1259 * @param peer sender identity
1260 * @param message the setup response message
1261 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1264 handle_dht_p2p_random_walk_response (void *cls,
1265 const struct GNUNET_PeerIdentity *peer,
1266 const struct GNUNET_MessageHeader *message)
1268 const struct RandomWalkResponseMessage *rwrm;
1270 rwrm = (const struct RandomWalkResponseMessage *) message;
1271 // 1) lookup trail => find Finger entry => fill in 'destination' and mark valid, move to end of sorted array,
1272 //mark unsorted, update links from 'trails'
1275 * 1 check if we are the correct layer
1276 * 1.a if true : add the returned value (finger) in the db structure
1277 * 1.b if true : do nothing
1279 /* FIXME: add the value in db structure 1.a */
1286 * Handle a `struct TrailDestroyMessage`.
1288 * @param cls closure (NULL)
1289 * @param peer sender identity
1290 * @param message the finger destroy message
1291 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1294 handle_dht_p2p_trail_destroy (void *cls,
1295 const struct GNUNET_PeerIdentity *peer,
1296 const struct GNUNET_MessageHeader *message)
1298 const struct TrailDestroyMessage *tdm;
1299 struct Trail *trail;
1301 tdm = (const struct TrailDestroyMessage *) message;
1302 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1304 delete_trail (trail,
1305 ( (NULL != trail->succ) &&
1308 sizeof (struct GNUNET_PeerIdentity))) ),
1309 ( (NULL != trail->pred) &&
1312 sizeof (struct GNUNET_PeerIdentity))) ));
1318 * Handle a `struct FindSuccessorMessage` from a #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND
1321 * @param cls closure (NULL)
1322 * @param trail_id path to the originator
1323 * @param message the finger setup message
1324 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1327 handle_dht_p2p_successor_find (void *cls,
1328 const struct GNUNET_HashCode *trail_id,
1329 const struct GNUNET_MessageHeader *message)
1331 const struct FindSuccessorMessage *fsm;
1333 fsm = (const struct FindSuccessorMessage *) message;
1334 // locate trail (for sending reply), if not exists, fail nicely.
1335 // otherwise, go to datacache and return 'top k' elements closest to 'key'
1336 // as "PUT" messages via the trail (need to extend DB API!)
1338 GDS_DATACACHE_get_successors (trail_id,
1346 * Handle a `struct PeerGetMessage`.
1348 * @param cls closure (NULL)
1349 * @param trail_id path to the originator
1350 * @param message the peer get message
1351 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1354 handle_dht_p2p_peer_get (void *cls,
1355 const struct GNUNET_HashCode *trail_id,
1356 const struct GNUNET_MessageHeader *message)
1358 const struct PeerGetMessage *pgm;
1360 // FIXME: note: never called like this, message embedded with trail route!
1361 pgm = (const struct PeerGetMessage *) message;
1362 // -> lookup in datacache (figure out way to remember trail!)
1365 * 1 extract the result
1367 * 3 send it using the good trail
1369 * What do i do when i don't have the key/value?
1377 * Handle a `struct PeerGetResultMessage`.
1379 * @param cls closure (NULL)
1380 * @param trail_id path to the originator
1381 * @param message the peer get result message
1382 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1385 handle_dht_p2p_peer_get_result (void *cls,
1386 const struct GNUNET_HashCode *trail_id,
1387 const struct GNUNET_MessageHeader *message)
1389 const struct PeerGetResultMessage *pgrm;
1391 pgrm = (const struct PeerGetResultMessage *) message;
1392 // pretty much: parse, & pass to client (there is some call for that...)
1395 GDS_CLIENTS_process_get (options,
1400 (void) GDS_DATACACHE_handle_get (trail_id,
1413 * Handle a `struct PeerPutMessage`.
1415 * @param cls closure (NULL)
1416 * @param trail_id path to the originator
1417 * @param message the peer put message
1418 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1421 handle_dht_p2p_peer_put (void *cls,
1422 const struct GNUNET_HashCode *trail_id,
1423 const struct GNUNET_MessageHeader *message)
1425 const struct PeerGetResultMessage *pgrm;
1427 pgrm = (const struct PeerGetResultMessage *) message;
1428 // parse & store in datacache, this is in response to us asking for successors.
1431 * 1 check the size of the message
1432 * 2 use the API to add the value in the "database". Check on the xdht file, how to do it.
1433 * 3 Did i a have to return a notification or did i have to return GNUNET_[OK|SYSERR]?
1436 GDS_DATACACHE_handle_put (expiration_time,
1442 GDS_CLIENTS_process_put (options,
1458 * Handler for a message we received along some trail.
1460 * @param cls closure
1461 * @param trail_id trail identifier
1462 * @param message the message we got
1463 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1466 (*TrailHandlerCallback)(void *cls,
1467 const struct GNUNET_HashCode *trail_id,
1468 const struct GNUNET_MessageHeader *message);
1472 * Definition of a handler for a message received along some trail.
1477 * NULL for end-of-list.
1479 TrailHandlerCallback callback;
1482 * Closure for @e callback.
1487 * Message type this handler addresses.
1489 uint16_t message_type;
1492 * Use 0 for variable-size.
1494 uint16_t message_size;
1499 * Handle a `struct TrailRouteMessage`.
1501 * @param cls closure (NULL)
1502 * @param peer sender identity
1503 * @param message the finger destroy message
1504 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1507 handle_dht_p2p_trail_route (void *cls,
1508 const struct GNUNET_PeerIdentity *peer,
1509 const struct GNUNET_MessageHeader *message)
1511 static const struct TrailHandler handlers[] = {
1512 { &handle_dht_p2p_successor_find, NULL,
1513 GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND,
1514 sizeof (struct FindSuccessorMessage) },
1515 { &handle_dht_p2p_peer_get, NULL,
1516 GNUNET_MESSAGE_TYPE_WDHT_GET,
1517 sizeof (struct FindSuccessorMessage) },
1518 { &handle_dht_p2p_peer_get_result, NULL,
1519 GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT,
1521 { &handle_dht_p2p_peer_put, NULL,
1522 GNUNET_MESSAGE_TYPE_WDHT_PUT,
1524 { NULL, NULL, 0, 0 }
1527 const struct TrailRouteMessage *trm;
1528 const struct GNUNET_PeerIdentity *path;
1529 uint16_t path_length;
1530 const struct GNUNET_MessageHeader *payload;
1531 const struct TrailHandler *th;
1532 struct Trail *trail;
1535 /* Parse and check message is well-formed */
1536 msize = ntohs (message->size);
1537 if (msize < sizeof (struct TrailRouteMessage))
1539 GNUNET_break_op (0);
1542 trm = (const struct TrailRouteMessage *) message;
1543 path_length = ntohs (trm->path_length);
1544 if (msize < sizeof (struct TrailRouteMessage) +
1545 path_length * sizeof (struct GNUNET_PeerIdentity) +
1546 sizeof (struct GNUNET_MessageHeader) )
1548 GNUNET_break_op (0);
1551 path = (const struct GNUNET_PeerIdentity *) &trm[1];
1552 payload = (const struct GNUNET_MessageHeader *) &path[path_length];
1553 if (msize != (ntohs (payload->size) +
1554 sizeof (struct TrailRouteMessage) +
1555 path_length * sizeof (struct GNUNET_PeerIdentity)))
1557 GNUNET_break_op (0);
1561 /* Is this message for us? */
1562 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1564 if ( (NULL != trail->pred) &&
1567 sizeof (struct GNUNET_PeerIdentity))) )
1569 /* forward to 'successor' */
1570 if (NULL != trail->succ)
1572 forward_message_on_trail (trail->succ,
1574 ntohs (trm->record_path),
1584 /* forward to 'predecessor' */
1585 GNUNET_break_op ( (NULL != trail->succ) &&
1588 sizeof (struct GNUNET_PeerIdentity))) );
1589 if (NULL != trail->pred)
1591 forward_message_on_trail (trail->pred,
1593 ntohs (trm->record_path),
1602 /* Message is for us, dispatch to handler */
1604 for (i=0; NULL != handlers[i].callback; i++)
1607 if (ntohs (payload->type) == th->message_type)
1609 if ( (0 == th->message_size) ||
1610 (ntohs (payload->size) == th->message_size) )
1611 th->callback (th->cls,
1615 GNUNET_break_op (0);
1619 GNUNET_break_op (NULL != th);
1625 * Initialize neighbours subsystem.
1626 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1629 GDS_NEIGHBOURS_init (void)
1631 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1632 { &handle_dht_p2p_random_walk,
1633 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK,
1634 sizeof (struct RandomWalkMessage) },
1635 { &handle_dht_p2p_random_walk_response,
1636 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE,
1637 sizeof (struct RandomWalkResponseMessage) },
1638 { &handle_dht_p2p_trail_destroy,
1639 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY,
1640 sizeof (struct TrailDestroyMessage) },
1641 { &handle_dht_p2p_trail_route,
1642 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE,
1648 GNUNET_CORE_connect (GDS_cfg, NULL,
1650 &handle_core_connect,
1651 &handle_core_disconnect,
1656 if (NULL == core_api)
1657 return GNUNET_SYSERR;
1658 friends_peermap = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
1659 trail_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
1660 trail_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1666 * Shutdown neighbours subsystem.
1669 GDS_NEIGHBOURS_done (void)
1671 if (NULL == core_api)
1673 GNUNET_CORE_disconnect (core_api);
1675 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap));
1676 GNUNET_CONTAINER_multipeermap_destroy (friends_peermap);
1677 friends_peermap = NULL;
1678 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (trail_map));
1679 GNUNET_CONTAINER_multihashmap_destroy (trail_map);
1681 GNUNET_CONTAINER_heap_destroy (trail_heap);
1683 if (NULL != trail_timeout_task)
1685 GNUNET_SCHEDULER_cancel (trail_timeout_task);
1686 trail_timeout_task = NULL;
1694 * @return my identity
1696 struct GNUNET_PeerIdentity
1697 GDS_NEIGHBOURS_get_my_id (void)
1702 /* end of gnunet-service-wdht_neighbours.c */