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;
398 msize = ntohs(msg->header.size);
399 GNUNET_assert(size >= msize);
402 memcpy(buf, msg, msize);
408 void send_to_plugin(const struct GNUNET_PeerIdentity * sender, const struct GNUNET_MessageHeader *message, size_t message_size, struct DistantNeighbor *distant_neighbor)
410 struct GNUNET_DV_MessageReceived *received_msg;
413 size = sizeof(struct GNUNET_DV_MessageReceived) + sizeof(struct GNUNET_PeerIdentity) + message_size;
414 received_msg = GNUNET_malloc(size);
415 received_msg->header.size = htons(size);
416 received_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE);
417 received_msg->sender_address_len = sizeof(struct GNUNET_PeerIdentity);
418 received_msg->distance = htonl(distant_neighbor->cost);
419 received_msg->msg_len = htons(message_size);
420 /* Set the sender in this message to be the original sender! */
421 memcpy(&received_msg->sender, &distant_neighbor->identity, sizeof(struct GNUNET_PeerIdentity));
422 /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */
423 memcpy(&received_msg[1], sender, sizeof(struct GNUNET_PeerIdentity));
424 /* Copy the actual message after the sender */
425 memcpy(&received_msg[1 + sizeof(struct GNUNET_PeerIdentity)], message, message_size);
427 /* FIXME: Send to the client please */
428 GNUNET_SERVER_notify_transmit_ready (client_handle,
429 size, client_transmit_timeout,
430 &transmit_to_plugin, &received_msg);
436 * Function called to notify a client about the socket
437 * begin ready to queue more data. "buf" will be
438 * NULL and "size" zero if the socket was closed for
439 * writing in the meantime.
442 * @param size number of bytes available in buf
443 * @param buf where the callee should write the message
444 * @return number of bytes written to buf
446 size_t core_transmit_notify (void *cls,
447 size_t size, void *buf)
449 struct PendingMessage *pending_message = cls;
454 /* FIXME: error handling: try again? free pending_message? */
457 ssize = pending_message->msg_size;
458 GNUNET_assert(size >= ssize);
459 memcpy(buf, pending_message->msg, ssize);
460 GNUNET_free(pending_message->msg);
461 GNUNET_free(pending_message);
466 * Send a DV data message via DV.
468 * @param recipient the ultimate recipient of this message
469 * @param the original sender of the message
470 * @param message the packed message
471 * @param importance what priority to send this message with
472 * @param timeout how long to possibly delay sending this message
475 send_message (const struct GNUNET_PeerIdentity * recipient,
476 const struct GNUNET_PeerIdentity * sender,
477 const struct GNUNET_MessageHeader * message,
478 unsigned int importance, struct GNUNET_TIME_Relative timeout)
480 p2p_dv_MESSAGE_Data *toSend;
481 unsigned int msg_size;
483 unsigned int recipient_id;
484 unsigned int sender_id;
485 struct DistantNeighbor *target;
486 struct DistantNeighbor *source;
487 struct PendingMessage *pending_message;
489 msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
491 target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
492 &recipient->hashPubKey);
495 /* target unknown to us, drop! */
496 return GNUNET_SYSERR;
498 recipient_id = target->referrer_id;
500 source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
501 &sender->hashPubKey);
504 if (0 != (memcmp (&my_identity,
505 sender, sizeof (struct GNUNET_PeerIdentity))))
507 /* sender unknown to us, drop! */
508 return GNUNET_SYSERR;
510 sender_id = 0; /* 0 == us */
514 /* find out the number that we use when we gossip about
516 sender_id = source->our_id;
520 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
521 pending_message->msg = GNUNET_malloc (msg_size);
522 toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
523 toSend->header.size = htons (msg_size);
524 toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
525 toSend->sender = htonl (sender_id);
526 toSend->recipient = htonl (recipient_id);
527 memcpy (&toSend[1], message, ntohs (message->size));
528 pending_message->msg_size = msg_size;
530 pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, pending_message);
531 if (NULL == pending_message->transmit_handle)
533 GNUNET_free (pending_message->msg);
534 GNUNET_free (pending_message);
535 return GNUNET_SYSERR;
538 /*coreAPI->ciphertext_send (&target->referrer->identity,
539 &toSend->header, importance, maxdelay);*/
545 * Core handler for dv data messages. Whatever this message
546 * contains all we really have to do is rip it out of its
547 * DV layering and give it to our pal the DV plugin to report
551 * @param peer peer which sent the message (immediate sender)
552 * @param message the message
553 * @param latency the latency of the connection we received the message from
554 * @param distance the distance to the immediate peer
556 static int handle_dv_data_message (void *cls,
557 const struct GNUNET_PeerIdentity * peer,
558 const struct GNUNET_MessageHeader * message,
559 struct GNUNET_TIME_Relative latency,
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "%s: Receives %s message!\n", "dv", "DV DATA");
567 const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
568 const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
569 struct DirectNeighbor *dn;
570 struct DistantNeighbor *pos;
571 unsigned int sid; /* Sender id */
572 unsigned int tid; /* Target id */
573 struct GNUNET_PeerIdentity original_sender;
574 struct GNUNET_PeerIdentity destination;
575 struct FindDestinationContext fdc;
578 if ((ntohs (incoming->header.size) <
579 sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
580 || (ntohs (incoming->header.size) !=
581 (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
583 return GNUNET_SYSERR;
586 dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
592 sid = ntohl (incoming->sender);
593 pos = dn->referee_head;
594 while ((NULL != pos) && (pos->referrer_id != sid))
601 original_sender = pos->identity;
602 tid = ntohl (incoming->recipient);
607 /* FIXME: Will we support wrapped messages being these types? Probably not, they should
608 * be encrypted messages that need decrypting and junk like that.
610 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
611 GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
612 if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
613 (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
615 send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
621 /* FIXME: this is the *only* per-request operation we have in DV
622 that is O(n) in relation to the number of connected peers; a
623 hash-table lookup could easily solve this (minor performance
627 GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
628 &find_destination, &fdc);
629 if (fdc.dest == NULL)
633 destination = fdc.dest->identity;
635 if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
637 /* FIXME: create stat: routing loop-discard! */
641 /* At this point we have a message, and we need to forward it on to the
644 /* FIXME: Can't send message on, we have to behave.
645 * We have to tell core we have a message for the next peer, and let
646 * transport do transport selection on how to get this message to 'em */
647 /*ret = send_message (&destination,
649 packed_message, DV_PRIORITY, DV_DELAY);*/
650 ret = send_message(&destination, &original_sender, packed_message, default_dv_priority, default_dv_delay);
652 if (ret != GNUNET_SYSERR)
655 return GNUNET_SYSERR;
660 * Thread which chooses a peer to gossip about and a peer to gossip
661 * to, then constructs the message and sends it out. Will run until
662 * done_module_dv is called.
665 neighbor_send_task (void *cls,
666 const struct GNUNET_SCHEDULER_TaskContext *tc)
668 struct NeighborSendContext *send_context = cls;
670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671 "%s: Entering neighbor_send_task...\n",
672 GNUNET_i2s(&my_identity));
676 struct DistantNeighbor *about;
677 struct DirectNeighbor *to;
679 p2p_dv_MESSAGE_NeighborInfo *message;
680 struct PendingMessage *pending_message;
682 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "%s: Called with reason shutdown, shutting down!\n",
687 GNUNET_i2s(&my_identity));
689 send_context->toNeighbor->send_context = NULL;
690 GNUNET_free(send_context);
695 /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means
696 * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
697 * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
698 * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
699 * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk
700 * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap
701 * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
702 * in the mean time that becomes nasty. For now we'll just assume that the walking is done
703 * asynchronously enough to avoid major problems (-;
705 about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
706 to = send_context->toNeighbor;
708 if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
710 (about->hidden == GNUNET_NO) &&
713 (0 != memcmp (&about->identity,
714 &to->identity, sizeof (struct GNUNET_PeerIdentity))))
717 encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
718 encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "%s: Sending info about peer %s to directly connected peer %s\n",
721 GNUNET_i2s(&my_identity),
722 encPeerAbout, encPeerTo);
723 GNUNET_free(encPeerAbout);
724 GNUNET_free(encPeerTo);
726 pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
727 pending_message->msg = GNUNET_malloc(sizeof(p2p_dv_MESSAGE_NeighborInfo));
728 message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
729 message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
730 message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
731 message->cost = htonl (about->cost);
732 message->neighbor_id = htonl (about->our_id);
733 memcpy (&message->neighbor,
734 &about->identity, sizeof (struct GNUNET_PeerIdentity));
736 pending_message->msg_size = sizeof(p2p_dv_MESSAGE_NeighborInfo);
737 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);
739 if (NULL == pending_message->transmit_handle)
741 GNUNET_free (pending_message->msg);
742 GNUNET_free (pending_message);
745 /*coreAPI->ciphertext_send (&to->identity, &message.header,
746 GNUNET_DV_DHT_GOSSIP_PRIORITY,
747 ctx.send_interval);*/
750 GNUNET_SCHEDULER_add_delayed(sched, send_context->timeout, &neighbor_send_task, send_context);
756 * Service server's handler for message send requests (which come
757 * bubbling up to us through the DV plugin).
760 * @param client identification of the client
761 * @param message the actual message
763 void send_dv_message (void *cls,
764 struct GNUNET_SERVER_Client * client,
765 const struct GNUNET_MessageHeader * message)
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769 "%s: Receives %s message!\n", "dv", "SEND");
771 if (client_handle == NULL)
773 client_handle = client;
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
776 "%s: Setting initial client handle!\n", "dv");
779 else if (client_handle != client)
781 client_handle = client;
782 /* What should we do in this case, assert fail or just log the warning? */
783 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
784 "%s: Setting client handle (was a different client!)!\n", "dv");
787 GNUNET_SERVER_receive_done(client, GNUNET_OK);
790 static int handle_dv_gossip_message (void *cls,
791 const struct GNUNET_PeerIdentity *peer,
792 const struct GNUNET_MessageHeader *message,
793 struct GNUNET_TIME_Relative latency,
797 * List of handlers for the messages understood by this
800 * Hmm... will we need to register some handlers with core and
801 * some handlers with our server here? Because core should be
802 * getting the incoming DV messages (from whichever lower level
803 * transport) and then our server should be getting messages
804 * from the dv_plugin, right?
806 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
807 {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
808 {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
813 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
814 {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
820 * Task run during shutdown.
826 shutdown_task (void *cls,
827 const struct GNUNET_SCHEDULER_TaskContext *tc)
829 GNUNET_CORE_disconnect (coreAPI);
833 * To be called on core init/fail.
835 void core_init (void *cls,
836 struct GNUNET_CORE_Handle * server,
837 const struct GNUNET_PeerIdentity *identity,
838 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
843 GNUNET_SCHEDULER_cancel(sched, cleanup_task);
844 GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
851 memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
857 * Iterator over hash map entries.
860 * @param key current key code
861 * @param value value in the hash map
862 * @return GNUNET_YES if we should continue to
866 static int update_matching_neighbors (void *cls,
867 const GNUNET_HashCode * key,
870 struct NeighborUpdateInfo * update_info = cls;
871 struct DistantNeighbor *distant_neighbor = value;
873 if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */
875 /* same referrer, cost change! */
876 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
877 update_info->neighbor->max_loc, update_info->cost);
878 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
879 update_info->neighbor->min_loc, update_info->cost);
880 update_info->neighbor->last_activity = update_info->now;
881 update_info->neighbor->cost = update_info->cost;
890 * Free a DistantNeighbor node, including removing it
891 * from the referer's list.
894 distant_neighbor_free (struct DistantNeighbor *referee)
896 struct DirectNeighbor *referrer;
898 referrer = referee->referrer;
899 if (referrer != NULL)
901 GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
902 referrer->referee_tail, referee);
904 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
905 GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
906 GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
907 &referee->identity.hashPubKey);
908 GNUNET_free (referee);
913 * Handles when a peer is either added due to being newly connected
914 * or having been gossiped about, also called when the cost for a neighbor
915 * needs to be updated.
917 * @param peer identity of the peer whose info is being added/updated
918 * @param referrer_peer_id id to use when sending to 'peer'
919 * @param referrer if this is a gossiped peer, who did we hear it from?
920 * @param cost the cost of communicating with this peer via 'referrer'
923 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
924 unsigned int referrer_peer_id,
925 struct DirectNeighbor *referrer, unsigned int cost)
927 struct DistantNeighbor *neighbor;
928 struct DistantNeighbor *max;
929 struct GNUNET_TIME_Absolute now;
930 struct NeighborUpdateInfo *neighbor_update;
933 now = GNUNET_TIME_absolute_get ();
934 our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
936 neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
938 neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
939 neighbor_update->neighbor = neighbor;
940 neighbor_update->cost = cost;
941 neighbor_update->now = now;
942 neighbor_update->referrer = referrer;
944 /* Either we do not know this peer, or we already do but via a different immediate peer */
945 if ((neighbor == NULL) ||
946 (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
948 &update_matching_neighbors,
949 neighbor_update) != GNUNET_SYSERR))
952 if (cost > ctx.fisheye_depth)
955 GNUNET_free(neighbor_update);
958 if (ctx.max_table_size <=
959 GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
961 /* remove most expensive entry */
962 max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
963 if (cost > max->cost)
965 /* new entry most expensive, don't create */
966 GNUNET_free(neighbor_update);
971 /* only free if this is not a direct connection;
972 we could theoretically have more direct
973 connections than DV entries allowed total! */
974 distant_neighbor_free (max);
978 neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
979 GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
980 referrer->referee_tail, neighbor);
981 neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
983 neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
985 neighbor->referrer = referrer;
986 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
987 neighbor->last_activity = now;
988 neighbor->cost = cost;
989 neighbor->referrer_id = referrer_peer_id;
990 neighbor->our_id = our_id;
992 (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
994 GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
996 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 "%s: Already know peer %s distance %d, referrer id %d!\n", "dv", GNUNET_i2s(peer), cost, referrer_peer_id);
1006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1007 "%s: Size of extended_neighbors is %d\n", "dv", GNUNET_CONTAINER_multihashmap_size(ctx.extended_neighbors));
1009 GNUNET_free(neighbor_update);
1010 /* Old logic to remove entry and replace, not needed now as we only want to remove when full
1011 * or when the referring peer disconnects from us.
1014 GNUNET_DLL_remove (neighbor->referrer->referee_head,
1015 neighbor->referrer->referee_tail, neighbor);
1016 neighbor->referrer = referrer;
1017 GNUNET_DLL_insert (referrer->referee_head,
1018 referrer->referee_tail, neighbor);
1019 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1020 neighbor->max_loc, cost);
1021 GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1022 neighbor->min_loc, cost);
1023 neighbor->referrer_id = referrer_peer_id;
1024 neighbor->last_activity = now;
1025 neighbor->cost = cost;
1030 * Core handler for dv gossip messages. These will be used
1031 * by us to create a HELLO message for the newly peer containing
1032 * which direct peer we can connect through, and what the cost
1033 * is. This HELLO will then be scheduled for validation by the
1034 * transport service so that it can be used by all others.
1036 * @param cls closure
1037 * @param peer peer which sent the message (immediate sender)
1038 * @param message the message
1039 * @param latency the latency of the connection we received the message from
1040 * @param distance the distance to the immediate peer
1042 static int handle_dv_gossip_message (void *cls,
1043 const struct GNUNET_PeerIdentity *peer,
1044 const struct GNUNET_MessageHeader *message,
1045 struct GNUNET_TIME_Relative latency,
1049 char * encPeerAbout;
1052 struct DirectNeighbor *referrer;
1053 p2p_dv_MESSAGE_NeighborInfo *enc_message = (p2p_dv_MESSAGE_NeighborInfo *)message;
1055 encPeerAbout = GNUNET_strdup(GNUNET_i2s(&enc_message->neighbor));
1056 encPeerFrom = GNUNET_strdup(GNUNET_i2s(peer));
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1058 "%s: Receives %s message from peer %s about peer %s!\n", "dv", "DV GOSSIP", encPeerFrom, encPeerAbout);
1059 GNUNET_free(encPeerAbout);
1060 GNUNET_free(encPeerFrom);
1063 if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_NeighborInfo))
1065 return GNUNET_SYSERR; /* invalid message */
1068 referrer = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
1070 if (referrer == NULL)
1073 addUpdateNeighbor (&enc_message->neighbor,
1074 ntohl (enc_message->neighbor_id),
1075 referrer, ntohl (enc_message->cost) + 1);
1081 * Method called whenever a peer connects.
1083 * @param cls closure
1084 * @param peer peer identity this notification is about
1085 * @param latency reported latency of the connection with peer
1086 * @param distance reported distance (DV) to peer
1088 void handle_core_connect (void *cls,
1089 const struct GNUNET_PeerIdentity * peer,
1090 struct GNUNET_TIME_Relative latency,
1093 struct DirectNeighbor *neighbor;
1095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1096 "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
1099 if ((distance == 0) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
1101 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1102 neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
1103 neighbor->send_context->toNeighbor = neighbor;
1104 neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */
1105 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1106 GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
1108 neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1109 addUpdateNeighbor (peer, 0, neighbor, 0);
1110 neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
1115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1116 "%s: Distance (%d) greater than 0 or already know about peer (%s), not re-adding!\n", "dv", distance, GNUNET_i2s(peer));
1123 * Method called whenever a given peer either connects.
1125 * @param cls closure
1126 * @param peer peer identity this notification is about
1128 void handle_core_disconnect (void *cls,
1129 const struct GNUNET_PeerIdentity * peer)
1131 struct DirectNeighbor *neighbor;
1132 struct DistantNeighbor *referee;
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "%s: Receives core peer disconnect message!\n", "dv");
1140 GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
1141 if (neighbor == NULL)
1145 while (NULL != (referee = neighbor->referee_head))
1146 distant_neighbor_free (referee);
1147 GNUNET_assert (neighbor->referee_tail == NULL);
1148 GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
1149 &peer->hashPubKey, neighbor);
1150 if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
1151 GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
1152 GNUNET_free (neighbor);
1157 * Process dv requests.
1159 * @param cls closure
1160 * @param scheduler scheduler to use
1161 * @param server the initialized server
1162 * @param c configuration to use
1166 struct GNUNET_SCHEDULER_Handle *scheduler,
1167 struct GNUNET_SERVER_Handle *server,
1168 const struct GNUNET_CONFIGURATION_Handle *c)
1170 struct GNUNET_TIME_Relative timeout;
1171 unsigned long long max_hosts;
1172 timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1176 /* FIXME: Read from config, or calculate, or something other than this! */
1178 ctx.max_table_size = 100;
1179 ctx.fisheye_depth = 3;
1181 ctx.neighbor_min_heap =
1182 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1183 ctx.neighbor_max_heap =
1184 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
1186 ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
1187 ctx.extended_neighbors =
1188 GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
1190 client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1191 default_dv_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1192 GNUNET_SERVER_add_handlers (server, plugin_handlers);
1194 GNUNET_CORE_connect (sched,
1197 NULL, /* FIXME: anything we want to pass around? */
1199 NULL, /* Don't care about pre-connects */
1200 &handle_core_connect,
1201 &handle_core_disconnect,
1208 if (coreAPI == NULL)
1210 /* load (server); Huh? */
1212 /* Scheduled the task to clean up when shutdown is called */
1213 cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
1214 GNUNET_TIME_UNIT_FOREVER_REL,
1221 * The main function for the dv service.
1223 * @param argc number of arguments from the command line
1224 * @param argv command line arguments
1225 * @return 0 ok, 1 on error
1228 main (int argc, char *const *argv)
1230 return (GNUNET_OK ==
1231 GNUNET_SERVICE_run (argc,
1234 GNUNET_SERVICE_OPTION_NONE,
1235 &run, NULL)) ? 0 : 1;