2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file dv/gnunet-service-dv.c
23 * @brief the distance vector service, primarily handles gossip of nearby
24 * peers and sending/receiving DV messages from core and decapsulating
27 * @author Christian Grothoff
28 * @author Nathan Evans
31 * - routing tables are not exchanged with direct neighbors
32 * - distance updates are not properly communicate to US by core,
33 * and conversely we don't give distance updates properly to the plugin yet
34 * - even local flow control (send ACK only after core took our message) is
35 * not implemented, but should be (easy fix)
36 * - we send 'ACK' even if a message was dropped due to no route (may
37 * be harmless, but should at least be documented)
40 #include "gnunet_util_lib.h"
41 #include "gnunet_protocols.h"
42 #include "gnunet_core_service.h"
43 #include "gnunet_hello_lib.h"
44 #include "gnunet_peerinfo_service.h"
45 #include "gnunet_statistics_service.h"
46 #include "gnunet_consensus_service.h"
50 * How often do we establish the consensu?
52 #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
55 * Maximum number of messages we queue per peer.
57 #define MAX_QUEUE_SIZE 16
60 * The default fisheye depth, from how many hops away will
63 #define DEFAULT_FISHEYE_DEPTH 3
66 * How many hops is a direct neighbor away?
68 #define DIRECT_NEIGHBOR_COST 1
71 GNUNET_NETWORK_STRUCT_BEGIN
74 * Information about a peer DV can route to. These entries are what
75 * we use as the binary format to establish consensus to create our
76 * routing table and as the address format in the HELLOs.
82 * Identity of the peer we can reach.
84 struct GNUNET_PeerIdentity peer;
87 * How many hops (1-3) is this peer away?
89 uint32_t distance GNUNET_PACKED;
95 * Message exchanged between DV services (via core), requesting a
96 * message to be routed.
101 * Type: GNUNET_MESSAGE_TYPE_DV_ROUTE
103 struct GNUNET_MessageHeader header;
106 * Expected (remaining) distance. Must be always smaller than
107 * DEFAULT_FISHEYE_DEPTH, should be zero at the target. Must
108 * be decremented by one at each hop. Peers must not forward
109 * these messages further once the counter has reached zero.
111 uint32_t distance GNUNET_PACKED;
114 * The (actual) target of the message (this peer, if distance is zero).
116 struct GNUNET_PeerIdentity target;
119 * The (actual) sender of the message.
121 struct GNUNET_PeerIdentity sender;
125 GNUNET_NETWORK_STRUCT_END
129 * Linked list of messages to send to clients.
131 struct PendingMessage
134 * Pointer to next item in the list
136 struct PendingMessage *next;
139 * Pointer to previous item in the list
141 struct PendingMessage *prev;
144 * Actual message to be sent, allocated after this struct.
146 const struct GNUNET_MessageHeader *msg;
149 * Ultimate target for the message.
151 struct GNUNET_PeerIdentity ultimate_target;
154 * Unique ID of the message.
162 * Information about a direct neighbor (core-level, excluding
163 * DV-links, only DV-enabled peers).
165 struct DirectNeighbor
169 * Identity of the peer.
171 struct GNUNET_PeerIdentity peer;
174 * Head of linked list of messages to send to this peer.
176 struct PendingMessage *pm_head;
179 * Tail of linked list of messages to send to this peer.
181 struct PendingMessage *pm_tail;
184 * Transmit handle to core service.
186 struct GNUNET_CORE_TransmitHandle *cth;
189 * Routing table of the neighbor, NULL if not yet established.
190 * Keys are peer identities, values are 'struct Target' entries.
191 * Note that the distances in the targets are from the point-of-view
192 * of the peer, not from us!
194 struct GNUNET_CONTAINER_MultiHashMap *neighbor_table;
197 * Updated routing table of the neighbor, under construction,
198 * NULL if we are not currently building it.
199 * Keys are peer identities, values are 'struct Target' entries.
200 * Note that the distances in the targets are from the point-of-view
201 * of the peer, not from us!
203 struct GNUNET_CONTAINER_MultiHashMap *neighbor_table_consensus;
206 * Active consensus, if we are currently synchronizing the
209 struct GNUNET_CONSENSUS_Handle *consensus;
212 * ID of the task we use to (periodically) update our consensus
215 GNUNET_SCHEDULER_TaskIdentifier consensus_task;
218 * At what offset are we, with respect to inserting our own routes
219 * into the consensus?
221 unsigned int consensus_insertion_offset;
224 * At what distance are we, with respect to inserting our own routes
225 * into the consensus?
227 unsigned int consensus_insertion_distance;
230 * Number of messages currently in the 'pm_XXXX'-DLL.
232 unsigned int pm_queue_size;
238 * A route includes information about the next hop,
239 * the target, and the ultimate distance to the
246 * Which peer do we need to forward the message to?
248 struct DirectNeighbor *next_hop;
251 * What would be the target, and how far is it away?
253 struct Target target;
256 * Offset of this target in the respective consensus set.
258 unsigned int set_offset;
264 * Set of targets we bring to a consensus; all targets in a set have a
265 * distance equal to the sets distance (which is implied by the array
272 * Array of targets in the set, may include NULL entries if a
273 * neighbor has disconnected; the targets are allocated with the
274 * respective container (all_routes), not here.
276 struct Route **targets;
279 * Size of the 'targets' array.
281 unsigned int array_length;
287 * Hashmap of all of our direct neighbors (no DV routing).
289 static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
292 * Hashmap with all routes that we currently support; contains
293 * routing information for all peers from distance 2
294 * up to distance DEFAULT_FISHEYE_DEPTH.
296 static struct GNUNET_CONTAINER_MultiHashMap *all_routes;
299 * Array of consensus sets we expose to the outside world. Sets
300 * are structured by the distance to the target.
302 static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH - 1];
305 * Handle to the core service api.
307 static struct GNUNET_CORE_Handle *core_api;
310 * The identity of our peer.
312 static struct GNUNET_PeerIdentity my_identity;
315 * The configuration for this service.
317 static const struct GNUNET_CONFIGURATION_Handle *cfg;
320 * The client, the DV plugin connected to us. Hopefully
321 * this client will never change, although if the plugin dies
322 * and returns for some reason it may happen.
324 static struct GNUNET_SERVER_Client *client_handle;
327 * Transmit handle to the plugin.
329 static struct GNUNET_SERVER_TransmitHandle *plugin_transmit_handle;
332 * Head of DLL for client messages
334 static struct PendingMessage *plugin_pending_head;
337 * Tail of DLL for client messages
339 static struct PendingMessage *plugin_pending_tail;
342 * Handle for the statistics service.
344 struct GNUNET_STATISTICS_Handle *stats;
348 * Get distance information from 'atsi'.
350 * @param atsi performance data
351 * @param atsi_count number of entries in atsi
352 * @return connected transport distance
355 get_atsi_distance (const struct GNUNET_ATS_Information *atsi,
356 unsigned int atsi_count)
360 for (i = 0; i < atsi_count; i++)
361 if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE)
362 return ntohl (atsi->value);
363 /* FIXME: we do not have distance data? Assume direct neighbor. */
364 return DIRECT_NEIGHBOR_COST;
369 * Function called to notify a client about the socket
370 * begin ready to queue more data. "buf" will be
371 * NULL and "size" zero if the socket was closed for
372 * writing in the meantime.
375 * @param size number of bytes available in buf
376 * @param buf where the callee should write the message
377 * @return number of bytes written to buf
380 transmit_to_plugin (void *cls, size_t size, void *buf)
383 struct PendingMessage *reply;
387 plugin_transmit_handle = NULL;
390 /* client disconnected */
394 while ( (NULL != (reply = plugin_pending_head)) &&
395 (size >= off + (msize = ntohs (reply->msg->size))))
397 GNUNET_CONTAINER_DLL_remove (plugin_pending_head, plugin_pending_tail,
399 memcpy (&cbuf[off], reply->msg, msize);
403 if (NULL != plugin_pending_head)
404 plugin_transmit_handle =
405 GNUNET_SERVER_notify_transmit_ready (client_handle,
407 GNUNET_TIME_UNIT_FOREVER_REL,
408 &transmit_to_plugin, NULL);
414 * Forward a message from another peer to the plugin.
416 * @param message the message to send to the plugin
417 * @param distant_neighbor the original sender of the message
418 * @param distnace distance to the original sender of the message
421 send_data_to_plugin (const struct GNUNET_MessageHeader *message,
422 const struct GNUNET_PeerIdentity *distant_neighbor,
425 struct GNUNET_DV_ReceivedMessage *received_msg;
426 struct PendingMessage *pending_message;
429 if (NULL == client_handle)
431 GNUNET_STATISTICS_update (stats,
432 "# messages discarded (no plugin)",
434 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435 _("Refusing to queue messages, DV plugin not active.\n"));
438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439 "Delivering message from peer `%s'\n",
440 GNUNET_i2s (distant_neighbor));
441 size = sizeof (struct GNUNET_DV_ReceivedMessage) +
442 ntohs (message->size);
443 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
445 GNUNET_break (0); /* too big */
448 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
449 received_msg = (struct GNUNET_DV_ReceivedMessage *) &pending_message[1];
450 received_msg->header.size = htons (size);
451 received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
452 received_msg->distance = htonl (distance);
453 received_msg->sender = *distant_neighbor;
454 memcpy (&received_msg[1], message, ntohs (message->size));
455 GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head,
458 if (NULL == plugin_transmit_handle)
459 plugin_transmit_handle =
460 GNUNET_SERVER_notify_transmit_ready (client_handle, size,
461 GNUNET_TIME_UNIT_FOREVER_REL,
462 &transmit_to_plugin, NULL);
467 * Forward a control message to the plugin.
469 * @param message the message to send to the plugin
470 * @param distant_neighbor the original sender of the message
471 * @param distnace distance to the original sender of the message
474 send_control_to_plugin (const struct GNUNET_MessageHeader *message)
476 struct PendingMessage *pending_message;
479 if (NULL == client_handle)
481 GNUNET_STATISTICS_update (stats,
482 "# control messages discarded (no plugin)",
484 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
485 _("Refusing to queue messages, DV plugin not active.\n"));
488 size = ntohs (message->size);
489 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
490 memcpy (&pending_message[1], message, size);
491 GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head,
494 if (NULL == plugin_transmit_handle)
495 plugin_transmit_handle =
496 GNUNET_SERVER_notify_transmit_ready (client_handle, size,
497 GNUNET_TIME_UNIT_FOREVER_REL,
498 &transmit_to_plugin, NULL);
503 * Give an ACK message to the plugin, we transmitted a message for it.
505 * @param target peer that received the message
506 * @param uid plugin-chosen UID for the message
509 send_ack_to_plugin (const struct GNUNET_PeerIdentity *target,
512 struct GNUNET_DV_AckMessage ack_msg;
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "Delivering ACK for message to peer `%s'\n",
516 GNUNET_i2s (target));
517 ack_msg.header.size = htons (sizeof (ack_msg));
518 ack_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_SEND_ACK);
519 ack_msg.uid = htonl (uid);
520 ack_msg.target = *target;
521 send_control_to_plugin (&ack_msg.header);
526 * Give a CONNECT message to the plugin.
528 * @param target peer that connected
529 * @param distance distance to the target
532 send_connect_to_plugin (const struct GNUNET_PeerIdentity *target,
535 struct GNUNET_DV_ConnectMessage cm;
537 if (NULL == client_handle)
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Delivering CONNECT about peer `%s'\n",
541 GNUNET_i2s (target));
542 cm.header.size = htons (sizeof (cm));
543 cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
544 cm.distance = htonl (distance);
546 send_control_to_plugin (&cm.header);
551 * Give a DISCONNECT message to the plugin.
553 * @param target peer that disconnected
556 send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
558 struct GNUNET_DV_DisconnectMessage dm;
560 if (NULL == client_handle)
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563 "Delivering DISCONNECT about peer `%s'\n",
564 GNUNET_i2s (target));
565 dm.header.size = htons (sizeof (dm));
566 dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
567 dm.reserved = htonl (0);
569 send_control_to_plugin (&dm.header);
574 * Function called to transfer a message to another peer
577 * @param cls closure with the direct neighbor
578 * @param size number of bytes available in buf
579 * @param buf where the callee should write the message
580 * @return number of bytes written to buf
583 core_transmit_notify (void *cls, size_t size, void *buf)
585 struct DirectNeighbor *dn = cls;
587 struct PendingMessage *pending;
594 /* peer disconnected */
598 pending = dn->pm_head;
600 while ( (NULL != (pending = dn->pm_head)) &&
601 (size >= off + (msize = ntohs (pending->msg->size))))
604 GNUNET_CONTAINER_DLL_remove (dn->pm_head,
607 memcpy (&cbuf[off], pending->msg, msize);
608 send_ack_to_plugin (&pending->ultimate_target,
610 GNUNET_free (pending);
613 if (NULL != dn->pm_head)
615 GNUNET_CORE_notify_transmit_ready (core_api,
616 GNUNET_YES /* cork */,
618 GNUNET_TIME_UNIT_FOREVER_REL,
621 &core_transmit_notify, dn);
627 * Forward the given payload to the given target.
629 * @param target where to send the message
630 * @param distance expected (remaining) distance to the target
631 * @param sender original sender of the message
632 * @param payload payload of the message
635 forward_payload (struct DirectNeighbor *target,
637 const struct GNUNET_PeerIdentity *sender,
638 const struct GNUNET_MessageHeader *payload)
640 struct PendingMessage *pm;
641 struct RouteMessage *rm;
644 if ( (target->pm_queue_size >= MAX_QUEUE_SIZE) &&
645 (0 != memcmp (sender,
647 sizeof (struct GNUNET_PeerIdentity))) )
649 msize = sizeof (struct RouteMessage) + ntohs (payload->size);
650 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
655 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
656 pm->msg = (const struct GNUNET_MessageHeader *) &pm[1];
657 rm = (struct RouteMessage *) &pm[1];
658 rm->header.size = htons ((uint16_t) msize);
659 rm->header.type = htons (GNUNET_MESSAGE_TYPE_DV_ROUTE);
660 rm->distance = htonl (distance);
661 rm->target = target->peer;
662 rm->sender = *sender;
663 memcpy (&rm[1], payload, ntohs (payload->size));
664 GNUNET_CONTAINER_DLL_insert_tail (target->pm_head,
667 target->pm_queue_size++;
668 if (NULL == target->cth)
669 target->cth = GNUNET_CORE_notify_transmit_ready (core_api,
670 GNUNET_YES /* cork */,
672 GNUNET_TIME_UNIT_FOREVER_REL,
675 &core_transmit_notify, target);
680 * Find a free slot for storing a 'route' in the 'consensi'
681 * set at the given distance.
683 * @param distance distance to use for the set slot
686 get_consensus_slot (uint32_t distance)
688 struct ConsensusSet *cs;
691 cs = &consensi[distance];
693 while ( (i < cs->array_length) &&
694 (NULL != cs->targets[i]) ) i++;
695 if (i == cs->array_length)
696 GNUNET_array_grow (cs->targets,
698 cs->array_length * 2 + 2);
704 * Allocate a slot in the consensus set for a route.
706 * @param route route to initialize
707 * @param distance which consensus set to use
710 allocate_route (struct Route *route,
715 i = get_consensus_slot (distance);
716 route->set_offset = i;
717 consensi[distance].targets[i] = route;
718 route->target.distance = distance;
723 * Release a slot in the consensus set for a route.
725 * @param route route to release the slot from
728 release_route (struct Route *route)
730 consensi[route->target.distance].targets[route->set_offset] = NULL;
731 route->set_offset = UINT_MAX; /* indicate invalid slot */
736 * Move a route from one consensus set to another.
738 * @param route route to move
739 * @param new_distance new distance for the route (destination set)
742 move_route (struct Route *route,
743 uint32_t new_distance)
747 release_route (route);
748 i = get_consensus_slot (new_distance);
749 route->set_offset = i;
750 consensi[new_distance].targets[i] = route;
751 route->target.distance = new_distance;
756 * Start creating a new consensus from scratch.
758 * @param cls the 'struct DirectNeighbor' of the peer we're building
759 * a routing consensus with
760 * @param tc scheduler context
763 start_consensus (void *cls,
764 const struct GNUNET_SCHEDULER_TaskContext *tc);
768 * Method called whenever a peer connects.
771 * @param peer peer identity this notification is about
772 * @param atsi performance data
773 * @param atsi_count number of entries in atsi
776 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
777 const struct GNUNET_ATS_Information *atsi,
778 unsigned int atsi_count)
780 struct DirectNeighbor *neighbor;
784 /* Check for connect to self message */
785 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
787 distance = get_atsi_distance (atsi, atsi_count);
788 neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors,
790 if (NULL != neighbor)
795 if (DIRECT_NEIGHBOR_COST != distance)
796 return; /* is a DV-neighbor */
797 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
798 neighbor->peer = *peer;
799 GNUNET_assert (GNUNET_YES ==
800 GNUNET_CONTAINER_multihashmap_put (direct_neighbors,
803 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
804 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
808 send_disconnect_to_plugin (peer);
809 release_route (route);
812 route->next_hop = neighbor;
813 neighbor->consensus_task = GNUNET_SCHEDULER_add_now (&start_consensus,
819 * We inserted the last element into the consensus, get ready to
820 * insert the next element into the consensus or conclude if
823 * @param cls the 'struct DirectNeighbor' of the peer we're building
824 * a routing consensus with
825 * @param success GNUNET_OK if the last element was added successfully,
826 * GNUNET_SYSERR if we failed
829 insert_next_element (void *cls,
832 struct DirectNeighbor *neighbor = cls;
833 struct GNUNET_CONSENSUS_Element element;
835 // FIXME: initialize element...
836 GNUNET_CONSENSUS_insert (neighbor->consensus,
838 &insert_next_element,
844 * We have learned a new route from the other peer. Add it to the
845 * route set we're building.
847 * @param cls the 'struct DirectNeighbor' we're building the consensus with
848 * @param element the new element we have learned
849 * @return GNUNET_OK if the valid is well-formed and should be added to the consensus,
850 * GNUNET_SYSERR if the element should be ignored and not be propagated
853 learn_route_cb (void *cls,
854 const struct GNUNET_CONSENSUS_Element *element)
856 GNUNET_break (0); // FIXME
857 return GNUNET_SYSERR;
862 * Start creating a new consensus from scratch.
864 * @param cls the 'struct DirectNeighbor' of the peer we're building
865 * a routing consensus with
866 * @param tc scheduler context
869 start_consensus (void *cls,
870 const struct GNUNET_SCHEDULER_TaskContext *tc)
872 struct DirectNeighbor *neighbor = cls;
873 struct GNUNET_HashCode session_id;
875 neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
876 GNUNET_assert (NULL == neighbor->consensus);
877 GNUNET_CRYPTO_hash_xor (&session_id, &my_identity.hashPubKey, &neighbor->peer.hashPubKey); // ARG order?
878 neighbor->consensus = GNUNET_CONSENSUS_create (cfg,
884 if (NULL == neighbor->consensus)
886 neighbor->consensus_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
891 insert_next_element (neighbor, GNUNET_OK);
896 * Core handler for DV data messages. Whatever this message
897 * contains all we really have to do is rip it out of its
898 * DV layering and give it to our pal the DV plugin to report
902 * @param peer peer which sent the message (immediate sender)
903 * @param message the message
904 * @param atsi transport ATS information (latency, distance, etc.)
905 * @param atsi_count number of entries in atsi
906 * @return GNUNET_OK on success, GNUNET_SYSERR if the other peer violated the protocol
909 handle_dv_route_message (void *cls, const struct GNUNET_PeerIdentity *peer,
910 const struct GNUNET_MessageHeader *message,
911 const struct GNUNET_ATS_Information *atsi,
912 unsigned int atsi_count)
914 const struct RouteMessage *rm;
915 const struct GNUNET_MessageHeader *payload;
918 if (ntohs (message->size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader))
921 return GNUNET_SYSERR;
923 rm = (const struct RouteMessage *) message;
924 payload = (const struct GNUNET_MessageHeader *) &rm[1];
925 if (ntohs (message->size) != sizeof (struct RouteMessage) + ntohs (payload->size))
928 return GNUNET_SYSERR;
930 if (0 == memcmp (&rm->target,
932 sizeof (struct GNUNET_PeerIdentity)))
934 /* message is for me, check reverse route! */
935 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
936 &rm->sender.hashPubKey);
939 /* don't have reverse route, drop */
940 GNUNET_STATISTICS_update (stats,
941 "# message discarded (no reverse route)",
945 send_data_to_plugin (payload,
947 route->target.distance);
950 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
951 &rm->target.hashPubKey);
954 GNUNET_STATISTICS_update (stats,
955 "# messages discarded (no route)",
959 if (route->target.distance > ntohl (rm->distance) + 1)
961 GNUNET_STATISTICS_update (stats,
962 "# messages discarded (target too far)",
966 forward_payload (route->next_hop,
967 route->target.distance,
975 * Service server's handler for message send requests (which come
976 * bubbling up to us through the DV plugin).
979 * @param client identification of the client
980 * @param message the actual message
983 handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client,
984 const struct GNUNET_MessageHeader *message)
987 const struct GNUNET_DV_SendMessage *msg;
988 const struct GNUNET_MessageHeader *payload;
990 if (ntohs (message->size) < sizeof (struct GNUNET_DV_SendMessage) + sizeof (struct GNUNET_MessageHeader))
993 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
996 msg = (const struct GNUNET_DV_SendMessage *) message;
997 payload = (const struct GNUNET_MessageHeader *) &msg[1];
998 if (ntohs (message->size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size))
1001 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1004 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1005 &msg->target.hashPubKey);
1008 /* got disconnected, send ACK anyway?
1009 FIXME: What we really want is an 'NACK' here... */
1010 GNUNET_STATISTICS_update (stats,
1011 "# local messages discarded (no route)",
1013 send_ack_to_plugin (&msg->target, htonl (msg->uid));
1014 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1017 // FIXME: flow control (send ACK only once message has left the queue...)
1018 send_ack_to_plugin (&msg->target, htonl (msg->uid));
1019 forward_payload (route->next_hop,
1020 route->target.distance,
1023 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1028 * Multihashmap iterator for freeing routes that go via a particular
1029 * neighbor that disconnected and is thus no longer available.
1031 * @param cls the direct neighbor that is now unavailable
1032 * @param key key value stored under
1033 * @param value a 'struct Route' that may or may not go via neighbor
1035 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1038 cull_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
1040 struct DirectNeighbor *neighbor = cls;
1041 struct Route *route = value;
1043 if (route->next_hop != neighbor)
1044 return GNUNET_YES; /* not affected */
1045 GNUNET_assert (GNUNET_YES ==
1046 GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
1047 release_route (route);
1048 send_disconnect_to_plugin (&route->target.peer);
1049 GNUNET_free (route);
1055 * Multihashmap iterator for checking if a given route is
1056 * (now) useful to this peer.
1058 * @param cls the direct neighbor for the given route
1059 * @param key key value stored under
1060 * @param value a 'struct Target' that may or may not be useful; not that
1061 * the distance in 'target' does not include the first hop yet
1062 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1065 check_possible_route (void *cls, const struct GNUNET_HashCode * key, void *value)
1067 struct DirectNeighbor *neighbor = cls;
1068 struct Target *target = value;
1069 struct Route *route;
1071 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1075 if (route->target.distance > target->distance + 1)
1077 /* this 'target' is cheaper than the existing route; switch to alternative route! */
1078 move_route (route, target->distance + 1);
1079 route->next_hop = neighbor;
1080 // FIXME: notify plugin about distance update?
1082 return GNUNET_YES; /* got a route to this target already */
1084 route = GNUNET_malloc (sizeof (struct Route));
1085 route->next_hop = neighbor;
1086 route->target.distance = target->distance + 1;
1087 route->target.peer = target->peer;
1088 allocate_route (route, route->target.distance);
1089 GNUNET_assert (GNUNET_YES ==
1090 GNUNET_CONTAINER_multihashmap_put (all_routes,
1091 &route->target.peer.hashPubKey,
1093 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1094 send_connect_to_plugin (&route->target.peer, target->distance);
1100 * Multihashmap iterator for finding routes that were previously
1101 * "hidden" due to a better route (called after a disconnect event).
1104 * @param key peer identity of the given direct neighbor
1105 * @param value a 'struct DirectNeighbor' to check for additional routes
1106 * @return GNUNET_YES to continue iteration
1109 refresh_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
1111 struct DirectNeighbor *neighbor = value;
1113 if (NULL != neighbor->neighbor_table)
1114 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
1115 &check_possible_route,
1122 * Cleanup all of the data structures associated with a given neighbor.
1124 * @param neighbor neighbor to clean up
1127 cleanup_neighbor (struct DirectNeighbor *neighbor)
1129 struct PendingMessage *pending;
1131 while (NULL != (pending = neighbor->pm_head))
1133 neighbor->pm_queue_size--;
1134 GNUNET_CONTAINER_DLL_remove (neighbor->pm_head,
1137 GNUNET_free (pending);
1139 GNUNET_CONTAINER_multihashmap_iterate (all_routes,
1142 if (NULL != neighbor->cth)
1144 GNUNET_CORE_notify_transmit_ready_cancel (neighbor->cth);
1145 neighbor->cth = NULL;
1147 if (GNUNET_SCHEDULER_NO_TASK != neighbor->consensus_task)
1149 GNUNET_SCHEDULER_cancel (neighbor->consensus_task);
1150 neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
1152 if (NULL != neighbor->consensus)
1154 GNUNET_CONSENSUS_destroy (neighbor->consensus);
1155 neighbor->consensus = NULL;
1157 GNUNET_assert (GNUNET_YES ==
1158 GNUNET_CONTAINER_multihashmap_remove (direct_neighbors,
1159 &neighbor->peer.hashPubKey,
1161 GNUNET_free (neighbor);
1166 * Method called whenever a given peer disconnects.
1168 * @param cls closure
1169 * @param peer peer identity this notification is about
1172 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1174 struct DirectNeighbor *neighbor;
1176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177 "Received core peer disconnect message for peer `%s'!\n",
1179 /* Check for disconnect from self message */
1180 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
1183 GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
1184 if (NULL == neighbor)
1186 /* must have been a DV-neighbor, ignore */
1189 cleanup_neighbor (neighbor);
1190 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1197 * Multihashmap iterator for freeing routes. Should never be called.
1200 * @param key key value stored under
1201 * @param value the route to be freed
1203 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1206 free_route (void *cls, const struct GNUNET_HashCode * key, void *value)
1208 struct Route *route = value;
1211 GNUNET_assert (GNUNET_YES ==
1212 GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
1213 release_route (route);
1214 send_disconnect_to_plugin (&route->target.peer);
1215 GNUNET_free (route);
1221 * Multihashmap iterator for freeing direct neighbors. Should never be called.
1224 * @param key key value stored under
1225 * @param value the direct neighbor to be freed
1227 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1230 free_direct_neighbors (void *cls, const struct GNUNET_HashCode * key, void *value)
1232 struct DirectNeighbor *neighbor = value;
1235 cleanup_neighbor (neighbor);
1241 * Task run during shutdown.
1247 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1249 struct PendingMessage *pending;
1252 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1253 &free_direct_neighbors, NULL);
1254 GNUNET_CONTAINER_multihashmap_destroy (direct_neighbors);
1255 GNUNET_CONTAINER_multihashmap_iterate (all_routes,
1257 GNUNET_CONTAINER_multihashmap_destroy (all_routes);
1258 GNUNET_CORE_disconnect (core_api);
1260 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1262 while (NULL != (pending = plugin_pending_head))
1264 GNUNET_CONTAINER_DLL_remove (plugin_pending_head,
1265 plugin_pending_tail,
1267 GNUNET_free (pending);
1269 for (i=0;i<DEFAULT_FISHEYE_DEPTH - 1;i++)
1270 GNUNET_array_grow (consensi[i].targets,
1271 consensi[i].array_length,
1277 * Handle START-message. This is the first message sent to us
1278 * by the client (can only be one!).
1280 * @param cls closure (always NULL)
1281 * @param client identification of the client
1282 * @param message the actual message
1285 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
1286 const struct GNUNET_MessageHeader *message)
1288 if (NULL != client_handle)
1290 /* forcefully drop old client */
1291 GNUNET_SERVER_client_disconnect (client_handle);
1292 GNUNET_SERVER_client_drop (client_handle);
1294 client_handle = client;
1295 GNUNET_SERVER_client_keep (client_handle);
1296 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1301 * Called on core init.
1304 * @param server legacy
1305 * @param identity this peer's identity
1308 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1309 const struct GNUNET_PeerIdentity *identity)
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313 GNUNET_i2s (identity));
1314 my_identity = *identity;
1319 * Process dv requests.
1321 * @param cls closure
1322 * @param server the initialized server
1323 * @param c configuration to use
1326 run (void *cls, struct GNUNET_SERVER_Handle *server,
1327 const struct GNUNET_CONFIGURATION_Handle *c)
1329 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1330 {&handle_dv_route_message, GNUNET_MESSAGE_TYPE_DV_ROUTE, 0},
1333 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
1334 {&handle_start, NULL,
1335 GNUNET_MESSAGE_TYPE_DV_START,
1336 sizeof (struct GNUNET_MessageHeader) },
1337 { &handle_dv_send_message, NULL,
1338 GNUNET_MESSAGE_TYPE_DV_SEND,
1344 direct_neighbors = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1345 all_routes = GNUNET_CONTAINER_multihashmap_create (65536, GNUNET_NO);
1346 core_api = GNUNET_CORE_connect (cfg, NULL,
1348 &handle_core_connect,
1349 &handle_core_disconnect,
1354 if (NULL == core_api)
1356 stats = GNUNET_STATISTICS_create ("dv", cfg);
1357 GNUNET_SERVER_add_handlers (server, plugin_handlers);
1358 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1359 &shutdown_task, NULL);
1364 * The main function for the dv service.
1366 * @param argc number of arguments from the command line
1367 * @param argv command line arguments
1368 * @return 0 ok, 1 on error
1371 main (int argc, char *const *argv)
1373 return (GNUNET_OK ==
1374 GNUNET_SERVICE_run (argc, argv, "dv", GNUNET_SERVICE_OPTION_NONE,
1375 &run, NULL)) ? 0 : 1;
1378 /* end of gnunet-service-dv.c */