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 struct GNUNET_PeerIdentity my_identity;
57 * The configuration for this service.
59 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;
447 char *send_buf = buf;
448 if ((buf == NULL) || (size < pending_message->msg_size))
453 memcpy(send_buf, pending_message->msg, pending_message->msg_size);
455 GNUNET_free(pending_message->msg);
456 GNUNET_free(pending_message);
462 * Send a DV data message via DV.
464 * @param recipient the ultimate recipient of this message
465 * @param the original sender of the message
466 * @param message the packed message
467 * @param importance what priority to send this message with
468 * @param timeout how long to possibly delay sending this message
471 send_message (const struct GNUNET_PeerIdentity * recipient,
472 const struct GNUNET_PeerIdentity * sender,
473 const struct GNUNET_MessageHeader * message,
474 unsigned int importance, struct GNUNET_TIME_Relative timeout)
476 p2p_dv_MESSAGE_Data *toSend;
477 unsigned int msg_size;
479 unsigned int recipient_id;
480 unsigned int sender_id;
481 struct DistantNeighbor *target;
482 struct DistantNeighbor *source;
483 struct PendingMessage *pending_message;
485 msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
487 target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
488 &recipient->hashPubKey);
491 /* target unknown to us, drop! */
492 return GNUNET_SYSERR;
494 recipient_id = target->referrer_id;
496 source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
497 &sender->hashPubKey);
500 if (0 != (memcmp (&my_identity,
501 sender, sizeof (struct GNUNET_PeerIdentity))))
503 /* sender unknown to us, drop! */
504 return GNUNET_SYSERR;
506 sender_id = 0; /* 0 == us */
510 /* find out the number that we use when we gossip about
512 sender_id = source->our_id;
516 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
517 pending_message->msg = GNUNET_malloc (msg_size);
518 toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
519 toSend->header.size = htons (msg_size);
520 toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
521 toSend->sender = htonl (sender_id);
522 toSend->recipient = htonl (recipient_id);
523 memcpy (&toSend[1], message, ntohs (message->size));
524 pending_message->msg_size = msg_size;
526 pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, pending_message);
527 if (NULL == pending_message->transmit_handle)
529 GNUNET_free (pending_message->msg);
530 GNUNET_free (pending_message);
531 return GNUNET_SYSERR;
534 /*coreAPI->ciphertext_send (&target->referrer->identity,
535 &toSend->header, importance, maxdelay);*/
541 * Core handler for dv data messages. Whatever this message
542 * contains all we really have to do is rip it out of its
543 * DV layering and give it to our pal the DV plugin to report
547 * @param peer peer which sent the message (immediate sender)
548 * @param message the message
549 * @param latency the latency of the connection we received the message from
550 * @param distance the distance to the immediate peer
552 static int handle_dv_data_message (void *cls,
553 const struct GNUNET_PeerIdentity * peer,
554 const struct GNUNET_MessageHeader * message,
555 struct GNUNET_TIME_Relative latency,
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "%s: Receives %s message!\n", "dv", "DV DATA");
563 const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
564 const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
565 struct DirectNeighbor *dn;
566 struct DistantNeighbor *pos;
567 unsigned int sid; /* Sender id */
568 unsigned int tid; /* Target id */
569 struct GNUNET_PeerIdentity original_sender;
570 struct GNUNET_PeerIdentity destination;
571 struct FindDestinationContext fdc;
574 if ((ntohs (incoming->header.size) <
575 sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
576 || (ntohs (incoming->header.size) !=
577 (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
579 return GNUNET_SYSERR;
582 dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
588 sid = ntohl (incoming->sender);
589 pos = dn->referee_head;
590 while ((NULL != pos) && (pos->referrer_id != sid))
597 original_sender = pos->identity;
598 tid = ntohl (incoming->recipient);
603 /* FIXME: Will we support wrapped messages being these types? Probably not, they should
604 * be encrypted messages that need decrypting and junk like that.
606 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
607 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
608 if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
609 (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
611 send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
617 /* FIXME: this is the *only* per-request operation we have in DV
618 that is O(n) in relation to the number of connected peers; a
619 hash-table lookup could easily solve this (minor performance
623 GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
624 &find_destination, &fdc);
625 if (fdc.dest == NULL)
629 destination = fdc.dest->identity;
631 if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
633 /* FIXME: create stat: routing loop-discard! */
637 /* At this point we have a message, and we need to forward it on to the
640 /* FIXME: Can't send message on, we have to behave.
641 * We have to tell core we have a message for the next peer, and let
642 * transport do transport selection on how to get this message to 'em */
643 /*ret = send_message (&destination,
645 packed_message, DV_PRIORITY, DV_DELAY);*/
646 ret = send_message(&destination, &original_sender, packed_message, default_dv_priority, default_dv_delay);
648 if (ret != GNUNET_SYSERR)
651 return GNUNET_SYSERR;
656 * Thread which chooses a peer to gossip about and a peer to gossip
657 * to, then constructs the message and sends it out. Will run until
658 * done_module_dv is called.
661 neighbor_send_task (void *cls,
662 const struct GNUNET_SCHEDULER_TaskContext *tc)
664 struct NeighborSendContext *send_context = cls;
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667 "%s: Entering neighbor_send_task...\n",
668 GNUNET_i2s(&my_identity));
672 struct DistantNeighbor *about;
673 struct DirectNeighbor *to;
675 p2p_dv_MESSAGE_NeighborInfo *message;
676 struct PendingMessage *pending_message;
678 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682 "%s: Called with reason shutdown, shutting down!\n",
683 GNUNET_i2s(&my_identity));
685 send_context->toNeighbor->send_context = NULL;
686 GNUNET_free(send_context);
691 /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means
692 * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
693 * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
694 * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
695 * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk
696 * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap
697 * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
698 * in the mean time that becomes nasty. For now we'll just assume that the walking is done
699 * asynchronously enough to avoid major problems (-;
701 about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
702 to = send_context->toNeighbor;
704 if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
706 (about->hidden == GNUNET_NO) &&
709 (0 != memcmp (&about->identity,
710 &to->identity, sizeof (struct GNUNET_PeerIdentity))))
713 encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
714 encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "%s: Sending info about peer %s to directly connected peer %s\n",
717 GNUNET_i2s(&my_identity),
718 encPeerAbout, encPeerTo);
720 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
721 pending_message->msg = GNUNET_malloc(sizeof(p2p_dv_MESSAGE_NeighborInfo));
722 message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
723 message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
724 message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
725 message->cost = htonl (about->cost);
726 message->neighbor_id = htonl (about->our_id);
727 memcpy (&message->neighbor,
728 &about->identity, sizeof (struct GNUNET_PeerIdentity));
730 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);
732 if (NULL == pending_message->transmit_handle)
734 GNUNET_free (pending_message->msg);
735 GNUNET_free (pending_message);
738 /*coreAPI->ciphertext_send (&to->identity, &message.header,
739 GNUNET_DV_DHT_GOSSIP_PRIORITY,
740 ctx.send_interval);*/
743 GNUNET_SCHEDULER_add_delayed(sched, send_context->timeout, &neighbor_send_task, send_context);
748 * Core handler for dv gossip messages. These will be used
749 * by us to create a HELLO message for the newly peer containing
750 * which direct peer we can connect through, and what the cost
751 * is. This HELLO will then be scheduled for validation by the
752 * transport service so that it can be used by all others.
755 * @param peer peer which sent the message (immediate sender)
756 * @param message the message
757 * @param latency the latency of the connection we received the message from
758 * @param distance the distance to the immediate peer
760 static int handle_dv_gossip_message (void *cls,
761 const struct GNUNET_PeerIdentity *peer,
762 const struct GNUNET_MessageHeader *message,
763 struct GNUNET_TIME_Relative latency,
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "%s: Receives %s message!\n", "dv", "DV GOSSIP");
776 * Service server's handler for message send requests (which come
777 * bubbling up to us through the DV plugin).
780 * @param client identification of the client
781 * @param message the actual message
783 void send_dv_message (void *cls,
784 struct GNUNET_SERVER_Client * client,
785 const struct GNUNET_MessageHeader * message)
788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789 "%s: Receives %s message!\n", "dv", "SEND");
791 if (client_handle == NULL)
793 client_handle = client;
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "%s: Setting initial client handle!\n", "dv");
799 else if (client_handle != client)
801 client_handle = client;
802 /* What should we do in this case, assert fail or just log the warning? */
803 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
804 "%s: Setting client handle (was a different client!)!\n", "dv");
807 GNUNET_SERVER_receive_done(client, GNUNET_OK);
812 * List of handlers for the messages understood by this
815 * Hmm... will we need to register some handlers with core and
816 * some handlers with our server here? Because core should be
817 * getting the incoming DV messages (from whichever lower level
818 * transport) and then our server should be getting messages
819 * from the dv_plugin, right?
821 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
822 {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
823 {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
828 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
829 {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
835 * Task run during shutdown.
841 shutdown_task (void *cls,
842 const struct GNUNET_SCHEDULER_TaskContext *tc)
845 GNUNET_CORE_disconnect (coreAPI);
849 * To be called on core init/fail.
851 void core_init (void *cls,
852 struct GNUNET_CORE_Handle * server,
853 const struct GNUNET_PeerIdentity *identity,
854 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
859 GNUNET_SCHEDULER_cancel(sched, cleanup_task);
860 GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865 "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
867 memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
873 * Iterator over hash map entries.
876 * @param key current key code
877 * @param value value in the hash map
878 * @return GNUNET_YES if we should continue to
882 static int update_matching_neighbors (void *cls,
883 const GNUNET_HashCode * key,
886 struct NeighborUpdateInfo * update_info = cls;
887 struct DirectNeighbor *direct_neighbor = value;
889 if (update_info->referrer == direct_neighbor) /* Direct neighbor matches, update it's info and return GNUNET_NO */
891 /* same referrer, cost change! */
892 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
893 update_info->neighbor->max_loc, update_info->cost);
894 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
895 update_info->neighbor->min_loc, update_info->cost);
896 update_info->neighbor->last_activity = update_info->now;
897 update_info->neighbor->cost = update_info->cost;
906 * Free a DistantNeighbor node, including removing it
907 * from the referer's list.
910 distant_neighbor_free (struct DistantNeighbor *referee)
912 struct DirectNeighbor *referrer;
914 referrer = referee->referrer;
915 if (referrer != NULL)
917 GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
918 referrer->referee_tail, referee);
920 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
921 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
922 GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
923 &referee->identity.hashPubKey);
924 GNUNET_free (referee);
929 * Handles when a peer is either added due to being newly connected
930 * or having been gossiped about, also called when a cost for a neighbor
931 * needs to be updated.
933 * @param peer identity of the peer whose info is being added/updated
934 * @param referrer_peer_id id to use when sending to 'peer'
935 * @param referrer if this is a gossiped peer, who did we hear it from?
936 * @param cost the cost of communicating with this peer via 'referrer'
939 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
940 unsigned int referrer_peer_id,
941 struct DirectNeighbor *referrer, unsigned int cost)
943 struct DistantNeighbor *neighbor;
944 struct DistantNeighbor *max;
945 struct GNUNET_TIME_Absolute now;
946 struct NeighborUpdateInfo *neighbor_update;
949 now = GNUNET_TIME_absolute_get ();
950 our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
952 neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
954 neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
955 neighbor_update->neighbor = neighbor;
956 neighbor_update->cost = cost;
957 neighbor_update->now = now;
958 neighbor_update->referrer = referrer;
960 /* Either we do not know this peer, or we already do but via a different immediate peer */
961 if ((neighbor == NULL) ||
962 (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
964 &update_matching_neighbors,
965 neighbor_update) != GNUNET_SYSERR))
968 if (cost > ctx.fisheye_depth)
973 if (ctx.max_table_size <=
974 GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
976 /* remove most expensive entry */
977 max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
978 if (cost > max->cost)
980 /* new entry most expensive, don't create */
985 /* only free if this is not a direct connection;
986 we could theoretically have more direct
987 connections than DV entries allowed total! */
988 distant_neighbor_free (max);
992 neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
993 GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
994 referrer->referee_tail, neighbor);
995 neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
997 neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
999 neighbor->referrer = referrer;
1000 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1001 neighbor->last_activity = now;
1002 neighbor->cost = cost;
1003 neighbor->referrer_id = referrer_peer_id;
1004 neighbor->our_id = our_id;
1006 (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1008 GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
1010 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1015 /* Old logic to remove entry and replace, not needed now as we only want to remove when full
1016 * or when the referring peer disconnects from us.
1019 GNUNET_DLL_remove (neighbor->referrer->referee_head,
1020 neighbor->referrer->referee_tail, neighbor);
1021 neighbor->referrer = referrer;
1022 GNUNET_DLL_insert (referrer->referee_head,
1023 referrer->referee_tail, neighbor);
1024 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1025 neighbor->max_loc, cost);
1026 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1027 neighbor->min_loc, cost);
1028 neighbor->referrer_id = referrer_peer_id;
1029 neighbor->last_activity = now;
1030 neighbor->cost = cost;
1036 * Method called whenever a peer connects.
1038 * @param cls closure
1039 * @param peer peer identity this notification is about
1040 * @param latency reported latency of the connection with peer
1041 * @param distance reported distance (DV) to peer
1043 void handle_core_connect (void *cls,
1044 const struct GNUNET_PeerIdentity * peer,
1045 struct GNUNET_TIME_Relative latency,
1048 struct DirectNeighbor *neighbor;
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
1054 if ((distance == 0) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
1056 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1057 neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
1058 neighbor->send_context->toNeighbor = neighbor;
1059 neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */
1060 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1061 GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
1063 neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1064 addUpdateNeighbor (peer, 0, neighbor, 0);
1065 neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071 "%s: Distance (%d) greater than 0 or already know about peer (%s), not re-adding!\n", "dv", distance, GNUNET_i2s(peer));
1078 * Method called whenever a given peer either connects.
1080 * @param cls closure
1081 * @param peer peer identity this notification is about
1083 void handle_core_disconnect (void *cls,
1084 const struct GNUNET_PeerIdentity * peer)
1086 struct DirectNeighbor *neighbor;
1087 struct DistantNeighbor *referee;
1090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1091 "%s: Receives core peer disconnect message!\n", "dv");
1095 GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
1096 if (neighbor == NULL)
1100 while (NULL != (referee = neighbor->referee_head))
1101 distant_neighbor_free (referee);
1102 GNUNET_assert (neighbor->referee_tail == NULL);
1103 GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
1104 &peer->hashPubKey, neighbor);
1105 if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
1106 GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
1107 GNUNET_free (neighbor);
1112 * Process dv requests.
1114 * @param cls closure
1115 * @param scheduler scheduler to use
1116 * @param server the initialized server
1117 * @param c configuration to use
1121 struct GNUNET_SCHEDULER_Handle *scheduler,
1122 struct GNUNET_SERVER_Handle *server,
1123 const struct GNUNET_CONFIGURATION_Handle *c)
1125 struct GNUNET_TIME_Relative timeout;
1126 unsigned long long max_hosts;
1127 timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1131 /* FIXME: Read from config, or calculate, or something other than this! */
1133 ctx.max_table_size = 100;
1134 ctx.fisheye_depth = 3;
1136 ctx.neighbor_min_heap =
1137 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1138 ctx.neighbor_max_heap =
1139 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
1141 ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
1142 ctx.extended_neighbors =
1143 GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
1145 client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1146 default_dv_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1147 GNUNET_SERVER_add_handlers (server, plugin_handlers);
1149 GNUNET_CORE_connect (sched,
1152 NULL, /* FIXME: anything we want to pass around? */
1154 NULL, /* Don't care about pre-connects */
1155 &handle_core_connect,
1156 &handle_core_disconnect,
1163 if (coreAPI == NULL)
1165 /* load (server); Huh? */
1167 /* Scheduled the task to clean up when shutdown is called */
1168 cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
1169 GNUNET_TIME_UNIT_FOREVER_REL,
1176 * The main function for the dv service.
1178 * @param argc number of arguments from the command line
1179 * @param argv command line arguments
1180 * @return 0 ok, 1 on error
1183 main (int argc, char *const *argv)
1185 return (GNUNET_OK ==
1186 GNUNET_SERVICE_run (argc,
1189 GNUNET_SERVICE_OPTION_NONE,
1190 &run, NULL)) ? 0 : 1;