2 This file is part of GNUnet.
3 (C) 2009 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 2, 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
32 #include "gnunet_client_lib.h"
33 #include "gnunet_getopt_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_service_lib.h"
37 #include "gnunet_core_service.h"
38 #include "gnunet_signal_lib.h"
39 #include "gnunet_util_lib.h"
43 * DV Service Context stuff goes here...
47 * Handle to the core service api.
49 static struct GNUNET_CORE_Handle *coreAPI;
52 * The identity of our peer.
54 static struct GNUNET_PeerIdentity my_identity;
57 * The configuration for this service.
59 static const struct GNUNET_CONFIGURATION_Handle *cfg;
62 * The scheduler for this service.
64 static struct GNUNET_SCHEDULER_Handle *sched;
67 * How often do we check about sending out more peer information (if
68 * we are connected to no peers previously).
70 #define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500))
73 * How long do we wait at most between sending out information?
75 #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
78 * How long can we have not heard from a peer and
79 * still have it in our tables?
81 #define GNUNET_DV_PEER_EXPIRATION_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1000))
84 * Priority for gossip.
86 #define GNUNET_DV_DHT_GOSSIP_PRIORITY (GNUNET_EXTREME_PRIORITY / 10)
89 * How often should we check if expiration time has elapsed for
92 #define GNUNET_DV_MAINTAIN_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
95 * How long to allow a message to be delayed?
97 #define DV_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
100 * Priority to use for DV data messages.
102 #define DV_PRIORITY 0
105 * The client, should be the DV plugin connected to us. Hopefully
106 * this client will never change, although if the plugin dies
107 * and returns for some reason it may happen.
109 static struct GNUNET_SERVER_Client * client_handle;
112 * Task to run when we shut down, cleaning up all our trash
114 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
117 * Task to run to gossip about peers. Will reschedule itself forever until shutdown!
119 GNUNET_SCHEDULER_TaskIdentifier gossip_task;
122 * Struct where neighbor information is stored.
124 struct DistantNeighbor *referees;
126 static struct GNUNET_TIME_Relative client_transmit_timeout;
128 static struct GNUNET_TIME_Relative default_dv_delay;
130 static size_t default_dv_priority = 0;
134 * Pending message struct, also a test to see if these can
135 * safely ONLY be freed by callback.
137 struct PendingMessage
140 * Copy of message to be sent
142 struct GNUNET_MessageHeader *msg;
145 * Size of message to be sent
150 * Transmit handle, for cancellation if necessary.
152 struct GNUNET_CORE_TransmitHandle *transmit_handle;
158 * Context created whenever a direct peer connects to us,
159 * used to gossip other peers to it.
161 struct NeighborSendContext
164 * The peer we will gossip to.
166 struct DirectNeighbor *toNeighbor;
169 * The timeout for this task.
171 struct GNUNET_TIME_Relative timeout;
174 * The task associated with this context.
176 GNUNET_SCHEDULER_TaskIdentifier task;
182 * Struct to hold information for updating existing neighbors
184 struct NeighborUpdateInfo
192 * The existing neighbor
194 struct DistantNeighbor *neighbor;
197 * The referrer of the possibly existing peer
199 struct DirectNeighbor *referrer;
202 * The time we heard about this peer
204 struct GNUNET_TIME_Absolute now;
208 * Struct where actual neighbor information is stored,
209 * referenced by min_heap and max_heap. Freeing dealt
210 * with when items removed from hashmap.
212 struct DirectNeighbor
215 * Identity of neighbor.
217 struct GNUNET_PeerIdentity identity;
220 * Head of DLL of nodes that this direct neighbor referred to us.
222 struct DistantNeighbor *referee_head;
225 * Tail of DLL of nodes that this direct neighbor referred to us.
227 struct DistantNeighbor *referee_tail;
230 * The sending context for gossiping peers to this neighbor.
232 struct NeighborSendContext *send_context;
235 * Is this one of the direct neighbors that we are "hiding"
243 * Struct where actual neighbor information is stored,
244 * referenced by min_heap and max_heap. Freeing dealt
245 * with when items removed from hashmap.
247 struct DistantNeighbor
250 * We keep distant neighbor's of the same referrer in a DLL.
252 struct DistantNeighbor *next;
255 * We keep distant neighbor's of the same referrer in a DLL.
257 struct DistantNeighbor *prev;
262 struct GNUNET_CONTAINER_HeapNode *min_loc;
267 struct GNUNET_CONTAINER_HeapNode *max_loc;
270 * Identity of referrer (next hop towards 'neighbor').
272 struct DirectNeighbor *referrer;
275 * Identity of neighbor.
277 struct GNUNET_PeerIdentity identity;
280 * Last time we received routing information from this peer
282 struct GNUNET_TIME_Absolute last_activity;
285 * Cost to neighbor, used for actual distance vector computations
290 * Random identifier *we* use for this peer, to be used as shortcut
291 * instead of sending full peer id for each message
296 * Random identifier the *referrer* uses for this peer.
298 unsigned int referrer_id;
301 * Is this one of the direct neighbors that we are "hiding"
311 struct GNUNET_DV_Context
314 * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all
315 * directly connected peers.
317 struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
320 * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for
321 * peers connected via DV (extended neighborhood). Does ALSO
322 * include any peers that are in 'direct_neighbors'; for those
323 * peers, the cost will be zero and the referrer all zeros.
325 struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors;
328 * We use the min heap (min refers to cost) to prefer
329 * gossipping about peers with small costs.
331 struct GNUNET_CONTAINER_Heap *neighbor_min_heap;
334 * We use the max heap (max refers to cost) for general
335 * iterations over all peers and to remove the most costly
336 * connection if we have too many.
338 struct GNUNET_CONTAINER_Heap *neighbor_max_heap;
340 unsigned long long fisheye_depth;
342 unsigned long long max_table_size;
344 unsigned int neighbor_id_loc;
350 static struct GNUNET_DV_Context ctx;
352 struct FindDestinationContext
355 struct DistantNeighbor *dest;
360 * We've been given a target ID based on the random numbers that
361 * we assigned to our DV-neighborhood. Find the entry for the
362 * respective neighbor.
365 find_destination (void *cls,
366 struct GNUNET_CONTAINER_HeapNode *node,
367 void *element, GNUNET_CONTAINER_HeapCostType cost)
369 struct FindDestinationContext *fdc = cls;
370 struct DistantNeighbor *dn = element;
372 if (fdc->tid != dn->our_id)
379 * Function called to notify a client about the socket
380 * begin ready to queue more data. "buf" will be
381 * NULL and "size" zero if the socket was closed for
382 * writing in the meantime.
385 * @param size number of bytes available in buf
386 * @param buf where the callee should write the message
387 * @return number of bytes written to buf
389 size_t transmit_to_plugin (void *cls,
390 size_t size, void *buf)
392 struct GNUNET_DV_MessageReceived *msg = cls;
397 GNUNET_assert(size >= ntohs(msg->header.size));
399 memcpy(buf, msg, size);
405 void send_to_plugin(const struct GNUNET_PeerIdentity * sender, const struct GNUNET_MessageHeader *message, size_t message_size, struct DistantNeighbor *distant_neighbor)
407 struct GNUNET_DV_MessageReceived *received_msg;
410 size = sizeof(struct GNUNET_DV_MessageReceived) + sizeof(struct GNUNET_PeerIdentity) + message_size;
411 received_msg = GNUNET_malloc(size);
412 received_msg->header.size = htons(size);
413 received_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE);
414 received_msg->sender_address_len = sizeof(struct GNUNET_PeerIdentity);
415 received_msg->distance = htonl(distant_neighbor->cost);
416 received_msg->msg_len = htons(message_size);
417 /* Set the sender in this message to be the original sender! */
418 memcpy(&received_msg->sender, &distant_neighbor->identity, sizeof(struct GNUNET_PeerIdentity));
419 /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */
420 memcpy(&received_msg[1], sender, sizeof(struct GNUNET_PeerIdentity));
421 /* Copy the actual message after the sender */
422 memcpy(&received_msg[1 + sizeof(struct GNUNET_PeerIdentity)], message, message_size);
424 /* FIXME: Send to the client please */
425 GNUNET_SERVER_notify_transmit_ready (client_handle,
426 size, client_transmit_timeout,
427 &transmit_to_plugin, &received_msg);
433 * Function called to notify a client about the socket
434 * begin ready to queue more data. "buf" will be
435 * NULL and "size" zero if the socket was closed for
436 * writing in the meantime.
439 * @param size number of bytes available in buf
440 * @param buf where the callee should write the message
441 * @return number of bytes written to buf
443 size_t core_transmit_notify (void *cls,
444 size_t size, void *buf)
446 struct PendingMessage *pending_message = cls;
451 /* FIXME: error handling: try again? free pending_message? */
454 ssize = pending_message->msg_size;
455 GNUNET_assert(size >= ssize);
456 memcpy(buf, pending_message->msg, ssize);
457 GNUNET_free(pending_message->msg);
458 GNUNET_free(pending_message);
463 * Send a DV data message via DV.
465 * @param recipient the ultimate recipient of this message
466 * @param the original sender of the message
467 * @param message the packed message
468 * @param importance what priority to send this message with
469 * @param timeout how long to possibly delay sending this message
472 send_message (const struct GNUNET_PeerIdentity * recipient,
473 const struct GNUNET_PeerIdentity * sender,
474 const struct GNUNET_MessageHeader * message,
475 unsigned int importance, struct GNUNET_TIME_Relative timeout)
477 p2p_dv_MESSAGE_Data *toSend;
478 unsigned int msg_size;
480 unsigned int recipient_id;
481 unsigned int sender_id;
482 struct DistantNeighbor *target;
483 struct DistantNeighbor *source;
484 struct PendingMessage *pending_message;
486 msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
488 target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
489 &recipient->hashPubKey);
492 /* target unknown to us, drop! */
493 return GNUNET_SYSERR;
495 recipient_id = target->referrer_id;
497 source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
498 &sender->hashPubKey);
501 if (0 != (memcmp (&my_identity,
502 sender, sizeof (struct GNUNET_PeerIdentity))))
504 /* sender unknown to us, drop! */
505 return GNUNET_SYSERR;
507 sender_id = 0; /* 0 == us */
511 /* find out the number that we use when we gossip about
513 sender_id = source->our_id;
517 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
518 pending_message->msg = GNUNET_malloc (msg_size);
519 toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
520 toSend->header.size = htons (msg_size);
521 toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
522 toSend->sender = htonl (sender_id);
523 toSend->recipient = htonl (recipient_id);
524 memcpy (&toSend[1], message, ntohs (message->size));
525 pending_message->msg_size = msg_size;
527 pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, pending_message);
528 if (NULL == pending_message->transmit_handle)
530 GNUNET_free (pending_message->msg);
531 GNUNET_free (pending_message);
532 return GNUNET_SYSERR;
535 /*coreAPI->ciphertext_send (&target->referrer->identity,
536 &toSend->header, importance, maxdelay);*/
542 * Core handler for dv data messages. Whatever this message
543 * contains all we really have to do is rip it out of its
544 * DV layering and give it to our pal the DV plugin to report
548 * @param peer peer which sent the message (immediate sender)
549 * @param message the message
550 * @param latency the latency of the connection we received the message from
551 * @param distance the distance to the immediate peer
553 static int handle_dv_data_message (void *cls,
554 const struct GNUNET_PeerIdentity * peer,
555 const struct GNUNET_MessageHeader * message,
556 struct GNUNET_TIME_Relative latency,
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561 "%s: Receives %s message!\n", "dv", "DV DATA");
564 const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
565 const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
566 struct DirectNeighbor *dn;
567 struct DistantNeighbor *pos;
568 unsigned int sid; /* Sender id */
569 unsigned int tid; /* Target id */
570 struct GNUNET_PeerIdentity original_sender;
571 struct GNUNET_PeerIdentity destination;
572 struct FindDestinationContext fdc;
575 if ((ntohs (incoming->header.size) <
576 sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
577 || (ntohs (incoming->header.size) !=
578 (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
580 return GNUNET_SYSERR;
583 dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
589 sid = ntohl (incoming->sender);
590 pos = dn->referee_head;
591 while ((NULL != pos) && (pos->referrer_id != sid))
598 original_sender = pos->identity;
599 tid = ntohl (incoming->recipient);
604 /* FIXME: Will we support wrapped messages being these types? Probably not, they should
605 * be encrypted messages that need decrypting and junk like that.
607 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
608 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
609 if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
610 (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
612 send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
618 /* FIXME: this is the *only* per-request operation we have in DV
619 that is O(n) in relation to the number of connected peers; a
620 hash-table lookup could easily solve this (minor performance
624 GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
625 &find_destination, &fdc);
626 if (fdc.dest == NULL)
630 destination = fdc.dest->identity;
632 if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
634 /* FIXME: create stat: routing loop-discard! */
638 /* At this point we have a message, and we need to forward it on to the
641 /* FIXME: Can't send message on, we have to behave.
642 * We have to tell core we have a message for the next peer, and let
643 * transport do transport selection on how to get this message to 'em */
644 /*ret = send_message (&destination,
646 packed_message, DV_PRIORITY, DV_DELAY);*/
647 ret = send_message(&destination, &original_sender, packed_message, default_dv_priority, default_dv_delay);
649 if (ret != GNUNET_SYSERR)
652 return GNUNET_SYSERR;
657 * Thread which chooses a peer to gossip about and a peer to gossip
658 * to, then constructs the message and sends it out. Will run until
659 * done_module_dv is called.
662 neighbor_send_task (void *cls,
663 const struct GNUNET_SCHEDULER_TaskContext *tc)
665 struct NeighborSendContext *send_context = cls;
667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668 "%s: Entering neighbor_send_task...\n",
669 GNUNET_i2s(&my_identity));
673 struct DistantNeighbor *about;
674 struct DirectNeighbor *to;
676 p2p_dv_MESSAGE_NeighborInfo *message;
677 struct PendingMessage *pending_message;
679 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683 "%s: Called with reason shutdown, shutting down!\n",
684 GNUNET_i2s(&my_identity));
686 send_context->toNeighbor->send_context = NULL;
687 GNUNET_free(send_context);
692 /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means
693 * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
694 * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
695 * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
696 * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk
697 * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap
698 * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
699 * in the mean time that becomes nasty. For now we'll just assume that the walking is done
700 * asynchronously enough to avoid major problems (-;
702 about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
703 to = send_context->toNeighbor;
705 if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
707 (about->hidden == GNUNET_NO) &&
710 (0 != memcmp (&about->identity,
711 &to->identity, sizeof (struct GNUNET_PeerIdentity))))
714 encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
715 encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "%s: Sending info about peer %s to directly connected peer %s\n",
718 GNUNET_i2s(&my_identity),
719 encPeerAbout, encPeerTo);
720 GNUNET_free(encPeerAbout);
721 GNUNET_free(encPeerTo);
723 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
724 pending_message->msg = GNUNET_malloc(sizeof(p2p_dv_MESSAGE_NeighborInfo));
725 message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
726 message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
727 message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
728 message->cost = htonl (about->cost);
729 message->neighbor_id = htonl (about->our_id);
730 memcpy (&message->neighbor,
731 &about->identity, sizeof (struct GNUNET_PeerIdentity));
733 pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, default_dv_delay, &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, pending_message);
735 if (NULL == pending_message->transmit_handle)
737 GNUNET_free (pending_message->msg);
738 GNUNET_free (pending_message);
741 /*coreAPI->ciphertext_send (&to->identity, &message.header,
742 GNUNET_DV_DHT_GOSSIP_PRIORITY,
743 ctx.send_interval);*/
746 GNUNET_SCHEDULER_add_delayed(sched, send_context->timeout, &neighbor_send_task, send_context);
751 * Core handler for dv gossip messages. These will be used
752 * by us to create a HELLO message for the newly peer containing
753 * which direct peer we can connect through, and what the cost
754 * is. This HELLO will then be scheduled for validation by the
755 * transport service so that it can be used by all others.
758 * @param peer peer which sent the message (immediate sender)
759 * @param message the message
760 * @param latency the latency of the connection we received the message from
761 * @param distance the distance to the immediate peer
763 static int handle_dv_gossip_message (void *cls,
764 const struct GNUNET_PeerIdentity *peer,
765 const struct GNUNET_MessageHeader *message,
766 struct GNUNET_TIME_Relative latency,
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "%s: Receives %s message!\n", "dv", "DV GOSSIP");
779 * Service server's handler for message send requests (which come
780 * bubbling up to us through the DV plugin).
783 * @param client identification of the client
784 * @param message the actual message
786 void send_dv_message (void *cls,
787 struct GNUNET_SERVER_Client * client,
788 const struct GNUNET_MessageHeader * message)
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 "%s: Receives %s message!\n", "dv", "SEND");
794 if (client_handle == NULL)
796 client_handle = client;
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "%s: Setting initial client handle!\n", "dv");
802 else if (client_handle != client)
804 client_handle = client;
805 /* What should we do in this case, assert fail or just log the warning? */
806 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
807 "%s: Setting client handle (was a different client!)!\n", "dv");
810 GNUNET_SERVER_receive_done(client, GNUNET_OK);
815 * List of handlers for the messages understood by this
818 * Hmm... will we need to register some handlers with core and
819 * some handlers with our server here? Because core should be
820 * getting the incoming DV messages (from whichever lower level
821 * transport) and then our server should be getting messages
822 * from the dv_plugin, right?
824 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
825 {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
826 {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
831 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
832 {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
838 * Task run during shutdown.
844 shutdown_task (void *cls,
845 const struct GNUNET_SCHEDULER_TaskContext *tc)
847 GNUNET_CORE_disconnect (coreAPI);
851 * To be called on core init/fail.
853 void core_init (void *cls,
854 struct GNUNET_CORE_Handle * server,
855 const struct GNUNET_PeerIdentity *identity,
856 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
861 GNUNET_SCHEDULER_cancel(sched, cleanup_task);
862 GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
869 memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
875 * Iterator over hash map entries.
878 * @param key current key code
879 * @param value value in the hash map
880 * @return GNUNET_YES if we should continue to
884 static int update_matching_neighbors (void *cls,
885 const GNUNET_HashCode * key,
888 struct NeighborUpdateInfo * update_info = cls;
889 struct DirectNeighbor *direct_neighbor = value;
891 if (update_info->referrer == direct_neighbor) /* Direct neighbor matches, update it's info and return GNUNET_NO */
893 /* same referrer, cost change! */
894 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
895 update_info->neighbor->max_loc, update_info->cost);
896 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
897 update_info->neighbor->min_loc, update_info->cost);
898 update_info->neighbor->last_activity = update_info->now;
899 update_info->neighbor->cost = update_info->cost;
908 * Free a DistantNeighbor node, including removing it
909 * from the referer's list.
912 distant_neighbor_free (struct DistantNeighbor *referee)
914 struct DirectNeighbor *referrer;
916 referrer = referee->referrer;
917 if (referrer != NULL)
919 GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
920 referrer->referee_tail, referee);
922 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
923 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
924 GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
925 &referee->identity.hashPubKey);
926 GNUNET_free (referee);
931 * Handles when a peer is either added due to being newly connected
932 * or having been gossiped about, also called when a cost for a neighbor
933 * needs to be updated.
935 * @param peer identity of the peer whose info is being added/updated
936 * @param referrer_peer_id id to use when sending to 'peer'
937 * @param referrer if this is a gossiped peer, who did we hear it from?
938 * @param cost the cost of communicating with this peer via 'referrer'
941 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
942 unsigned int referrer_peer_id,
943 struct DirectNeighbor *referrer, unsigned int cost)
945 struct DistantNeighbor *neighbor;
946 struct DistantNeighbor *max;
947 struct GNUNET_TIME_Absolute now;
948 struct NeighborUpdateInfo *neighbor_update;
951 now = GNUNET_TIME_absolute_get ();
952 our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
954 neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
956 neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
957 neighbor_update->neighbor = neighbor;
958 neighbor_update->cost = cost;
959 neighbor_update->now = now;
960 neighbor_update->referrer = referrer;
962 /* Either we do not know this peer, or we already do but via a different immediate peer */
963 if ((neighbor == NULL) ||
964 (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
966 &update_matching_neighbors,
967 neighbor_update) != GNUNET_SYSERR))
970 if (cost > ctx.fisheye_depth)
973 GNUNET_free(neighbor_update);
976 if (ctx.max_table_size <=
977 GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
979 /* remove most expensive entry */
980 max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
981 if (cost > max->cost)
983 /* new entry most expensive, don't create */
984 GNUNET_free(neighbor_update);
989 /* only free if this is not a direct connection;
990 we could theoretically have more direct
991 connections than DV entries allowed total! */
992 distant_neighbor_free (max);
996 neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
997 GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
998 referrer->referee_tail, neighbor);
999 neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
1001 neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
1003 neighbor->referrer = referrer;
1004 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1005 neighbor->last_activity = now;
1006 neighbor->cost = cost;
1007 neighbor->referrer_id = referrer_peer_id;
1008 neighbor->our_id = our_id;
1010 (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1012 GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
1014 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1017 GNUNET_free(neighbor_update);
1018 /* Old logic to remove entry and replace, not needed now as we only want to remove when full
1019 * or when the referring peer disconnects from us.
1022 GNUNET_DLL_remove (neighbor->referrer->referee_head,
1023 neighbor->referrer->referee_tail, neighbor);
1024 neighbor->referrer = referrer;
1025 GNUNET_DLL_insert (referrer->referee_head,
1026 referrer->referee_tail, neighbor);
1027 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1028 neighbor->max_loc, cost);
1029 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1030 neighbor->min_loc, cost);
1031 neighbor->referrer_id = referrer_peer_id;
1032 neighbor->last_activity = now;
1033 neighbor->cost = cost;
1039 * Method called whenever a peer connects.
1041 * @param cls closure
1042 * @param peer peer identity this notification is about
1043 * @param latency reported latency of the connection with peer
1044 * @param distance reported distance (DV) to peer
1046 void handle_core_connect (void *cls,
1047 const struct GNUNET_PeerIdentity * peer,
1048 struct GNUNET_TIME_Relative latency,
1051 struct DirectNeighbor *neighbor;
1053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1054 "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
1057 if ((distance == 0) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
1059 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1060 neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
1061 neighbor->send_context->toNeighbor = neighbor;
1062 neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */
1063 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1064 GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
1066 neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1067 addUpdateNeighbor (peer, 0, neighbor, 0);
1068 neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074 "%s: Distance (%d) greater than 0 or already know about peer (%s), not re-adding!\n", "dv", distance, GNUNET_i2s(peer));
1081 * Method called whenever a given peer either connects.
1083 * @param cls closure
1084 * @param peer peer identity this notification is about
1086 void handle_core_disconnect (void *cls,
1087 const struct GNUNET_PeerIdentity * peer)
1089 struct DirectNeighbor *neighbor;
1090 struct DistantNeighbor *referee;
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "%s: Receives core peer disconnect message!\n", "dv");
1098 GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
1099 if (neighbor == NULL)
1103 while (NULL != (referee = neighbor->referee_head))
1104 distant_neighbor_free (referee);
1105 GNUNET_assert (neighbor->referee_tail == NULL);
1106 GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
1107 &peer->hashPubKey, neighbor);
1108 if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
1109 GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
1110 GNUNET_free (neighbor);
1115 * Process dv requests.
1117 * @param cls closure
1118 * @param scheduler scheduler to use
1119 * @param server the initialized server
1120 * @param c configuration to use
1124 struct GNUNET_SCHEDULER_Handle *scheduler,
1125 struct GNUNET_SERVER_Handle *server,
1126 const struct GNUNET_CONFIGURATION_Handle *c)
1128 struct GNUNET_TIME_Relative timeout;
1129 unsigned long long max_hosts;
1130 timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1134 /* FIXME: Read from config, or calculate, or something other than this! */
1136 ctx.max_table_size = 100;
1137 ctx.fisheye_depth = 3;
1139 ctx.neighbor_min_heap =
1140 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1141 ctx.neighbor_max_heap =
1142 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
1144 ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
1145 ctx.extended_neighbors =
1146 GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
1148 client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1149 default_dv_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1150 GNUNET_SERVER_add_handlers (server, plugin_handlers);
1152 GNUNET_CORE_connect (sched,
1155 NULL, /* FIXME: anything we want to pass around? */
1157 NULL, /* Don't care about pre-connects */
1158 &handle_core_connect,
1159 &handle_core_disconnect,
1166 if (coreAPI == NULL)
1168 /* load (server); Huh? */
1170 /* Scheduled the task to clean up when shutdown is called */
1171 cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
1172 GNUNET_TIME_UNIT_FOREVER_REL,
1179 * The main function for the dv service.
1181 * @param argc number of arguments from the command line
1182 * @param argv command line arguments
1183 * @return 0 ok, 1 on error
1186 main (int argc, char *const *argv)
1188 return (GNUNET_OK ==
1189 GNUNET_SERVICE_run (argc,
1192 GNUNET_SERVICE_OPTION_NONE,
1193 &run, NULL)) ? 0 : 1;