2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
17 * @file cadet/gnunet-service-cadet_peer.c
18 * @brief Information we track per peer.
19 * @author Bartlomiej Polot
20 * @author Christian Grothoff
23 * - optimize stopping/restarting DHT search to situations
24 * where we actually need it (i.e. not if we have a direct connection,
25 * or if we already have plenty of good short ones, or maybe even
26 * to take a break if we have some connections and have searched a lot (?))
29 #include "gnunet_util_lib.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_ats_service.h"
34 #include "gnunet_core_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "cadet_protocol.h"
37 #include "gnunet-service-cadet_connection.h"
38 #include "gnunet-service-cadet_dht.h"
39 #include "gnunet-service-cadet_peer.h"
40 #include "gnunet-service-cadet_paths.h"
41 #include "gnunet-service-cadet_tunnels.h"
44 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
48 * How long do we wait until tearing down an idle peer?
50 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
53 * How long do we keep paths around if we no longer care about the peer?
55 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
58 * Queue size when we start dropping OOO messages.
60 #define MAX_OOO_QUEUE_SIZE 100
64 * Data structure used to track whom we have to notify about changes
65 * to our message queue.
67 struct GCP_MessageQueueManager
73 struct GCP_MessageQueueManager *next;
78 struct GCP_MessageQueueManager *prev;
81 * Function to call with updated message queue object.
83 GCP_MessageQueueNotificationCallback cb;
91 * The peer this is for.
96 * Envelope this manager would like to transmit once it is its turn.
98 struct GNUNET_MQ_Envelope *env;
104 * Struct containing all information regarding a given peer
111 struct GNUNET_PeerIdentity pid;
114 * Last time we heard from this peer (currently not used!)
116 struct GNUNET_TIME_Absolute last_contactXXX;
119 * Array of DLLs of paths traversing the peer, organized by the
120 * offset of the peer on the larger path.
122 struct CadetPeerPathEntry **path_heads;
125 * Array of DLL of paths traversing the peer, organized by the
126 * offset of the peer on the larger path.
128 struct CadetPeerPathEntry **path_tails;
131 * Notifications to call when @e core_mq changes.
133 struct GCP_MessageQueueManager *mqm_head;
136 * Notifications to call when @e core_mq changes.
138 struct GCP_MessageQueueManager *mqm_tail;
141 * Pointer to first "ready" entry in @e mqm_head.
143 struct GCP_MessageQueueManager *mqm_ready_ptr;
146 * MIN-heap of paths owned by this peer (they also end at this
147 * peer). Ordered by desirability.
149 struct GNUNET_CONTAINER_Heap *path_heap;
152 * Handle to stop the DHT search for paths to this peer
154 struct GCD_search_handle *search_h;
157 * Task to clean up @e path_heap asynchronously.
159 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
162 * Task to destroy this entry.
164 struct GNUNET_SCHEDULER_Task *destroy_task;
167 * Tunnel to this peer, if any.
169 struct CadetTunnel *t;
172 * Connections that go through this peer; indexed by tid.
174 struct GNUNET_CONTAINER_MultiShortmap *connections;
177 * Handle for core transmissions.
179 struct GNUNET_MQ_Handle *core_mq;
182 * Hello message of the peer.
184 struct GNUNET_HELLO_Message *hello;
187 * Handle to us offering the HELLO to the transport.
189 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
192 * Handle to our ATS request asking ATS to suggest an address
193 * to TRANSPORT for this peer (to establish a direct link).
195 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
198 * How many messages are in the queue to this peer.
200 unsigned int queue_n;
203 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
205 unsigned int num_paths;
208 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
209 * Used to speed-up @GCP_get_desirability_of_path() calculation.
211 unsigned int off_sum;
214 * Number of message queue managers of this peer that have a message in waiting.
216 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
217 * TODO: could be replaced by another DLL that would then allow us to avoid
218 * the O(n)-scan of the DLL for ready entries!
220 unsigned int mqm_ready_counter;
223 * Current length of the @e path_heads and @path_tails arrays.
224 * The arrays should be grown as needed.
226 unsigned int path_dll_length;
232 * Get the static string for a peer ID.
235 * @return Static string for it's ID.
238 GCP_2s (const struct CadetPeer *cp)
243 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
254 * Calculate how desirable a path is for @a cp if @a cp
255 * is at offset @a off.
257 * The 'desirability_table.c' program can be used to compute a list of
258 * sample outputs for different scenarios. Basically, we score paths
259 * lower if there are many alternatives, and higher if they are
260 * shorter than average, and very high if they are much shorter than
261 * average and without many alternatives.
263 * @param cp a peer reachable via a path
264 * @param off offset of @a cp in the path
265 * @return score how useful a path is to reach @a cp,
266 * positive scores mean path is more desirable
269 GCP_get_desirability_of_path (struct CadetPeer *cp,
272 unsigned int num_alts = cp->num_paths;
273 unsigned int off_sum;
278 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
279 GNUNET_assert (0 != cp->path_dll_length);
281 /* We maintain 'off_sum' in 'peer' and thereby
282 avoid the SLOW recalculation each time. Kept here
283 just to document what is going on. */
286 for (unsigned int j=0;j<cp->path_dll_length;j++)
287 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
291 GNUNET_assert (off_sum == cp->off_sum);
293 off_sum = cp->off_sum;
295 avg_sum = off_sum * 1.0 / cp->path_dll_length;
296 path_delta = off - avg_sum;
297 /* path_delta positiv: path off of peer above average (bad path for peer),
298 path_delta negativ: path off of peer below average (good path for peer) */
299 if (path_delta <= - 1.0)
300 weight_alts = - num_alts / path_delta; /* discount alternative paths */
301 else if (path_delta >= 1.0)
302 weight_alts = num_alts * path_delta; /* overcount alternative paths */
304 weight_alts = num_alts; /* count alternative paths normally */
307 /* off+1: long paths are generally harder to find and thus count
308 a bit more as they get longer. However, above-average paths
309 still need to count less, hence the squaring of that factor. */
310 return (off + 1.0) / (weight_alts * weight_alts);
315 * This peer is no longer be needed, clean it up now.
317 * @param cls peer to clean up
320 destroy_peer (void *cls)
322 struct CadetPeer *cp = cls;
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Destroying state about peer %s\n",
327 cp->destroy_task = NULL;
328 GNUNET_assert (NULL == cp->t);
329 GNUNET_assert (NULL == cp->core_mq);
330 GNUNET_assert (0 == cp->num_paths);
331 for (unsigned int i=0;i<cp->path_dll_length;i++)
332 GNUNET_assert (NULL == cp->path_heads[i]);
333 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
334 GNUNET_assert (GNUNET_YES ==
335 GNUNET_CONTAINER_multipeermap_remove (peers,
338 GNUNET_free_non_null (cp->path_heads);
339 GNUNET_free_non_null (cp->path_tails);
340 cp->path_dll_length = 0;
341 if (NULL != cp->search_h)
343 GCD_search_stop (cp->search_h);
346 /* FIXME: clean up search_delayedXXX! */
348 if (NULL != cp->hello_offer)
350 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
351 cp->hello_offer = NULL;
353 if (NULL != cp->connectivity_suggestion)
355 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
356 cp->connectivity_suggestion = NULL;
358 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
359 if (NULL != cp->path_heap)
361 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
362 cp->path_heap = NULL;
364 if (NULL != cp->heap_cleanup_task)
366 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
367 cp->heap_cleanup_task = NULL;
369 GNUNET_free_non_null (cp->hello);
370 /* Peer should not be freed if paths exist; if there are no paths,
371 there ought to be no connections, and without connections, no
372 notifications. Thus we can assert that mqm_head is empty at this
374 GNUNET_assert (NULL == cp->mqm_head);
375 GNUNET_assert (NULL == cp->mqm_ready_ptr);
381 * This peer is now on more "active" duty, activate processes related to it.
383 * @param cp the more-active peer
386 consider_peer_activate (struct CadetPeer *cp)
390 LOG (GNUNET_ERROR_TYPE_DEBUG,
391 "Updating peer %s activation state (%u connections)%s%s\n",
393 GNUNET_CONTAINER_multishortmap_size (cp->connections),
394 (NULL == cp->t) ? "" : " with tunnel",
395 (NULL == cp->core_mq) ? "" : " with CORE link");
396 if (NULL != cp->destroy_task)
398 /* It's active, do not destory! */
399 GNUNET_SCHEDULER_cancel (cp->destroy_task);
400 cp->destroy_task = NULL;
402 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
405 /* We're just on a path or directly connected; don't bother too much */
406 if (NULL != cp->connectivity_suggestion)
408 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
409 cp->connectivity_suggestion = NULL;
411 if (NULL != cp->search_h)
413 GCD_search_stop (cp->search_h);
418 if (NULL == cp->core_mq)
420 /* Lacks direct connection, try to create one by querying the DHT */
421 if ( (NULL == cp->search_h) &&
422 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
424 = GCD_search (&cp->pid);
428 /* Have direct connection, stop DHT search if active */
429 if (NULL != cp->search_h)
431 GCD_search_stop (cp->search_h);
436 /* If we have a tunnel, our urge for connections is much bigger */
437 strength = (NULL != cp->t) ? 32 : 1;
438 if (NULL != cp->connectivity_suggestion)
439 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
440 cp->connectivity_suggestion
441 = GNUNET_ATS_connectivity_suggest (ats_ch,
448 * This peer may no longer be needed, consider cleaning it up.
450 * @param cp peer to clean up
453 consider_peer_destroy (struct CadetPeer *cp);
457 * We really no longere care about a peer, stop hogging memory with paths to it.
458 * Afterwards, see if there is more to be cleaned up about this peer.
460 * @param cls a `struct CadetPeer`.
463 drop_paths (void *cls)
465 struct CadetPeer *cp = cls;
466 struct CadetPeerPath *path;
468 cp->destroy_task = NULL;
469 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
471 consider_peer_destroy (cp);
476 * This peer may no longer be needed, consider cleaning it up.
478 * @param cp peer to clean up
481 consider_peer_destroy (struct CadetPeer *cp)
483 struct GNUNET_TIME_Relative exp;
485 if (NULL != cp->destroy_task)
487 GNUNET_SCHEDULER_cancel (cp->destroy_task);
488 cp->destroy_task = NULL;
491 return; /* still relevant! */
492 if (NULL != cp->core_mq)
493 return; /* still relevant! */
494 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
495 return; /* still relevant! */
496 if ( (NULL != cp->path_heap) &&
497 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
499 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
504 if (0 != cp->num_paths)
505 return; /* still relevant! */
506 if (NULL != cp->hello)
508 /* relevant only until HELLO expires */
509 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
510 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
515 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
522 * Set the message queue to @a mq for peer @a cp and notify watchers.
524 * @param cp peer to modify
525 * @param mq message queue to set (can be NULL)
528 GCP_set_mq (struct CadetPeer *cp,
529 struct GNUNET_MQ_Handle *mq)
531 LOG (GNUNET_ERROR_TYPE_DEBUG,
532 "Message queue for peer %s is now %p\n",
536 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
540 /* Save next pointer in case mqm gets freed by the callback */
544 if (NULL != mqm->env)
546 GNUNET_MQ_discard (mqm->env);
548 mqm->cb (mqm->cb_cls,
553 mqm->cb (mqm->cb_cls,
559 GNUNET_assert (NULL == mqm->env);
560 mqm->cb (mqm->cb_cls,
566 consider_peer_activate (cp);
568 consider_peer_destroy (cp);
573 /* have a new, direct path to the target, notify tunnel */
574 struct CadetPeerPath *path;
576 path = GCPP_get_path_from_route (1,
578 GCT_consider_path (cp->t,
586 * Debug function should NEVER return true in production code, useful to
587 * simulate losses for testcases.
589 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
594 if (0 == drop_percent)
596 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
604 * Function called when CORE took one of the messages from
605 * a message queue manager and transmitted it.
607 * @param cls the `struct CadetPeeer` where we made progress
610 mqm_send_done (void *cls);
614 * Transmit current envelope from this @a mqm.
616 * @param mqm mqm to transmit message for now
619 mqm_execute (struct GCP_MessageQueueManager *mqm)
621 struct CadetPeer *cp = mqm->cp;
623 /* Move ready pointer to the next entry that might be ready. */
624 if ( (mqm == cp->mqm_ready_ptr) &&
625 (NULL != mqm->next) )
626 cp->mqm_ready_ptr = mqm->next;
627 /* Move entry to the end of the DLL, to be fair. */
628 if (mqm != cp->mqm_tail)
630 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
633 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
637 cp->mqm_ready_counter--;
638 if (GNUNET_YES == should_I_drop ())
640 LOG (GNUNET_ERROR_TYPE_DEBUG,
641 "DROPPING message to peer %s from MQM %p\n",
644 GNUNET_MQ_discard (mqm->env);
651 const struct GNUNET_MessageHeader *mh;
653 mh = GNUNET_MQ_env_get_msg (mqm->env);
654 switch (ntohs (mh->type))
656 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
658 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
659 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
660 LOG (GNUNET_ERROR_TYPE_DEBUG,
661 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
662 GNUNET_e2s (&msg->ephemeral_key),
664 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
671 LOG (GNUNET_ERROR_TYPE_DEBUG,
672 "Sending to peer %s from MQM %p\n",
675 GNUNET_MQ_send (cp->core_mq,
679 mqm->cb (mqm->cb_cls,
685 * Find the next ready message in the queue (starting
686 * the search from the `cp->mqm_ready_ptr`) and if possible
687 * execute the transmission.
689 * @param cp peer to try to send the next ready message to
692 send_next_ready (struct CadetPeer *cp)
694 struct GCP_MessageQueueManager *mqm;
696 if (0 == cp->mqm_ready_counter)
698 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
700 cp->mqm_ready_ptr = mqm->next;
702 return; /* nothing to do */
708 * Function called when CORE took one of the messages from
709 * a message queue manager and transmitted it.
711 * @param cls the `struct CadetPeeer` where we made progress
714 mqm_send_done (void *cls)
716 struct CadetPeer *cp = cls;
718 LOG (GNUNET_ERROR_TYPE_DEBUG,
719 "Sending to peer %s completed\n",
721 send_next_ready (cp);
726 * Send the message in @a env to @a cp.
728 * @param mqm the message queue manager to use for transmission
729 * @param env envelope with the message to send; must NOT
730 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
733 GCP_send (struct GCP_MessageQueueManager *mqm,
734 struct GNUNET_MQ_Envelope *env)
736 struct CadetPeer *cp = mqm->cp;
738 GNUNET_assert (NULL != env);
739 LOG (GNUNET_ERROR_TYPE_DEBUG,
740 "Queueing message to peer %s in MQM %p\n",
743 GNUNET_assert (NULL != cp->core_mq);
744 GNUNET_assert (NULL == mqm->env);
745 GNUNET_MQ_notify_sent (env,
749 cp->mqm_ready_counter++;
750 if (mqm != cp->mqm_ready_ptr)
751 cp->mqm_ready_ptr = cp->mqm_head;
752 if (1 == cp->mqm_ready_counter)
753 cp->mqm_ready_ptr = mqm;
754 if (0 != GNUNET_MQ_get_length (cp->core_mq))
756 send_next_ready (cp);
761 * Function called to destroy a peer now.
764 * @param pid identity of the peer (unused)
765 * @param value the `struct CadetPeer` to clean up
766 * @return #GNUNET_OK (continue to iterate)
769 destroy_iterator_cb (void *cls,
770 const struct GNUNET_PeerIdentity *pid,
773 struct CadetPeer *cp = value;
775 if (NULL != cp->destroy_task)
777 GNUNET_SCHEDULER_cancel (cp->destroy_task);
778 cp->destroy_task = NULL;
786 * Clean up all entries about all peers.
787 * Must only be called after all tunnels, CORE-connections and
788 * connections are down.
791 GCP_destroy_all_peers ()
793 LOG (GNUNET_ERROR_TYPE_DEBUG,
794 "Destroying all peers now\n");
795 GNUNET_CONTAINER_multipeermap_iterate (peers,
796 &destroy_iterator_cb,
802 * Drop all paths owned by this peer, and do not
803 * allow new ones to be added: We are shutting down.
805 * @param cp peer to drop paths to
808 GCP_drop_owned_paths (struct CadetPeer *cp)
810 struct CadetPeerPath *path;
812 LOG (GNUNET_ERROR_TYPE_DEBUG,
813 "Destroying all paths to %s\n",
815 while (NULL != (path =
816 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
818 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
819 cp->path_heap = NULL;
824 * Add an entry to the DLL of all of the paths that this peer is on.
826 * @param cp peer to modify
827 * @param entry an entry on a path
828 * @param off offset of this peer on the path
831 GCP_path_entry_add (struct CadetPeer *cp,
832 struct CadetPeerPathEntry *entry,
835 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
837 LOG (GNUNET_ERROR_TYPE_DEBUG,
838 "Discovered that peer %s is on path %s at offset %u\n",
840 GCPP_2s (entry->path),
842 if (off >= cp->path_dll_length)
844 unsigned int len = cp->path_dll_length;
846 GNUNET_array_grow (cp->path_heads,
849 GNUNET_array_grow (cp->path_tails,
853 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
859 /* If we have a tunnel to this peer, tell the tunnel that there is a
860 new path available. */
862 GCT_consider_path (cp->t,
866 if ( (NULL != cp->search_h) &&
867 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
869 /* Now I have enough paths, stop search */
870 GCD_search_stop (cp->search_h);
873 if (NULL != cp->destroy_task)
875 /* paths changed, this resets the destroy timeout counter
876 and aborts a destroy task that may no longer be valid
877 to have (as we now have more paths via this peer). */
878 consider_peer_destroy (cp);
884 * Remove an entry from the DLL of all of the paths that this peer is on.
886 * @param cp peer to modify
887 * @param entry an entry on a path
888 * @param off offset of this peer on the path
891 GCP_path_entry_remove (struct CadetPeer *cp,
892 struct CadetPeerPathEntry *entry,
895 LOG (GNUNET_ERROR_TYPE_DEBUG,
896 "Removing knowledge about peer %s beging on path %s at offset %u\n",
898 GCPP_2s (entry->path),
900 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
903 GNUNET_assert (0 < cp->num_paths);
906 if ( (NULL == cp->core_mq) &&
908 (NULL == cp->search_h) &&
909 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
911 = GCD_search (&cp->pid);
912 if (NULL == cp->destroy_task)
914 /* paths changed, we might now be ready for destruction, check again */
915 consider_peer_destroy (cp);
921 * Prune down the number of paths to this peer, we seem to
924 * @param cls the `struct CadetPeer` to maintain the path heap for
927 path_heap_cleanup (void *cls)
929 struct CadetPeer *cp = cls;
930 struct CadetPeerPath *root;
932 cp->heap_cleanup_task = NULL;
933 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
934 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
936 /* Now we have way too many, drop least desirable UNLESS it is in use!
937 (Note that this intentionally keeps highly desireable, but currently
938 unused paths around in the hope that we might be able to switch, even
939 if the number of paths exceeds the threshold.) */
940 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
941 GNUNET_assert (NULL != root);
943 GCPP_get_connection (root,
945 GCPP_get_length (root) - 1))
946 break; /* can't fix */
947 /* Got plenty of paths to this destination, and this is a low-quality
948 one that we don't care about. Allow it to die. */
949 GNUNET_assert (root ==
950 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
957 * Try adding a @a path to this @a peer. If the peer already
958 * has plenty of paths, return NULL.
960 * @param cp peer to which the @a path leads to
961 * @param path a path looking for an owner; may not be fully initialized yet!
962 * @param off offset of @a cp in @a path
963 * @param force force attaching the path
964 * @return NULL if this peer does not care to become a new owner,
965 * otherwise the node in the peer's path heap for the @a path.
967 struct GNUNET_CONTAINER_HeapNode *
968 GCP_attach_path (struct CadetPeer *cp,
969 struct CadetPeerPath *path,
973 GNUNET_CONTAINER_HeapCostType desirability;
974 struct CadetPeerPath *root;
975 GNUNET_CONTAINER_HeapCostType root_desirability;
976 struct GNUNET_CONTAINER_HeapNode *hn;
978 GNUNET_assert (off == GCPP_get_length (path) - 1);
979 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
981 if (NULL == cp->path_heap)
983 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
984 GNUNET_assert (GNUNET_NO == force);
987 desirability = GCPP_get_desirability (path);
988 if (GNUNET_NO == force)
990 /* FIXME: desirability is not yet initialized; tricky! */
992 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
997 root_desirability = 0;
1000 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1001 (desirability < root_desirability) )
1003 LOG (GNUNET_ERROR_TYPE_DEBUG,
1004 "Decided to not attach path %s to peer %s due to undesirability\n",
1011 LOG (GNUNET_ERROR_TYPE_DEBUG,
1012 "Attaching path %s to peer %s (%s)\n",
1015 (GNUNET_NO == force) ? "desirable" : "forced");
1017 /* Yes, we'd like to add this path, add to our heap */
1018 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1022 /* Consider maybe dropping other paths because of the new one */
1023 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1024 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1025 (NULL != cp->heap_cleanup_task) )
1026 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1033 * This peer can no longer own @a path as the path
1034 * has been extended and a peer further down the line
1035 * is now the new owner.
1037 * @param cp old owner of the @a path
1038 * @param path path where the ownership is lost
1039 * @param hn note in @a cp's path heap that must be deleted
1042 GCP_detach_path (struct CadetPeer *cp,
1043 struct CadetPeerPath *path,
1044 struct GNUNET_CONTAINER_HeapNode *hn)
1046 LOG (GNUNET_ERROR_TYPE_DEBUG,
1047 "Detatching path %s from peer %s\n",
1050 GNUNET_assert (path ==
1051 GNUNET_CONTAINER_heap_remove_node (hn));
1056 * Add a @a connection to this @a cp.
1058 * @param cp peer via which the @a connection goes
1059 * @param cc the connection to add
1062 GCP_add_connection (struct CadetPeer *cp,
1063 struct CadetConnection *cc)
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Adding %s to peer %s\n",
1069 GNUNET_assert (GNUNET_OK ==
1070 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1071 &GCC_get_id (cc)->connection_of_tunnel,
1073 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1074 if (NULL != cp->destroy_task)
1076 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1077 cp->destroy_task = NULL;
1083 * Remove a @a connection that went via this @a cp.
1085 * @param cp peer via which the @a connection went
1086 * @param cc the connection to remove
1089 GCP_remove_connection (struct CadetPeer *cp,
1090 struct CadetConnection *cc)
1092 LOG (GNUNET_ERROR_TYPE_DEBUG,
1093 "Removing connection %s from peer %s\n",
1096 GNUNET_assert (GNUNET_YES ==
1097 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1098 &GCC_get_id (cc)->connection_of_tunnel,
1100 consider_peer_destroy (cp);
1105 * Retrieve the CadetPeer stucture associated with the
1106 * peer. Optionally create one and insert it in the appropriate
1107 * structures if the peer is not known yet.
1109 * @param peer_id Full identity of the peer.
1110 * @param create #GNUNET_YES if a new peer should be created if unknown.
1111 * #GNUNET_NO to return NULL if peer is unknown.
1112 * @return Existing or newly created peer structure.
1113 * NULL if unknown and not requested @a create
1116 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1119 struct CadetPeer *cp;
1121 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1125 if (GNUNET_NO == create)
1127 cp = GNUNET_new (struct CadetPeer);
1129 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1131 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1132 GNUNET_assert (GNUNET_YES ==
1133 GNUNET_CONTAINER_multipeermap_put (peers,
1136 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1137 LOG (GNUNET_ERROR_TYPE_DEBUG,
1138 "Creating peer %s\n",
1145 * Obtain the peer identity for a `struct CadetPeer`.
1147 * @param cp our peer handle
1148 * @return the peer identity
1150 const struct GNUNET_PeerIdentity *
1151 GCP_get_id (struct CadetPeer *cp)
1158 * Iterate over all known peers.
1160 * @param iter Iterator.
1161 * @param cls Closure for @c iter.
1164 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1167 GNUNET_CONTAINER_multipeermap_iterate (peers,
1174 * Count the number of known paths toward the peer.
1176 * @param cp Peer to get path info.
1177 * @return Number of known paths.
1180 GCP_count_paths (const struct CadetPeer *cp)
1182 return cp->num_paths;
1187 * Iterate over the paths to a peer.
1189 * @param cp Peer to get path info.
1190 * @param callback Function to call for every path.
1191 * @param callback_cls Closure for @a callback.
1192 * @return Number of iterated paths.
1195 GCP_iterate_paths (struct CadetPeer *cp,
1196 GCP_PathIterator callback,
1199 unsigned int ret = 0;
1201 LOG (GNUNET_ERROR_TYPE_DEBUG,
1202 "Iterating over paths to peer %s%s\n",
1204 (NULL == cp->core_mq) ? "" : " including direct link");
1205 if (NULL != cp->core_mq)
1207 struct CadetPeerPath *path;
1209 path = GCPP_get_path_from_route (1,
1213 callback (callback_cls,
1218 for (unsigned int i=0;i<cp->path_dll_length;i++)
1220 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1226 callback (callback_cls,
1237 * Iterate over the paths to @a cp where
1238 * @a cp is at distance @a dist from us.
1240 * @param cp Peer to get path info.
1241 * @param dist desired distance of @a cp to us on the path
1242 * @param callback Function to call for every path.
1243 * @param callback_cls Closure for @a callback.
1244 * @return Number of iterated paths.
1247 GCP_iterate_paths_at (struct CadetPeer *cp,
1249 GCP_PathIterator callback,
1252 unsigned int ret = 0;
1254 if (dist >= cp->path_dll_length)
1256 LOG (GNUNET_ERROR_TYPE_DEBUG,
1257 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1259 cp->path_dll_length);
1262 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1267 callback (callback_cls,
1278 * Get the tunnel towards a peer.
1280 * @param cp Peer to get from.
1281 * @param create #GNUNET_YES to create a tunnel if we do not have one
1282 * @return Tunnel towards peer.
1284 struct CadetTunnel *
1285 GCP_get_tunnel (struct CadetPeer *cp,
1290 if ( (NULL != cp->t) ||
1291 (GNUNET_NO == create) )
1293 cp->t = GCT_create_tunnel (cp);
1294 consider_peer_activate (cp);
1300 * Hello offer was passed to the transport service. Mark it
1303 * @param cls the `struct CadetPeer` where the offer completed
1306 hello_offer_done (void *cls)
1308 struct CadetPeer *cp = cls;
1310 cp->hello_offer = NULL;
1315 * We got a HELLO for a @a peer, remember it, and possibly
1316 * trigger adequate actions (like trying to connect).
1318 * @param cp the peer we got a HELLO for
1319 * @param hello the HELLO to remember
1322 GCP_set_hello (struct CadetPeer *cp,
1323 const struct GNUNET_HELLO_Message *hello)
1325 struct GNUNET_HELLO_Message *mrg;
1327 LOG (GNUNET_ERROR_TYPE_DEBUG,
1328 "Got %u byte HELLO for peer %s\n",
1329 (unsigned int) GNUNET_HELLO_size (hello),
1331 if (NULL != cp->hello_offer)
1333 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1334 cp->hello_offer = NULL;
1336 if (NULL != cp->hello)
1338 mrg = GNUNET_HELLO_merge (hello,
1340 GNUNET_free (cp->hello);
1345 cp->hello = GNUNET_memdup (hello,
1346 GNUNET_HELLO_size (hello));
1349 = GNUNET_TRANSPORT_offer_hello (cfg,
1350 GNUNET_HELLO_get_header (cp->hello) ,
1353 /* New HELLO means cp's destruction time may change... */
1354 consider_peer_destroy (cp);
1359 * The tunnel to the given peer no longer exists, remove it from our
1360 * data structures, and possibly clean up the peer itself.
1362 * @param cp the peer affected
1363 * @param t the dead tunnel
1366 GCP_drop_tunnel (struct CadetPeer *cp,
1367 struct CadetTunnel *t)
1369 LOG (GNUNET_ERROR_TYPE_DEBUG,
1370 "Dropping tunnel %s to peer %s\n",
1373 GNUNET_assert (cp->t == t);
1375 consider_peer_destroy (cp);
1380 * Test if @a cp has a core-level connection
1382 * @param cp peer to test
1383 * @return #GNUNET_YES if @a cp has a core-level connection
1386 GCP_has_core_connection (struct CadetPeer *cp)
1388 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1393 * Start message queue change notifications.
1395 * @param cp peer to notify for
1396 * @param cb function to call if mq becomes available or unavailable
1397 * @param cb_cls closure for @a cb
1398 * @return handle to cancel request
1400 struct GCP_MessageQueueManager *
1401 GCP_request_mq (struct CadetPeer *cp,
1402 GCP_MessageQueueNotificationCallback cb,
1405 struct GCP_MessageQueueManager *mqm;
1407 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1409 mqm->cb_cls = cb_cls;
1411 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1414 LOG (GNUNET_ERROR_TYPE_DEBUG,
1415 "Creating MQM %p for peer %s\n",
1418 if (NULL != cp->core_mq)
1426 * Stops message queue change notifications.
1428 * @param mqm handle matching request to cancel
1429 * @param last_env final message to transmit, or NULL
1432 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1433 struct GNUNET_MQ_Envelope *last_env)
1435 struct CadetPeer *cp = mqm->cp;
1437 LOG (GNUNET_ERROR_TYPE_DEBUG,
1438 "Destroying MQM %p for peer %s%s\n",
1441 (NULL == last_env) ? "" : " with last ditch transmission");
1442 if (NULL != mqm->env)
1443 GNUNET_MQ_discard (mqm->env);
1444 if (NULL != last_env)
1446 if (NULL != cp->core_mq)
1448 GNUNET_MQ_notify_sent (last_env,
1451 GNUNET_MQ_send (cp->core_mq,
1456 GNUNET_MQ_discard (last_env);
1459 if (cp->mqm_ready_ptr == mqm)
1460 cp->mqm_ready_ptr = mqm->next;
1461 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1469 * Send the message in @a env to @a cp, overriding queueing logic.
1470 * This function should only be used to send error messages outside
1471 * of flow and congestion control, similar to ICMP. Note that
1472 * the envelope may be silently discarded as well.
1474 * @param cp peer to send the message to
1475 * @param env envelope with the message to send
1478 GCP_send_ooo (struct CadetPeer *cp,
1479 struct GNUNET_MQ_Envelope *env)
1481 LOG (GNUNET_ERROR_TYPE_DEBUG,
1482 "Sending message to %s out of management\n",
1484 if (NULL == cp->core_mq)
1486 GNUNET_MQ_discard (env);
1489 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1491 GNUNET_MQ_discard (env);
1494 GNUNET_MQ_notify_sent (env,
1497 GNUNET_MQ_send (cp->core_mq,
1504 /* end of gnunet-service-cadet-new_peer.c */