2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
17 * @file dv/gnunet-service-dv.c
18 * @brief the distance vector service, primarily handles gossip of nearby
19 * peers and sending/receiving DV messages from core and decapsulating
22 * @author Christian Grothoff
23 * @author Nathan Evans
26 #include "gnunet_util_lib.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_core_service.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_set_service.h"
33 #include "gnunet_ats_service.h"
39 * How often do we establish the consensu?
41 #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
44 * Maximum number of messages we queue per peer.
46 #define MAX_QUEUE_SIZE 16
49 * Maximum number of messages we queue towards the clients/plugin.
51 #define MAX_QUEUE_SIZE_PLUGIN 1024
54 * The default fisheye depth, from how many hops away will
57 #define DEFAULT_FISHEYE_DEPTH 3
60 * How many hops is a direct neighbor away?
62 #define DIRECT_NEIGHBOR_COST 1
65 GNUNET_NETWORK_STRUCT_BEGIN
68 * Information about a peer DV can route to. These entries are what
69 * we use as the binary format to establish consensus to create our
70 * routing table and as the address format in the HELLOs.
76 * Identity of the peer we can reach.
78 struct GNUNET_PeerIdentity peer;
81 * How many hops (1-3) is this peer away? in network byte order
83 uint32_t distance GNUNET_PACKED;
89 * Message exchanged between DV services (via core), requesting a
90 * message to be routed.
95 * Type: #GNUNET_MESSAGE_TYPE_DV_ROUTE
97 struct GNUNET_MessageHeader header;
100 * Expected (remaining) distance. Must be always smaller than
101 * #DEFAULT_FISHEYE_DEPTH, should be zero at the target. Must
102 * be decremented by one at each hop. Peers must not forward
103 * these messages further once the counter has reached zero.
105 uint32_t distance GNUNET_PACKED;
108 * The (actual) target of the message (this peer, if distance is zero).
110 struct GNUNET_PeerIdentity target;
113 * The (actual) sender of the message.
115 struct GNUNET_PeerIdentity sender;
119 GNUNET_NETWORK_STRUCT_END
123 * Information about a direct neighbor (core-level, excluding
124 * DV-links, only DV-enabled peers).
126 struct DirectNeighbor
130 * Identity of the peer.
132 struct GNUNET_PeerIdentity peer;
135 * Session ID we use whenever we create a set union with
136 * this neighbor; constructed from the XOR of our peer
137 * IDs and then salted with "DV-SALT" to avoid conflicts
138 * with other applications.
140 struct GNUNET_HashCode real_session_id;
143 * Transmit handle to core service.
145 struct GNUNET_MQ_Handle *mq;
148 * Routing table of the neighbor, NULL if not yet established.
149 * Keys are peer identities, values are 'struct Target' entries.
150 * Note that the distances in the targets are from the point-of-view
151 * of the peer, not from us!
153 struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table;
156 * Updated routing table of the neighbor, under construction,
157 * NULL if we are not currently building it.
158 * Keys are peer identities, values are 'struct Target' entries.
159 * Note that the distances in the targets are from the point-of-view
160 * of the other peer, not from us!
162 struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table_consensus;
165 * Our current (exposed) routing table as a set.
167 struct GNUNET_SET_Handle *my_set;
170 * Handle for our current active set union operation.
172 struct GNUNET_SET_OperationHandle *set_op;
175 * Handle used if we are listening for this peer, waiting for the
176 * other peer to initiate construction of the set union. NULL if
177 * we ar the initiating peer.
179 struct GNUNET_SET_ListenHandle *listen_handle;
182 * ID of the task we use to (periodically) update our consensus
183 * with this peer. Used if we are the initiating peer.
185 struct GNUNET_SCHEDULER_Task *initiate_task;
188 * At what offset are we, with respect to inserting our own routes
189 * into the consensus?
191 unsigned int consensus_insertion_offset;
194 * At what distance are we, with respect to inserting our own routes
195 * into the consensus?
197 unsigned int consensus_insertion_distance;
200 * Elements in consensus
202 unsigned int consensus_elements;
205 * Direct one hop route
207 struct Route *direct_route;
210 * Flag set within 'check_target_removed' to trigger full global route refresh.
215 * Our distance to this peer, 0 for unknown.
220 * The network this peer is in
222 enum GNUNET_ATS_Network_Type network;
225 * Is this neighbor connected at the core level?
233 * A route includes information about the next hop,
234 * the target, and the ultimate distance to the
241 * Which peer do we need to forward the message to?
243 struct DirectNeighbor *next_hop;
246 * What would be the target, and how far is it away?
248 struct Target target;
251 * Offset of this target in the respective consensus set.
253 unsigned int set_offset;
259 * Set of targets we bring to a consensus; all targets in a set have a
260 * distance equal to the sets distance (which is implied by the array
267 * Array of targets in the set, may include NULL entries if a
268 * neighbor has disconnected; the targets are allocated with the
269 * respective container (all_routes), not here.
271 struct Route **targets;
274 * Size of the @e targets array.
276 unsigned int array_length;
282 * Peermap of all of our neighbors; processing these usually requires
283 * first checking to see if the peer is core-connected and if the
284 * distance is 1, in which case they are direct neighbors.
286 static struct GNUNET_CONTAINER_MultiPeerMap *direct_neighbors;
289 * Hashmap with all routes that we currently support; contains
290 * routing information for all peers from distance 2
291 * up to distance #DEFAULT_FISHEYE_DEPTH.
293 static struct GNUNET_CONTAINER_MultiPeerMap *all_routes;
296 * Array of consensus sets we expose to the outside world. Sets
297 * are structured by the distance to the target.
299 static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH];
302 * Handle to the core service api.
304 static struct GNUNET_CORE_Handle *core_api;
307 * The identity of our peer.
309 static struct GNUNET_PeerIdentity my_identity;
312 * The configuration for this service.
314 static const struct GNUNET_CONFIGURATION_Handle *cfg;
317 * The client, the DV plugin connected to us (or an event monitor).
318 * Hopefully this client will never change, although if the plugin
319 * dies and returns for some reason it may happen.
321 static struct GNUNET_NotificationContext *nc;
324 * Handle for the statistics service.
326 static struct GNUNET_STATISTICS_Handle *stats;
329 * Handle to ATS service.
331 static struct GNUNET_ATS_PerformanceHandle *ats;
334 * Task scheduled to refresh routes based on direct neighbours.
336 static struct GNUNET_SCHEDULER_Task *rr_task;
339 * #GNUNET_YES if we are shutting down.
341 static int in_shutdown;
344 * Start creating a new DV set union by initiating the connection.
346 * @param cls the 'struct DirectNeighbor' of the peer we're building
347 * a routing consensus with
350 initiate_set_union (void *cls);
354 * Start creating a new DV set union construction, our neighbour has
355 * asked for it (callback for listening peer).
357 * @param cls the 'struct DirectNeighbor' of the peer we're building
358 * a routing consensus with
359 * @param other_peer the other peer
360 * @param context_msg message with application specific information from
362 * @param request request from the other peer, use GNUNET_SET_accept
363 * to accept it, otherwise the request will be refused
364 * Note that we don't use a return value here, as it is also
365 * necessary to specify the set we want to do the operation with,
366 * whith sometimes can be derived from the context message.
367 * Also necessary to specify the timeout.
370 listen_set_union (void *cls,
371 const struct GNUNET_PeerIdentity *other_peer,
372 const struct GNUNET_MessageHeader *context_msg,
373 struct GNUNET_SET_Request *request);
377 * Forward a message from another peer to the plugin.
379 * @param message the message to send to the plugin
380 * @param origin the original sender of the message
381 * @param distance distance to the original sender of the message
384 send_data_to_plugin (const struct GNUNET_MessageHeader *message,
385 const struct GNUNET_PeerIdentity *origin,
388 struct GNUNET_DV_ReceivedMessage *received_msg;
391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392 "Delivering message from peer `%s' at distance %u\n",
394 (unsigned int) distance);
395 size = sizeof (struct GNUNET_DV_ReceivedMessage) +
396 ntohs (message->size);
397 if (size >= GNUNET_MAX_MESSAGE_SIZE)
399 GNUNET_break (0); /* too big */
402 received_msg = GNUNET_malloc (size);
403 received_msg->header.size = htons (size);
404 received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
405 received_msg->distance = htonl (distance);
406 received_msg->sender = *origin;
407 GNUNET_memcpy (&received_msg[1], message, ntohs (message->size));
408 GNUNET_notification_context_broadcast (nc,
409 &received_msg->header,
411 GNUNET_free (received_msg);
416 * Forward a control message to the plugin.
418 * @param message the message to send to the plugin
421 send_control_to_plugin (const struct GNUNET_MessageHeader *message)
423 GNUNET_notification_context_broadcast (nc,
430 * Send a DISTANCE_CHANGED message to the plugin.
432 * @param peer peer with a changed distance
433 * @param distance new distance to the peer
434 * @param network network used by the neighbor
437 send_distance_change_to_plugin (const struct GNUNET_PeerIdentity *peer,
439 enum GNUNET_ATS_Network_Type network)
441 struct GNUNET_DV_DistanceUpdateMessage du_msg;
443 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network);
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Delivering DISTANCE_CHANGED for message about peer `%s'\n",
447 du_msg.header.size = htons (sizeof (du_msg));
448 du_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED);
449 du_msg.distance = htonl (distance);
451 du_msg.network = htonl ((uint32_t) network);
452 send_control_to_plugin (&du_msg.header);
457 * Give a CONNECT message to the plugin.
459 * @param target peer that connected
460 * @param distance distance to the target
461 * @param network the network the next hop is located in
464 send_connect_to_plugin (const struct GNUNET_PeerIdentity *target,
466 enum GNUNET_ATS_Network_Type network)
468 struct GNUNET_DV_ConnectMessage cm;
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "Delivering CONNECT about peer %s with distance %u\n",
472 GNUNET_i2s (target), distance);
473 cm.header.size = htons (sizeof (cm));
474 cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
475 cm.distance = htonl (distance);
476 cm.network = htonl ((uint32_t) network);
478 send_control_to_plugin (&cm.header);
483 * Give a DISCONNECT message to the plugin.
485 * @param target peer that disconnected
488 send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
490 struct GNUNET_DV_DisconnectMessage dm;
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "Delivering DISCONNECT about peer `%s'\n",
494 GNUNET_i2s (target));
495 dm.header.size = htons (sizeof (dm));
496 dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
497 dm.reserved = htonl (0);
499 send_control_to_plugin (&dm.header);
504 * Forward the given payload to the given target.
506 * @param target where to send the message
507 * @param distance distance to the @a sender
508 * @param sender original sender of the message
509 * @param actual_target ultimate recipient for the message
510 * @param payload payload of the message
513 forward_payload (struct DirectNeighbor *target,
515 const struct GNUNET_PeerIdentity *sender,
516 const struct GNUNET_PeerIdentity *actual_target,
517 const struct GNUNET_MessageHeader *payload)
519 struct GNUNET_MQ_Envelope *env;
520 struct RouteMessage *rm;
522 if ( (GNUNET_MQ_get_length (target->mq) >= MAX_QUEUE_SIZE) &&
523 (0 != memcmp (sender,
525 sizeof (struct GNUNET_PeerIdentity))) )
527 /* not _our_ client and queue is full, drop */
528 GNUNET_STATISTICS_update (stats,
529 "# messages dropped",
534 if (sizeof (struct RouteMessage) + ntohs (payload->size)
535 >= GNUNET_MAX_MESSAGE_SIZE)
540 env = GNUNET_MQ_msg_nested_mh (rm,
541 GNUNET_MESSAGE_TYPE_DV_ROUTE,
543 rm->distance = htonl (distance);
544 rm->target = *actual_target;
545 rm->sender = *sender;
546 GNUNET_MQ_send (target->mq,
552 * Find a free slot for storing a 'route' in the 'consensi'
553 * set at the given distance.
555 * @param distance distance to use for the set slot
558 get_consensus_slot (uint32_t distance)
560 struct ConsensusSet *cs;
563 GNUNET_assert (distance < DEFAULT_FISHEYE_DEPTH);
564 cs = &consensi[distance];
566 while ( (i < cs->array_length) &&
567 (NULL != cs->targets[i]) ) i++;
568 if (i == cs->array_length)
570 GNUNET_array_grow (cs->targets,
572 cs->array_length * 2 + 2);
579 * Allocate a slot in the consensus set for a route.
581 * @param route route to initialize
582 * @param distance which consensus set to use
585 allocate_route (struct Route *route,
590 if (distance >= DEFAULT_FISHEYE_DEPTH)
592 route->target.distance = htonl (distance);
593 route->set_offset = UINT_MAX; /* invalid slot */
596 i = get_consensus_slot (distance);
597 route->set_offset = i;
598 consensi[distance].targets[i] = route;
599 route->target.distance = htonl (distance);
604 * Release a slot in the consensus set for a route.
606 * @param route route to release the slot from
609 release_route (struct Route *route)
611 if (UINT_MAX == route->set_offset)
613 GNUNET_assert (ntohl (route->target.distance) < DEFAULT_FISHEYE_DEPTH);
614 consensi[ntohl (route->target.distance)].targets[route->set_offset] = NULL;
615 route->set_offset = UINT_MAX; /* indicate invalid slot */
620 * Move a route from one consensus set to another.
622 * @param route route to move
623 * @param new_distance new distance for the route (destination set)
626 move_route (struct Route *route,
627 uint32_t new_distance)
629 release_route (route);
630 allocate_route (route, new_distance);
635 * Initialize this neighbors 'my_set' and when done give
636 * it to the pending set operation for execution.
638 * Add a single element to the set per call:
640 * If we reached the last element of a consensus element: increase distance
643 * @param cls the neighbor for which we are building the set
646 build_set (void *cls)
648 struct DirectNeighbor *neighbor = cls;
649 struct GNUNET_SET_Element element;
650 struct Target *target;
654 /* skip over NULL entries */
655 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
656 (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) &&
657 (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
658 neighbor->consensus_insertion_offset++;
659 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
660 (consensi[neighbor->consensus_insertion_distance].array_length == neighbor->consensus_insertion_offset) )
662 /* If we reached the last element of a consensus array element: increase distance and start with next array */
663 neighbor->consensus_insertion_offset = 0;
664 neighbor->consensus_insertion_distance++;
665 /* skip over NULL entries */
666 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
667 (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) &&
668 (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
669 neighbor->consensus_insertion_offset++;
671 if (DEFAULT_FISHEYE_DEPTH == neighbor->consensus_insertion_distance)
673 /* we have added all elements to the set, run the operation */
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Finished building my SET for peer `%s' with %u elements, committing\n",
676 GNUNET_i2s (&neighbor->peer),
677 neighbor->consensus_elements);
678 GNUNET_SET_commit (neighbor->set_op,
680 GNUNET_SET_destroy (neighbor->my_set);
681 neighbor->my_set = NULL;
685 route = consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset];
686 GNUNET_assert (NULL != route);
687 target = &route->target;
688 GNUNET_assert (ntohl (target->distance) < DEFAULT_FISHEYE_DEPTH);
689 element.size = sizeof (struct Target);
690 element.element_type = htons (0);
691 element.data = target;
693 /* Find next non-NULL entry */
694 neighbor->consensus_insertion_offset++;
695 if ( (0 != memcmp (&target->peer,
697 sizeof (my_identity))) &&
698 (0 != memcmp (&target->peer,
700 sizeof (struct GNUNET_PeerIdentity))) )
702 /* Add target if it is not the neighbor or this peer */
703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704 "Adding peer `%s' with distance %u to SET\n",
705 GNUNET_i2s (&target->peer),
706 ntohl (target->distance) + 1);
707 GNUNET_SET_add_element (neighbor->my_set,
709 &build_set, neighbor);
710 neighbor->consensus_elements++;
713 build_set (neighbor);
718 * A peer is now connected to us at distance 1. Initiate DV exchange.
720 * @param neighbor entry for the neighbor at distance 1
723 handle_direct_connect (struct DirectNeighbor *neighbor)
726 struct GNUNET_HashCode h1;
727 struct GNUNET_HashCode h2;
728 struct GNUNET_HashCode session_id;
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
731 "Direct connection to %s established, routing table exchange begins.\n",
732 GNUNET_i2s (&neighbor->peer));
733 GNUNET_STATISTICS_update (stats,
734 "# peers connected (1-hop)",
736 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
740 GNUNET_assert (GNUNET_YES ==
741 GNUNET_CONTAINER_multipeermap_remove (all_routes,
744 send_disconnect_to_plugin (&neighbor->peer);
745 release_route (route);
749 neighbor->direct_route = GNUNET_new (struct Route);
750 neighbor->direct_route->next_hop = neighbor;
751 neighbor->direct_route->target.peer = neighbor->peer;
752 allocate_route (neighbor->direct_route, DIRECT_NEIGHBOR_COST);
754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755 "Adding direct route to %s\n",
756 GNUNET_i2s (&neighbor->direct_route->target.peer));
759 /* construct session ID seed as XOR of both peer's identities */
760 GNUNET_CRYPTO_hash (&my_identity,
761 sizeof (my_identity),
763 GNUNET_CRYPTO_hash (&neighbor->peer,
764 sizeof (struct GNUNET_PeerIdentity),
766 GNUNET_CRYPTO_hash_xor (&h1,
769 /* make sure session ID is unique across applications by salting it with 'DV' */
770 GNUNET_CRYPTO_hkdf (&neighbor->real_session_id, sizeof (struct GNUNET_HashCode),
771 GCRY_MD_SHA512, GCRY_MD_SHA256,
773 &session_id, sizeof (session_id),
775 if (0 < memcmp (&neighbor->peer,
777 sizeof (struct GNUNET_PeerIdentity)))
779 if (NULL != neighbor->listen_handle)
784 neighbor->initiate_task = GNUNET_SCHEDULER_add_now (&initiate_set_union,
789 if (NULL != neighbor->listen_handle)
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "Starting SET listen operation with peer `%s'\n",
797 GNUNET_i2s (&neighbor->peer));
798 neighbor->listen_handle = GNUNET_SET_listen (cfg,
799 GNUNET_SET_OPERATION_UNION,
800 &neighbor->real_session_id,
809 * Method called whenever a peer connects.
812 * @param peer peer identity this notification is about
813 * @param mq message queue for sending data to @a peer
814 * @return our `struct DirectNeighbour` for this peer
817 handle_core_connect (void *cls,
818 const struct GNUNET_PeerIdentity *peer,
819 struct GNUNET_MQ_Handle *mq)
821 struct DirectNeighbor *neighbor;
823 /* Check for connect to self message */
824 if (0 == memcmp (&my_identity,
826 sizeof (struct GNUNET_PeerIdentity)))
828 /* check if entry exists */
829 neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
831 if (NULL != neighbor)
833 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != neighbor->network);
834 GNUNET_break (GNUNET_YES != neighbor->connected);
835 neighbor->connected = GNUNET_YES;
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837 "Core connected to %s (distance %u)\n",
839 (unsigned int) neighbor->distance);
840 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
842 handle_direct_connect (neighbor);
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846 "Core connected to %s (distance unknown)\n",
848 neighbor = GNUNET_new (struct DirectNeighbor);
849 neighbor->peer = *peer;
850 GNUNET_assert (GNUNET_YES ==
851 GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
854 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
855 neighbor->connected = GNUNET_YES;
856 neighbor->distance = 0; /* unknown */
857 neighbor->network = GNUNET_ATS_NET_UNSPECIFIED;
863 * Called for each 'target' in a neighbor table to free the associated memory.
866 * @param key key of the value
867 * @param value value to free
868 * @return #GNUNET_OK to continue to iterate
871 free_targets (void *cls,
872 const struct GNUNET_PeerIdentity *key,
881 * Add a new route to the given @a target via the given @a neighbor.
883 * @param target the target of the route
884 * @param neighbor the next hop for communicating with the @a target
887 add_new_route (struct Target *target,
888 struct DirectNeighbor *neighbor)
892 route = GNUNET_new (struct Route);
893 route->next_hop = neighbor;
894 route->target.peer = target->peer;
895 allocate_route (route, ntohl (target->distance) + 1);
896 GNUNET_assert (GNUNET_YES ==
897 GNUNET_CONTAINER_multipeermap_put (all_routes,
900 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
901 send_connect_to_plugin (&route->target.peer,
902 ntohl (route->target.distance),
908 * Multipeerhmap iterator for checking if a given route is
909 * (now) useful to this peer.
911 * @param cls the direct neighbor for the given route
912 * @param key key value stored under
913 * @param value a 'struct Target' that may or may not be useful; not that
914 * the distance in 'target' does not include the first hop yet
915 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
918 check_possible_route (void *cls,
919 const struct GNUNET_PeerIdentity *key,
922 struct DirectNeighbor *neighbor = cls;
923 struct Target *target = value;
927 GNUNET_CONTAINER_multipeermap_contains (direct_neighbors,
929 return GNUNET_YES; /* direct route, do not care about alternatives */
930 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
934 /* we have an existing route, check how it compares with going via 'target' */
935 if (ntohl (route->target.distance) > ntohl (target->distance) + 1)
937 /* via 'target' is cheaper than the existing route; switch to alternative route! */
938 move_route (route, ntohl (target->distance) + 1);
939 route->next_hop = neighbor;
940 send_distance_change_to_plugin (&target->peer,
941 ntohl (target->distance) + 1,
944 return GNUNET_YES; /* got a route to this target already */
946 if (ntohl (target->distance) >= DEFAULT_FISHEYE_DEPTH)
947 return GNUNET_YES; /* distance is too large to be interesting */
948 add_new_route (target, neighbor);
954 * Multipeermap iterator for finding routes that were previously
955 * "hidden" due to a better route (called after a disconnect event).
958 * @param key peer identity of the given direct neighbor
959 * @param value a `struct DirectNeighbor` to check for additional routes
960 * @return #GNUNET_YES to continue iteration
963 refresh_routes (void *cls,
964 const struct GNUNET_PeerIdentity *key,
967 struct DirectNeighbor *neighbor = value;
969 if ( (GNUNET_YES != neighbor->connected) ||
970 (DIRECT_NEIGHBOR_COST != neighbor->distance) )
972 if (NULL != neighbor->neighbor_table)
973 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
974 &check_possible_route,
981 * Task to run #refresh_routes() on all direct neighbours.
986 refresh_routes_task (void *cls)
989 GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
996 * Asynchronously run #refresh_routes() at the next opportunity
997 * on all direct neighbours.
1000 schedule_refresh_routes ()
1002 if (NULL == rr_task)
1003 rr_task = GNUNET_SCHEDULER_add_now (&refresh_routes_task,
1009 * Multipeermap iterator for freeing routes that go via a particular
1010 * neighbor that disconnected and is thus no longer available.
1012 * @param cls the direct neighbor that is now unavailable
1013 * @param key key value stored under
1014 * @param value a `struct Route` that may or may not go via neighbor
1016 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1019 cull_routes (void *cls,
1020 const struct GNUNET_PeerIdentity *key,
1023 struct DirectNeighbor *neighbor = cls;
1024 struct Route *route = value;
1026 if (route->next_hop != neighbor)
1027 return GNUNET_YES; /* not affected */
1028 GNUNET_assert (GNUNET_YES ==
1029 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1030 release_route (route);
1031 send_disconnect_to_plugin (&route->target.peer);
1032 GNUNET_free (route);
1038 * Handle the case that a direct connection to a peer is
1039 * disrupted. Remove all routes via that peer and
1040 * stop the consensus with it.
1042 * @param neighbor peer that was disconnected (or at least is no
1043 * longer at distance 1)
1046 handle_direct_disconnect (struct DirectNeighbor *neighbor)
1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1049 "Culling routes via %s due to direct disconnect\n",
1050 GNUNET_i2s (&neighbor->peer));
1051 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1054 if (NULL != neighbor->direct_route)
1056 release_route (neighbor->direct_route);
1057 GNUNET_free (neighbor->direct_route);
1058 neighbor->direct_route = NULL;
1060 if (NULL != neighbor->neighbor_table_consensus)
1062 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1065 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1066 neighbor->neighbor_table_consensus = NULL;
1068 if (NULL != neighbor->neighbor_table)
1070 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1073 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1074 neighbor->neighbor_table = NULL;
1076 if (NULL != neighbor->set_op)
1078 GNUNET_SET_operation_cancel (neighbor->set_op);
1079 neighbor->set_op = NULL;
1081 if (NULL != neighbor->my_set)
1083 GNUNET_SET_destroy (neighbor->my_set);
1084 neighbor->my_set = NULL;
1086 if (NULL != neighbor->listen_handle)
1088 GNUNET_SET_listen_cancel (neighbor->listen_handle);
1089 neighbor->listen_handle = NULL;
1091 if (NULL != neighbor->initiate_task)
1093 GNUNET_SCHEDULER_cancel (neighbor->initiate_task);
1094 neighbor->initiate_task = NULL;
1100 * Function that is called with QoS information about an address; used
1101 * to update our current distance to another peer.
1103 * @param cls closure
1104 * @param address the address
1105 * @param active #GNUNET_YES if this address is actively used
1106 * to maintain a connection to a peer;
1107 * #GNUNET_NO if the address is not actively used;
1108 * #GNUNET_SYSERR if this address is no longer available for ATS
1109 * @param bandwidth_out assigned outbound bandwidth for the connection
1110 * @param bandwidth_in assigned inbound bandwidth for the connection
1111 * @param prop performance data for the address (as far as known)
1114 handle_ats_update (void *cls,
1115 const struct GNUNET_HELLO_Address *address,
1117 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1118 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1119 const struct GNUNET_ATS_Properties *prop)
1121 struct DirectNeighbor *neighbor;
1123 enum GNUNET_ATS_Network_Type network;
1125 if (NULL == address)
1127 /* ATS service temporarily disconnected */
1131 if (GNUNET_YES != active)
1133 // FIXME: handle disconnect/inactive case too!
1136 distance = prop->distance;
1137 network = prop->scope;
1138 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network);
1139 /* check if entry exists */
1140 neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1142 if (NULL != neighbor)
1144 neighbor->network = network;
1145 if (neighbor->distance == distance)
1146 return; /* nothing new to see here, move along */
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "ATS says distance to %s is now %u\n",
1149 GNUNET_i2s (&address->peer),
1150 (unsigned int) distance);
1151 if ( (DIRECT_NEIGHBOR_COST == neighbor->distance) &&
1152 (DIRECT_NEIGHBOR_COST == distance) )
1153 return; /* no change */
1154 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1156 neighbor->distance = distance;
1157 GNUNET_STATISTICS_update (stats,
1158 "# peers connected (1-hop)",
1160 handle_direct_disconnect (neighbor);
1161 schedule_refresh_routes ();
1164 neighbor->distance = distance;
1165 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
1167 if (GNUNET_YES != neighbor->connected)
1169 handle_direct_connect (neighbor);
1172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173 "ATS says distance to %s is now %u\n",
1174 GNUNET_i2s (&address->peer),
1175 (unsigned int) distance);
1176 neighbor = GNUNET_new (struct DirectNeighbor);
1177 neighbor->peer = address->peer;
1178 GNUNET_assert (GNUNET_YES ==
1179 GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
1182 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1183 neighbor->connected = GNUNET_NO; /* not yet */
1184 neighbor->distance = distance;
1185 neighbor->network = network;
1190 * Check if a target was removed from the set of the other peer; if so,
1191 * if we also used it for our route, we need to remove it from our
1192 * 'all_routes' set (and later check if an alternative path now exists).
1194 * @param cls the `struct DirectNeighbor`
1195 * @param key peer identity for the target
1196 * @param value a `struct Target` previously reachable via the given neighbor
1199 check_target_removed (void *cls,
1200 const struct GNUNET_PeerIdentity *key,
1203 struct DirectNeighbor *neighbor = cls;
1204 struct Target *new_target;
1205 struct Route *current_route;
1207 new_target = GNUNET_CONTAINER_multipeermap_get (neighbor->neighbor_table_consensus,
1209 current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1211 if (NULL != new_target)
1213 /* target was in old set, is in new set */
1214 if ( (NULL != current_route) &&
1215 (current_route->next_hop == neighbor) &&
1216 (current_route->target.distance != new_target->distance) )
1218 /* need to recalculate routes due to distance change */
1219 neighbor->target_removed = GNUNET_YES;
1223 /* target was revoked, check if it was used */
1224 if ( (NULL == current_route) ||
1225 (current_route->next_hop != neighbor) )
1227 /* didn't matter, wasn't used */
1230 /* remove existing route */
1231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1232 "Lost route to %s\n",
1233 GNUNET_i2s (¤t_route->target.peer));
1234 GNUNET_assert (GNUNET_YES ==
1235 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, current_route));
1236 send_disconnect_to_plugin (¤t_route->target.peer);
1237 release_route (current_route);
1238 GNUNET_free (current_route);
1239 neighbor->target_removed = GNUNET_YES;
1245 * Check if a target was added to the set of the other peer; if it
1246 * was added or impoves the existing route, do the needed updates.
1248 * @param cls the `struct DirectNeighbor`
1249 * @param key peer identity for the target
1250 * @param value a `struct Target` now reachable via the given neighbor
1253 check_target_added (void *cls,
1254 const struct GNUNET_PeerIdentity *key,
1257 struct DirectNeighbor *neighbor = cls;
1258 struct Target *target = value;
1259 struct Route *current_route;
1261 /* target was revoked, check if it was used */
1262 current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1264 if (NULL != current_route)
1267 if (current_route->next_hop == neighbor)
1269 /* we had the same route before, no change in target */
1270 if (ntohl (target->distance) + 1 != ntohl (current_route->target.distance))
1272 /* but distance changed! */
1273 if (ntohl (target->distance) + 1 > DEFAULT_FISHEYE_DEPTH)
1275 /* distance increased beyond what is allowed, kill route */
1276 GNUNET_assert (GNUNET_YES ==
1277 GNUNET_CONTAINER_multipeermap_remove (all_routes,
1280 send_disconnect_to_plugin (key);
1281 release_route (current_route);
1282 GNUNET_free (current_route);
1286 /* distance decreased, update route */
1287 move_route (current_route,
1288 ntohl (target->distance) + 1);
1289 send_distance_change_to_plugin (&target->peer,
1290 ntohl (target->distance) + 1,
1296 if (ntohl (current_route->target.distance) <= ntohl (target->distance) + 1)
1298 /* alternative, shorter route exists, ignore */
1301 /* new route is better than the existing one, take over! */
1302 /* NOTE: minor security issue: malicious peers may advertise
1303 very short routes to take over longer paths; as we don't
1304 check that the shorter routes actually work, a malicious
1305 direct neighbor can use this to DoS our long routes */
1307 move_route (current_route, ntohl (target->distance) + 1);
1308 current_route->next_hop = neighbor;
1309 send_distance_change_to_plugin (&target->peer,
1310 ntohl (target->distance) + 1,
1315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1316 "Discovered new route to %s using %u hops\n",
1317 GNUNET_i2s (&target->peer),
1318 (unsigned int) (ntohl (target->distance) + 1));
1319 current_route = GNUNET_new (struct Route);
1320 current_route->next_hop = neighbor;
1321 current_route->target.peer = target->peer;
1322 allocate_route (current_route, ntohl (target->distance) + 1);
1323 GNUNET_assert (GNUNET_YES ==
1324 GNUNET_CONTAINER_multipeermap_put (all_routes,
1325 ¤t_route->target.peer,
1327 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1329 send_connect_to_plugin (¤t_route->target.peer,
1330 ntohl (current_route->target.distance),
1337 * Callback for set operation results. Called for each element
1338 * in the result set.
1339 * We have learned a new route from the other peer. Add it to the
1340 * route set we're building.
1342 * @param cls the `struct DirectNeighbor` we're building the consensus with
1343 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1344 * @param current_size current set size
1345 * @param status see `enum GNUNET_SET_Status`
1348 handle_set_union_result (void *cls,
1349 const struct GNUNET_SET_Element *element,
1350 uint64_t current_size,
1351 enum GNUNET_SET_Status status)
1353 struct DirectNeighbor *neighbor = cls;
1354 struct DirectNeighbor *dn;
1355 struct Target *target;
1356 const struct Target *ctarget;
1361 case GNUNET_SET_STATUS_OK:
1362 status_str = "GNUNET_SET_STATUS_OK";
1364 case GNUNET_SET_STATUS_FAILURE:
1365 status_str = "GNUNET_SET_STATUS_FAILURE";
1367 case GNUNET_SET_STATUS_HALF_DONE:
1368 status_str = "GNUNET_SET_STATUS_HALF_DONE";
1370 case GNUNET_SET_STATUS_DONE:
1371 status_str = "GNUNET_SET_STATUS_DONE";
1374 status_str = "UNDEFINED";
1378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379 "Got SET union result: %s\n",
1383 case GNUNET_SET_STATUS_OK:
1384 if (sizeof (struct Target) != element->size)
1386 GNUNET_break_op (0);
1389 ctarget = element->data;
1391 (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1392 &ctarget->peer))) &&
1393 (DIRECT_NEIGHBOR_COST == dn->distance) )
1395 /* this is a direct neighbor of ours, we do not care about routes
1399 target = GNUNET_new (struct Target);
1400 GNUNET_memcpy (target, element->data, sizeof (struct Target));
1401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1402 "Received information about peer `%s' with distance %u from SET\n",
1403 GNUNET_i2s (&target->peer),
1404 ntohl (target->distance) + 1);
1406 if (NULL == neighbor->neighbor_table_consensus)
1407 neighbor->neighbor_table_consensus
1408 = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1410 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table_consensus,
1413 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1415 GNUNET_break_op (0);
1416 GNUNET_free (target);
1419 case GNUNET_SET_STATUS_FAILURE:
1420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1421 "Failed to establish DV union, will try again later\n");
1422 neighbor->set_op = NULL;
1423 if (NULL != neighbor->neighbor_table_consensus)
1425 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1428 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1429 neighbor->neighbor_table_consensus = NULL;
1431 if (0 < memcmp (&neighbor->peer,
1433 sizeof (struct GNUNET_PeerIdentity)))
1434 neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1435 &initiate_set_union,
1438 case GNUNET_SET_STATUS_HALF_DONE:
1440 case GNUNET_SET_STATUS_DONE:
1441 /* we got all of our updates; integrate routing table! */
1442 neighbor->target_removed = GNUNET_NO;
1443 if (NULL == neighbor->neighbor_table_consensus)
1444 neighbor->neighbor_table_consensus = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1445 if (NULL != neighbor->neighbor_table)
1446 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1447 &check_target_removed,
1449 if (GNUNET_YES == neighbor->target_removed)
1451 /* check if we got an alternative for the removed routes */
1452 schedule_refresh_routes ();
1454 /* add targets that appeared (and check for improved routes) */
1455 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1456 &check_target_added,
1458 if (NULL != neighbor->neighbor_table)
1460 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1463 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1464 neighbor->neighbor_table = NULL;
1466 neighbor->neighbor_table = neighbor->neighbor_table_consensus;
1467 neighbor->neighbor_table_consensus = NULL;
1469 /* operation done, schedule next run! */
1470 neighbor->set_op = NULL;
1471 if (0 < memcmp (&neighbor->peer,
1473 sizeof (struct GNUNET_PeerIdentity)))
1474 neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1475 &initiate_set_union,
1486 * Start creating a new DV set union construction, our neighbour has
1487 * asked for it (callback for listening peer).
1489 * @param cls the 'struct DirectNeighbor' of the peer we're building
1490 * a routing consensus with
1491 * @param other_peer the other peer
1492 * @param context_msg message with application specific information from
1494 * @param request request from the other peer, use GNUNET_SET_accept
1495 * to accept it, otherwise the request will be refused
1496 * Note that we don't use a return value here, as it is also
1497 * necessary to specify the set we want to do the operation with,
1498 * whith sometimes can be derived from the context message.
1499 * Also necessary to specify the timeout.
1502 listen_set_union (void *cls,
1503 const struct GNUNET_PeerIdentity *other_peer,
1504 const struct GNUNET_MessageHeader *context_msg,
1505 struct GNUNET_SET_Request *request)
1507 struct DirectNeighbor *neighbor = cls;
1509 if (NULL == request)
1510 return; /* why??? */
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "Starting to create consensus with %s\n",
1513 GNUNET_i2s (&neighbor->peer));
1514 if (NULL != neighbor->set_op)
1516 GNUNET_SET_operation_cancel (neighbor->set_op);
1517 neighbor->set_op = NULL;
1519 if (NULL != neighbor->my_set)
1521 GNUNET_SET_destroy (neighbor->my_set);
1522 neighbor->my_set = NULL;
1524 neighbor->my_set = GNUNET_SET_create (cfg,
1525 GNUNET_SET_OPERATION_UNION);
1526 neighbor->set_op = GNUNET_SET_accept (request,
1527 GNUNET_SET_RESULT_ADDED,
1528 (struct GNUNET_SET_Option[]) {{ 0 }},
1529 &handle_set_union_result,
1531 neighbor->consensus_insertion_offset = 0;
1532 neighbor->consensus_insertion_distance = 0;
1533 neighbor->consensus_elements = 0;
1534 build_set (neighbor);
1539 * Start creating a new DV set union by initiating the connection.
1541 * @param cls the `struct DirectNeighbor *` of the peer we're building
1542 * a routing consensus with
1545 initiate_set_union (void *cls)
1547 struct DirectNeighbor *neighbor = cls;
1549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1550 "Initiating SET union with peer `%s'\n",
1551 GNUNET_i2s (&neighbor->peer));
1552 neighbor->initiate_task = NULL;
1553 neighbor->my_set = GNUNET_SET_create (cfg,
1554 GNUNET_SET_OPERATION_UNION);
1555 neighbor->set_op = GNUNET_SET_prepare (&neighbor->peer,
1556 &neighbor->real_session_id,
1558 GNUNET_SET_RESULT_ADDED,
1559 (struct GNUNET_SET_Option[]) {{ 0 }},
1560 &handle_set_union_result,
1562 neighbor->consensus_insertion_offset = 0;
1563 neighbor->consensus_insertion_distance = 0;
1564 neighbor->consensus_elements = 0;
1565 build_set (neighbor);
1570 * Check that @a rm is well-formed.
1572 * @param cls closure
1573 * @param rm the message
1574 * @return #GNUNET_OK if @a rm is well-formed.
1577 check_dv_route_message (void *cls,
1578 const struct RouteMessage *rm)
1580 const struct GNUNET_MessageHeader *payload;
1582 if (ntohs (rm->header.size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader))
1584 GNUNET_break_op (0);
1585 return GNUNET_SYSERR;
1587 payload = (const struct GNUNET_MessageHeader *) &rm[1];
1588 if (ntohs (rm->header.size) != sizeof (struct RouteMessage) + ntohs (payload->size))
1590 GNUNET_break_op (0);
1591 return GNUNET_SYSERR;
1598 * Core handler for DV data messages. Whatever this message
1599 * contains all we really have to do is rip it out of its
1600 * DV layering and give it to our pal the DV plugin to report
1603 * @param cls closure
1604 * @param rm the message
1607 handle_dv_route_message (void *cls,
1608 const struct RouteMessage *rm)
1610 struct DirectNeighbor *neighbor = cls;
1611 const struct GNUNET_MessageHeader *payload;
1612 struct Route *route;
1613 struct DirectNeighbor *nneighbor;
1614 struct DirectNeighbor *dn;
1615 struct Target *target;
1622 distance = ntohl (rm->distance);
1623 payload = (const struct GNUNET_MessageHeader *) &rm[1];
1624 strncpy (prev, GNUNET_i2s (&neighbor->peer), 4);
1625 strncpy (me, GNUNET_i2s (&my_identity), 4);
1626 strncpy (src, GNUNET_i2s (&rm->sender), 4);
1627 strncpy (dst, GNUNET_i2s (&rm->target), 4);
1628 prev[4] = me[4] = src[4] = dst[4] = '\0';
1629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1630 "Handling DV message with %u bytes payload of type %u from %s to %s routed by %s to me (%s @ hop %u)\n",
1631 (unsigned int) (ntohs (rm->header.size) - sizeof (struct RouteMessage)),
1632 ntohs (payload->type),
1637 (unsigned int) distance + 1);
1639 if (0 == memcmp (&rm->target,
1641 sizeof (struct GNUNET_PeerIdentity)))
1644 (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1646 (DIRECT_NEIGHBOR_COST == dn->distance))
1648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1649 "Discarding DV message, as %s is a direct neighbor\n",
1650 GNUNET_i2s (&rm->sender));
1651 GNUNET_STATISTICS_update (stats,
1652 "# messages discarded (direct neighbor)",
1656 /* message is for me, check reverse route! */
1657 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1659 if ( (NULL == route) &&
1660 (distance < DEFAULT_FISHEYE_DEPTH) )
1662 /* don't have reverse route yet, learn it! */
1663 target = GNUNET_new (struct Target);
1664 target->peer = rm->sender;
1665 target->distance = htonl (distance);
1666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1667 "Learning sender %s at distance %u from delivery!\n",
1668 GNUNET_i2s (&rm->sender),
1669 (unsigned int) distance + 1);
1670 if (NULL == neighbor->neighbor_table)
1671 neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1673 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1676 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1678 GNUNET_break_op (0);
1679 GNUNET_free (target);
1682 add_new_route (target, neighbor);
1684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685 "Delivering %u bytes from %s to myself!\n",
1686 ntohs (payload->size),
1687 GNUNET_i2s (&rm->sender));
1688 send_data_to_plugin (payload,
1693 if ( (NULL == GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1695 (NULL == GNUNET_CONTAINER_multipeermap_get (all_routes,
1698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1699 "Learning sender %s at distance %u from forwarding!\n",
1700 GNUNET_i2s (&rm->sender),
1702 target = GNUNET_new (struct Target);
1703 target->peer = rm->sender;
1704 target->distance = htonl (distance);
1705 if (NULL == neighbor->neighbor_table)
1706 neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1708 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1711 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1713 GNUNET_break_op (0);
1714 GNUNET_free (target);
1717 add_new_route (target, neighbor);
1720 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1724 nneighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1726 if (NULL == nneighbor)
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "No route to %s, not routing %u bytes!\n",
1730 GNUNET_i2s (&rm->target),
1731 ntohs (payload->size));
1732 GNUNET_STATISTICS_update (stats,
1733 "# messages discarded (no route)",
1740 nneighbor = route->next_hop;
1742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1743 "Forwarding message to %s\n",
1744 GNUNET_i2s (&nneighbor->peer));
1745 forward_payload (nneighbor,
1754 * Check that @a msg is well-formed
1756 * @param cls identification of the client
1757 * @param message the actual message
1758 * @return #GNUNET_OK if @a msg is well-formed
1761 check_dv_send_message (void *cls,
1762 const struct GNUNET_DV_SendMessage *msg)
1764 const struct GNUNET_MessageHeader *payload;
1766 if (ntohs (msg->header.size) < sizeof (struct GNUNET_DV_SendMessage) +
1767 sizeof (struct GNUNET_MessageHeader))
1770 return GNUNET_SYSERR;
1772 payload = (const struct GNUNET_MessageHeader *) &msg[1];
1773 if (ntohs (msg->header.size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size))
1776 return GNUNET_SYSERR;
1783 * Service server's handler for message send requests (which come
1784 * bubbling up to us through the DV plugin).
1786 * @param cls identification of the client
1787 * @param message the actual message
1790 handle_dv_send_message (void *cls,
1791 const struct GNUNET_DV_SendMessage *msg)
1793 struct GNUNET_SERVICE_Client *client = cls;
1794 struct Route *route;
1795 const struct GNUNET_MessageHeader *payload;
1797 payload = (const struct GNUNET_MessageHeader *) &msg[1];
1798 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1802 /* got disconnected */
1803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1804 "No route to %s, dropping local message of type %u\n",
1805 GNUNET_i2s (&msg->target),
1806 ntohs (payload->type));
1807 GNUNET_STATISTICS_update (stats,
1808 "# local messages discarded (no route)",
1810 GNUNET_SERVICE_client_continue (client);
1813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1814 "Forwarding %u bytes of type %u to %s\n",
1815 ntohs (payload->size),
1816 ntohs (payload->type),
1817 GNUNET_i2s (&msg->target));
1819 forward_payload (route->next_hop,
1820 0 /* first hop, distance is zero */,
1824 GNUNET_SERVICE_client_continue (client);
1829 * Cleanup all of the data structures associated with a given neighbor.
1831 * @param neighbor neighbor to clean up
1834 cleanup_neighbor (struct DirectNeighbor *neighbor)
1836 handle_direct_disconnect (neighbor);
1837 GNUNET_assert (GNUNET_YES ==
1838 GNUNET_CONTAINER_multipeermap_remove (direct_neighbors,
1841 GNUNET_free (neighbor);
1846 * Method called whenever a given peer disconnects.
1848 * @param cls closure
1849 * @param peer peer identity this notification is about
1850 * @param internal_cls the corresponding `struct DirectNeighbor`
1853 handle_core_disconnect (void *cls,
1854 const struct GNUNET_PeerIdentity *peer,
1857 struct DirectNeighbor *neighbor = internal_cls;
1859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860 "Received core peer disconnect message for peer `%s'!\n",
1862 /* Check for disconnect from self message */
1863 if (NULL == neighbor)
1865 GNUNET_break (GNUNET_YES == neighbor->connected);
1866 neighbor->connected = GNUNET_NO;
1867 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1869 GNUNET_STATISTICS_update (stats,
1870 "# peers connected (1-hop)",
1874 cleanup_neighbor (neighbor);
1875 if (GNUNET_YES == in_shutdown)
1877 schedule_refresh_routes ();
1882 * Multipeermap iterator for freeing routes. Should never be called.
1885 * @param key key value stored under
1886 * @param value the route to be freed
1887 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1890 free_route (void *cls,
1891 const struct GNUNET_PeerIdentity *key,
1894 struct Route *route = value;
1897 GNUNET_assert (GNUNET_YES ==
1898 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1899 release_route (route);
1900 send_disconnect_to_plugin (&route->target.peer);
1901 GNUNET_free (route);
1907 * Multipeermap iterator for freeing direct neighbors. Should never be called.
1910 * @param key key value stored under
1911 * @param value the direct neighbor to be freed
1912 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1915 free_direct_neighbors (void *cls,
1916 const struct GNUNET_PeerIdentity *key,
1919 struct DirectNeighbor *neighbor = value;
1921 cleanup_neighbor (neighbor);
1927 * Task run during shutdown.
1932 shutdown_task (void *cls)
1936 in_shutdown = GNUNET_YES;
1937 GNUNET_assert (NULL != core_api);
1938 GNUNET_CORE_disconnect (core_api);
1940 GNUNET_ATS_performance_done (ats);
1942 GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
1943 &free_direct_neighbors,
1945 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1948 GNUNET_CONTAINER_multipeermap_destroy (direct_neighbors);
1949 GNUNET_CONTAINER_multipeermap_destroy (all_routes);
1950 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1952 GNUNET_notification_context_destroy (nc);
1954 for (i=0;i<DEFAULT_FISHEYE_DEPTH;i++)
1956 GNUNET_array_grow (consensi[i].targets,
1957 consensi[i].array_length,
1960 if (NULL != rr_task)
1962 GNUNET_SCHEDULER_cancel (rr_task);
1969 * Notify newly connected client about an existing route.
1971 * @param cls the `struct GNUNET_SERVICE_Client *`
1972 * @param key peer identity
1973 * @param value the `struct Route *`
1974 * @return #GNUNET_OK (continue to iterate)
1977 notify_client_about_route (void *cls,
1978 const struct GNUNET_PeerIdentity *key,
1981 struct GNUNET_SERVICE_Client *client = cls;
1982 struct Route *route = value;
1983 struct GNUNET_MQ_Envelope *env;
1984 struct GNUNET_DV_ConnectMessage *cm;
1986 env = GNUNET_MQ_msg (cm,
1987 GNUNET_MESSAGE_TYPE_DV_CONNECT);
1988 cm->distance = htonl (route->target.distance);
1989 cm->peer = route->target.peer;
1990 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1997 * Handle START-message. This is the first message sent to us
1998 * by the client (can only be one!).
2000 * @param cls closure (always NULL)
2001 * @param client identification of the client
2002 * @param message the actual message
2005 handle_start (void *cls,
2006 const struct GNUNET_MessageHeader *message)
2008 struct GNUNET_SERVICE_Client *client = cls;
2010 GNUNET_notification_context_add (nc,
2011 GNUNET_SERVICE_client_get_mq (client));
2012 GNUNET_SERVICE_client_continue (client);
2013 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
2014 ¬ify_client_about_route,
2020 * Called on core init.
2023 * @param identity this peer's identity
2026 core_init (void *cls,
2027 const struct GNUNET_PeerIdentity *identity)
2029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2031 GNUNET_i2s (identity));
2032 my_identity = *identity;
2037 * Process dv requests.
2039 * @param cls closure
2040 * @param c configuration to use
2041 * @param service the initialized service
2045 const struct GNUNET_CONFIGURATION_Handle *c,
2046 struct GNUNET_SERVICE_Handle *service)
2048 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2049 GNUNET_MQ_hd_var_size (dv_route_message,
2050 GNUNET_MESSAGE_TYPE_DV_ROUTE,
2051 struct RouteMessage,
2053 GNUNET_MQ_handler_end ()
2055 in_shutdown = GNUNET_NO;
2057 direct_neighbors = GNUNET_CONTAINER_multipeermap_create (128,
2059 all_routes = GNUNET_CONTAINER_multipeermap_create (65536,
2061 core_api = GNUNET_CORE_connect (cfg,
2064 &handle_core_connect,
2065 &handle_core_disconnect,
2068 if (NULL == core_api)
2070 ats = GNUNET_ATS_performance_init (cfg,
2075 GNUNET_CORE_disconnect (core_api);
2079 nc = GNUNET_notification_context_create (MAX_QUEUE_SIZE_PLUGIN);
2080 stats = GNUNET_STATISTICS_create ("dv",
2082 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2088 * Callback called when a client connects to the service.
2090 * @param cls closure for the service
2091 * @param c the new client that connected to the service
2092 * @param mq the message queue used to send messages to the client
2096 client_connect_cb (void *cls,
2097 struct GNUNET_SERVICE_Client *c,
2098 struct GNUNET_MQ_Handle *mq)
2105 * Callback called when a client disconnected from the service
2107 * @param cls closure for the service
2108 * @param c the client that disconnected
2109 * @param internal_cls should be equal to @a c
2112 client_disconnect_cb (void *cls,
2113 struct GNUNET_SERVICE_Client *c,
2116 GNUNET_assert (c == internal_cls);
2121 * Define "main" method using service macro.
2125 GNUNET_SERVICE_OPTION_NONE,
2128 &client_disconnect_cb,
2130 GNUNET_MQ_hd_fixed_size (start,
2131 GNUNET_MESSAGE_TYPE_DV_START,
2132 struct GNUNET_MessageHeader,
2134 GNUNET_MQ_hd_var_size (dv_send_message,
2135 GNUNET_MESSAGE_TYPE_DV_SEND,
2136 struct GNUNET_DV_SendMessage,
2138 GNUNET_MQ_handler_end ());
2141 /* end of gnunet-service-dv.c */