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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file cadet/gnunet-service-cadet_peer.c
23 * @brief Information we track per peer.
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
28 * - optimize stopping/restarting DHT search to situations
29 * where we actually need it (i.e. not if we have a direct connection,
30 * or if we already have plenty of good short ones, or maybe even
31 * to take a break if we have some connections and have searched a lot (?))
34 #include "gnunet_util_lib.h"
35 #include "gnunet_hello_lib.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_ats_service.h"
39 #include "gnunet_core_service.h"
40 #include "gnunet_statistics_service.h"
41 #include "cadet_protocol.h"
42 #include "gnunet-service-cadet_connection.h"
43 #include "gnunet-service-cadet_dht.h"
44 #include "gnunet-service-cadet_peer.h"
45 #include "gnunet-service-cadet_paths.h"
46 #include "gnunet-service-cadet_tunnels.h"
49 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
53 * How long do we wait until tearing down an idle peer?
55 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
58 * How long do we keep paths around if we no longer care about the peer?
60 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
63 * Queue size when we start dropping OOO messages.
65 #define MAX_OOO_QUEUE_SIZE 100
69 * Data structure used to track whom we have to notify about changes
70 * to our message queue.
72 struct GCP_MessageQueueManager
78 struct GCP_MessageQueueManager *next;
83 struct GCP_MessageQueueManager *prev;
86 * Function to call with updated message queue object.
88 GCP_MessageQueueNotificationCallback cb;
96 * The peer this is for.
101 * Envelope this manager would like to transmit once it is its turn.
103 struct GNUNET_MQ_Envelope *env;
109 * Struct containing all information regarding a given peer
116 struct GNUNET_PeerIdentity pid;
119 * Last time we heard from this peer (currently not used!)
121 struct GNUNET_TIME_Absolute last_contactXXX;
124 * Array of DLLs of paths traversing the peer, organized by the
125 * offset of the peer on the larger path.
127 struct CadetPeerPathEntry **path_heads;
130 * Array of DLL of paths traversing the peer, organized by the
131 * offset of the peer on the larger path.
133 struct CadetPeerPathEntry **path_tails;
136 * Notifications to call when @e core_mq changes.
138 struct GCP_MessageQueueManager *mqm_head;
141 * Notifications to call when @e core_mq changes.
143 struct GCP_MessageQueueManager *mqm_tail;
146 * Pointer to first "ready" entry in @e mqm_head.
148 struct GCP_MessageQueueManager *mqm_ready_ptr;
151 * MIN-heap of paths owned by this peer (they also end at this
152 * peer). Ordered by desirability.
154 struct GNUNET_CONTAINER_Heap *path_heap;
157 * Handle to stop the DHT search for paths to this peer
159 struct GCD_search_handle *search_h;
162 * Task to clean up @e path_heap asynchronously.
164 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
167 * Task to destroy this entry.
169 struct GNUNET_SCHEDULER_Task *destroy_task;
172 * Tunnel to this peer, if any.
174 struct CadetTunnel *t;
177 * Connections that go through this peer; indexed by tid.
179 struct GNUNET_CONTAINER_MultiShortmap *connections;
182 * Handle for core transmissions.
184 struct GNUNET_MQ_Handle *core_mq;
187 * Hello message of the peer.
189 struct GNUNET_HELLO_Message *hello;
192 * Handle to us offering the HELLO to the transport.
194 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
197 * Handle to our ATS request asking ATS to suggest an address
198 * to TRANSPORT for this peer (to establish a direct link).
200 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
203 * How many messages are in the queue to this peer.
205 unsigned int queue_n;
208 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
210 unsigned int num_paths;
213 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
214 * Used to speed-up @GCP_get_desirability_of_path() calculation.
216 unsigned int off_sum;
219 * Number of message queue managers of this peer that have a message in waiting.
221 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
222 * TODO: could be replaced by another DLL that would then allow us to avoid
223 * the O(n)-scan of the DLL for ready entries!
225 unsigned int mqm_ready_counter;
228 * Current length of the @e path_heads and @path_tails arrays.
229 * The arrays should be grown as needed.
231 unsigned int path_dll_length;
237 * Get the static string for a peer ID.
240 * @return Static string for it's ID.
243 GCP_2s (const struct CadetPeer *cp)
248 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
259 * Calculate how desirable a path is for @a cp if @a cp
260 * is at offset @a off.
262 * The 'desirability_table.c' program can be used to compute a list of
263 * sample outputs for different scenarios. Basically, we score paths
264 * lower if there are many alternatives, and higher if they are
265 * shorter than average, and very high if they are much shorter than
266 * average and without many alternatives.
268 * @param cp a peer reachable via a path
269 * @param off offset of @a cp in the path
270 * @return score how useful a path is to reach @a cp,
271 * positive scores mean path is more desirable
274 GCP_get_desirability_of_path (struct CadetPeer *cp,
277 unsigned int num_alts = cp->num_paths;
278 unsigned int off_sum;
283 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
284 GNUNET_assert (0 != cp->path_dll_length);
286 /* We maintain 'off_sum' in 'peer' and thereby
287 avoid the SLOW recalculation each time. Kept here
288 just to document what is going on. */
291 for (unsigned int j=0;j<cp->path_dll_length;j++)
292 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
296 GNUNET_assert (off_sum == cp->off_sum);
298 off_sum = cp->off_sum;
300 avg_sum = off_sum * 1.0 / cp->path_dll_length;
301 path_delta = off - avg_sum;
302 /* path_delta positiv: path off of peer above average (bad path for peer),
303 path_delta negativ: path off of peer below average (good path for peer) */
304 if (path_delta <= - 1.0)
305 weight_alts = - num_alts / path_delta; /* discount alternative paths */
306 else if (path_delta >= 1.0)
307 weight_alts = num_alts * path_delta; /* overcount alternative paths */
309 weight_alts = num_alts; /* count alternative paths normally */
312 /* off+1: long paths are generally harder to find and thus count
313 a bit more as they get longer. However, above-average paths
314 still need to count less, hence the squaring of that factor. */
315 return (off + 1.0) / (weight_alts * weight_alts);
320 * This peer is no longer be needed, clean it up now.
322 * @param cls peer to clean up
325 destroy_peer (void *cls)
327 struct CadetPeer *cp = cls;
329 LOG (GNUNET_ERROR_TYPE_DEBUG,
330 "Destroying state about peer %s\n",
332 cp->destroy_task = NULL;
333 GNUNET_assert (NULL == cp->t);
334 GNUNET_assert (NULL == cp->core_mq);
335 GNUNET_assert (0 == cp->num_paths);
336 for (unsigned int i=0;i<cp->path_dll_length;i++)
337 GNUNET_assert (NULL == cp->path_heads[i]);
338 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
339 GNUNET_assert (GNUNET_YES ==
340 GNUNET_CONTAINER_multipeermap_remove (peers,
343 GNUNET_free_non_null (cp->path_heads);
344 GNUNET_free_non_null (cp->path_tails);
345 cp->path_dll_length = 0;
346 if (NULL != cp->search_h)
348 GCD_search_stop (cp->search_h);
351 /* FIXME: clean up search_delayedXXX! */
353 if (NULL != cp->hello_offer)
355 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
356 cp->hello_offer = NULL;
358 if (NULL != cp->connectivity_suggestion)
360 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
361 cp->connectivity_suggestion = NULL;
363 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
364 if (NULL != cp->path_heap)
366 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
367 cp->path_heap = NULL;
369 if (NULL != cp->heap_cleanup_task)
371 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
372 cp->heap_cleanup_task = NULL;
374 GNUNET_free_non_null (cp->hello);
375 /* Peer should not be freed if paths exist; if there are no paths,
376 there ought to be no connections, and without connections, no
377 notifications. Thus we can assert that mqm_head is empty at this
379 GNUNET_assert (NULL == cp->mqm_head);
380 GNUNET_assert (NULL == cp->mqm_ready_ptr);
386 * This peer is now on more "active" duty, activate processes related to it.
388 * @param cp the more-active peer
391 consider_peer_activate (struct CadetPeer *cp)
395 LOG (GNUNET_ERROR_TYPE_DEBUG,
396 "Updating peer %s activation state (%u connections)%s%s\n",
398 GNUNET_CONTAINER_multishortmap_size (cp->connections),
399 (NULL == cp->t) ? "" : " with tunnel",
400 (NULL == cp->core_mq) ? "" : " with CORE link");
401 if (NULL != cp->destroy_task)
403 /* It's active, do not destory! */
404 GNUNET_SCHEDULER_cancel (cp->destroy_task);
405 cp->destroy_task = NULL;
407 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
410 /* We're just on a path or directly connected; don't bother too much */
411 if (NULL != cp->connectivity_suggestion)
413 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
414 cp->connectivity_suggestion = NULL;
416 if (NULL != cp->search_h)
418 GCD_search_stop (cp->search_h);
423 if (NULL == cp->core_mq)
425 /* Lacks direct connection, try to create one by querying the DHT */
426 if ( (NULL == cp->search_h) &&
427 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
429 = GCD_search (&cp->pid);
433 /* Have direct connection, stop DHT search if active */
434 if (NULL != cp->search_h)
436 GCD_search_stop (cp->search_h);
441 /* If we have a tunnel, our urge for connections is much bigger */
442 strength = (NULL != cp->t) ? 32 : 1;
443 if (NULL != cp->connectivity_suggestion)
444 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
445 cp->connectivity_suggestion
446 = GNUNET_ATS_connectivity_suggest (ats_ch,
453 * This peer may no longer be needed, consider cleaning it up.
455 * @param cp peer to clean up
458 consider_peer_destroy (struct CadetPeer *cp);
462 * We really no longere care about a peer, stop hogging memory with paths to it.
463 * Afterwards, see if there is more to be cleaned up about this peer.
465 * @param cls a `struct CadetPeer`.
468 drop_paths (void *cls)
470 struct CadetPeer *cp = cls;
471 struct CadetPeerPath *path;
473 cp->destroy_task = NULL;
474 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
476 consider_peer_destroy (cp);
481 * This peer may no longer be needed, consider cleaning it up.
483 * @param cp peer to clean up
486 consider_peer_destroy (struct CadetPeer *cp)
488 struct GNUNET_TIME_Relative exp;
490 if (NULL != cp->destroy_task)
492 GNUNET_SCHEDULER_cancel (cp->destroy_task);
493 cp->destroy_task = NULL;
496 return; /* still relevant! */
497 if (NULL != cp->core_mq)
498 return; /* still relevant! */
499 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
500 return; /* still relevant! */
501 if ( (NULL != cp->path_heap) &&
502 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
504 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
509 if (0 != cp->num_paths)
510 return; /* still relevant! */
511 if (NULL != cp->hello)
513 /* relevant only until HELLO expires */
514 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
515 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
520 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
527 * Set the message queue to @a mq for peer @a cp and notify watchers.
529 * @param cp peer to modify
530 * @param mq message queue to set (can be NULL)
533 GCP_set_mq (struct CadetPeer *cp,
534 struct GNUNET_MQ_Handle *mq)
536 LOG (GNUNET_ERROR_TYPE_DEBUG,
537 "Message queue for peer %s is now %p\n",
541 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
545 /* Save next pointer in case mqm gets freed by the callback */
549 if (NULL != mqm->env)
551 GNUNET_MQ_discard (mqm->env);
553 mqm->cb (mqm->cb_cls,
558 mqm->cb (mqm->cb_cls,
564 GNUNET_assert (NULL == mqm->env);
565 mqm->cb (mqm->cb_cls,
571 consider_peer_activate (cp);
573 consider_peer_destroy (cp);
578 /* have a new, direct path to the target, notify tunnel */
579 struct CadetPeerPath *path;
581 path = GCPP_get_path_from_route (1,
583 GCT_consider_path (cp->t,
591 * Debug function should NEVER return true in production code, useful to
592 * simulate losses for testcases.
594 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
599 if (0 == drop_percent)
601 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
609 * Function called when CORE took one of the messages from
610 * a message queue manager and transmitted it.
612 * @param cls the `struct CadetPeeer` where we made progress
615 mqm_send_done (void *cls);
619 * Transmit current envelope from this @a mqm.
621 * @param mqm mqm to transmit message for now
624 mqm_execute (struct GCP_MessageQueueManager *mqm)
626 struct CadetPeer *cp = mqm->cp;
628 /* Move ready pointer to the next entry that might be ready. */
629 if ( (mqm == cp->mqm_ready_ptr) &&
630 (NULL != mqm->next) )
631 cp->mqm_ready_ptr = mqm->next;
632 /* Move entry to the end of the DLL, to be fair. */
633 if (mqm != cp->mqm_tail)
635 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
638 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
642 cp->mqm_ready_counter--;
643 if (GNUNET_YES == should_I_drop ())
645 LOG (GNUNET_ERROR_TYPE_DEBUG,
646 "DROPPING message to peer %s from MQM %p\n",
649 GNUNET_MQ_discard (mqm->env);
656 const struct GNUNET_MessageHeader *mh;
658 mh = GNUNET_MQ_env_get_msg (mqm->env);
659 switch (ntohs (mh->type))
661 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
663 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
664 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
665 LOG (GNUNET_ERROR_TYPE_DEBUG,
666 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
667 GNUNET_e2s (&msg->ephemeral_key),
669 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
676 LOG (GNUNET_ERROR_TYPE_DEBUG,
677 "Sending to peer %s from MQM %p\n",
680 GNUNET_MQ_send (cp->core_mq,
684 mqm->cb (mqm->cb_cls,
690 * Find the next ready message in the queue (starting
691 * the search from the `cp->mqm_ready_ptr`) and if possible
692 * execute the transmission.
694 * @param cp peer to try to send the next ready message to
697 send_next_ready (struct CadetPeer *cp)
699 struct GCP_MessageQueueManager *mqm;
701 if (0 == cp->mqm_ready_counter)
703 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
705 cp->mqm_ready_ptr = mqm->next;
707 return; /* nothing to do */
713 * Function called when CORE took one of the messages from
714 * a message queue manager and transmitted it.
716 * @param cls the `struct CadetPeeer` where we made progress
719 mqm_send_done (void *cls)
721 struct CadetPeer *cp = cls;
723 LOG (GNUNET_ERROR_TYPE_DEBUG,
724 "Sending to peer %s completed\n",
726 send_next_ready (cp);
731 * Send the message in @a env to @a cp.
733 * @param mqm the message queue manager to use for transmission
734 * @param env envelope with the message to send; must NOT
735 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
738 GCP_send (struct GCP_MessageQueueManager *mqm,
739 struct GNUNET_MQ_Envelope *env)
741 struct CadetPeer *cp = mqm->cp;
743 GNUNET_assert (NULL != env);
744 LOG (GNUNET_ERROR_TYPE_DEBUG,
745 "Queueing message to peer %s in MQM %p\n",
748 GNUNET_assert (NULL != cp->core_mq);
749 GNUNET_assert (NULL == mqm->env);
750 GNUNET_MQ_notify_sent (env,
754 cp->mqm_ready_counter++;
755 if (mqm != cp->mqm_ready_ptr)
756 cp->mqm_ready_ptr = cp->mqm_head;
757 if (1 == cp->mqm_ready_counter)
758 cp->mqm_ready_ptr = mqm;
759 if (0 != GNUNET_MQ_get_length (cp->core_mq))
761 send_next_ready (cp);
766 * Function called to destroy a peer now.
769 * @param pid identity of the peer (unused)
770 * @param value the `struct CadetPeer` to clean up
771 * @return #GNUNET_OK (continue to iterate)
774 destroy_iterator_cb (void *cls,
775 const struct GNUNET_PeerIdentity *pid,
778 struct CadetPeer *cp = value;
780 if (NULL != cp->destroy_task)
782 GNUNET_SCHEDULER_cancel (cp->destroy_task);
783 cp->destroy_task = NULL;
791 * Clean up all entries about all peers.
792 * Must only be called after all tunnels, CORE-connections and
793 * connections are down.
796 GCP_destroy_all_peers ()
798 LOG (GNUNET_ERROR_TYPE_DEBUG,
799 "Destroying all peers now\n");
800 GNUNET_CONTAINER_multipeermap_iterate (peers,
801 &destroy_iterator_cb,
807 * Drop all paths owned by this peer, and do not
808 * allow new ones to be added: We are shutting down.
810 * @param cp peer to drop paths to
813 GCP_drop_owned_paths (struct CadetPeer *cp)
815 struct CadetPeerPath *path;
817 LOG (GNUNET_ERROR_TYPE_DEBUG,
818 "Destroying all paths to %s\n",
820 while (NULL != (path =
821 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
823 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
824 cp->path_heap = NULL;
829 * Add an entry to the DLL of all of the paths that this peer is on.
831 * @param cp peer to modify
832 * @param entry an entry on a path
833 * @param off offset of this peer on the path
836 GCP_path_entry_add (struct CadetPeer *cp,
837 struct CadetPeerPathEntry *entry,
840 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
842 LOG (GNUNET_ERROR_TYPE_DEBUG,
843 "Discovered that peer %s is on path %s at offset %u\n",
845 GCPP_2s (entry->path),
847 if (off >= cp->path_dll_length)
849 unsigned int len = cp->path_dll_length;
851 GNUNET_array_grow (cp->path_heads,
854 GNUNET_array_grow (cp->path_tails,
858 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
864 /* If we have a tunnel to this peer, tell the tunnel that there is a
865 new path available. */
867 GCT_consider_path (cp->t,
871 if ( (NULL != cp->search_h) &&
872 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
874 /* Now I have enough paths, stop search */
875 GCD_search_stop (cp->search_h);
878 if (NULL != cp->destroy_task)
880 /* paths changed, this resets the destroy timeout counter
881 and aborts a destroy task that may no longer be valid
882 to have (as we now have more paths via this peer). */
883 consider_peer_destroy (cp);
889 * Remove an entry from the DLL of all of the paths that this peer is on.
891 * @param cp peer to modify
892 * @param entry an entry on a path
893 * @param off offset of this peer on the path
896 GCP_path_entry_remove (struct CadetPeer *cp,
897 struct CadetPeerPathEntry *entry,
900 LOG (GNUNET_ERROR_TYPE_DEBUG,
901 "Removing knowledge about peer %s beging on path %s at offset %u\n",
903 GCPP_2s (entry->path),
905 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
908 GNUNET_assert (0 < cp->num_paths);
911 if ( (NULL == cp->core_mq) &&
913 (NULL == cp->search_h) &&
914 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
916 = GCD_search (&cp->pid);
917 if (NULL == cp->destroy_task)
919 /* paths changed, we might now be ready for destruction, check again */
920 consider_peer_destroy (cp);
926 * Prune down the number of paths to this peer, we seem to
929 * @param cls the `struct CadetPeer` to maintain the path heap for
932 path_heap_cleanup (void *cls)
934 struct CadetPeer *cp = cls;
935 struct CadetPeerPath *root;
937 cp->heap_cleanup_task = NULL;
938 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
939 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
941 /* Now we have way too many, drop least desirable UNLESS it is in use!
942 (Note that this intentionally keeps highly desireable, but currently
943 unused paths around in the hope that we might be able to switch, even
944 if the number of paths exceeds the threshold.) */
945 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
946 GNUNET_assert (NULL != root);
948 GCPP_get_connection (root,
950 GCPP_get_length (root) - 1))
951 break; /* can't fix */
952 /* Got plenty of paths to this destination, and this is a low-quality
953 one that we don't care about. Allow it to die. */
954 GNUNET_assert (root ==
955 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
962 * Try adding a @a path to this @a peer. If the peer already
963 * has plenty of paths, return NULL.
965 * @param cp peer to which the @a path leads to
966 * @param path a path looking for an owner; may not be fully initialized yet!
967 * @param off offset of @a cp in @a path
968 * @param force force attaching the path
969 * @return NULL if this peer does not care to become a new owner,
970 * otherwise the node in the peer's path heap for the @a path.
972 struct GNUNET_CONTAINER_HeapNode *
973 GCP_attach_path (struct CadetPeer *cp,
974 struct CadetPeerPath *path,
978 GNUNET_CONTAINER_HeapCostType desirability;
979 struct CadetPeerPath *root;
980 GNUNET_CONTAINER_HeapCostType root_desirability;
981 struct GNUNET_CONTAINER_HeapNode *hn;
983 GNUNET_assert (off == GCPP_get_length (path) - 1);
984 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
986 if (NULL == cp->path_heap)
988 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
989 GNUNET_assert (GNUNET_NO == force);
992 desirability = GCPP_get_desirability (path);
993 if (GNUNET_NO == force)
995 /* FIXME: desirability is not yet initialized; tricky! */
997 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
1002 root_desirability = 0;
1005 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1006 (desirability < root_desirability) )
1008 LOG (GNUNET_ERROR_TYPE_DEBUG,
1009 "Decided to not attach path %s to peer %s due to undesirability\n",
1016 LOG (GNUNET_ERROR_TYPE_DEBUG,
1017 "Attaching path %s to peer %s (%s)\n",
1020 (GNUNET_NO == force) ? "desirable" : "forced");
1022 /* Yes, we'd like to add this path, add to our heap */
1023 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1027 /* Consider maybe dropping other paths because of the new one */
1028 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1029 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1030 (NULL != cp->heap_cleanup_task) )
1031 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1038 * This peer can no longer own @a path as the path
1039 * has been extended and a peer further down the line
1040 * is now the new owner.
1042 * @param cp old owner of the @a path
1043 * @param path path where the ownership is lost
1044 * @param hn note in @a cp's path heap that must be deleted
1047 GCP_detach_path (struct CadetPeer *cp,
1048 struct CadetPeerPath *path,
1049 struct GNUNET_CONTAINER_HeapNode *hn)
1051 LOG (GNUNET_ERROR_TYPE_DEBUG,
1052 "Detatching path %s from peer %s\n",
1055 GNUNET_assert (path ==
1056 GNUNET_CONTAINER_heap_remove_node (hn));
1061 * Add a @a connection to this @a cp.
1063 * @param cp peer via which the @a connection goes
1064 * @param cc the connection to add
1067 GCP_add_connection (struct CadetPeer *cp,
1068 struct CadetConnection *cc)
1070 LOG (GNUNET_ERROR_TYPE_DEBUG,
1071 "Adding %s to peer %s\n",
1074 GNUNET_assert (GNUNET_OK ==
1075 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1076 &GCC_get_id (cc)->connection_of_tunnel,
1078 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1079 if (NULL != cp->destroy_task)
1081 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1082 cp->destroy_task = NULL;
1088 * Remove a @a connection that went via this @a cp.
1090 * @param cp peer via which the @a connection went
1091 * @param cc the connection to remove
1094 GCP_remove_connection (struct CadetPeer *cp,
1095 struct CadetConnection *cc)
1097 LOG (GNUNET_ERROR_TYPE_DEBUG,
1098 "Removing connection %s from peer %s\n",
1101 GNUNET_assert (GNUNET_YES ==
1102 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1103 &GCC_get_id (cc)->connection_of_tunnel,
1105 consider_peer_destroy (cp);
1110 * Retrieve the CadetPeer stucture associated with the
1111 * peer. Optionally create one and insert it in the appropriate
1112 * structures if the peer is not known yet.
1114 * @param peer_id Full identity of the peer.
1115 * @param create #GNUNET_YES if a new peer should be created if unknown.
1116 * #GNUNET_NO to return NULL if peer is unknown.
1117 * @return Existing or newly created peer structure.
1118 * NULL if unknown and not requested @a create
1121 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1124 struct CadetPeer *cp;
1126 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1130 if (GNUNET_NO == create)
1132 cp = GNUNET_new (struct CadetPeer);
1134 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1136 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1137 GNUNET_assert (GNUNET_YES ==
1138 GNUNET_CONTAINER_multipeermap_put (peers,
1141 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1142 LOG (GNUNET_ERROR_TYPE_DEBUG,
1143 "Creating peer %s\n",
1150 * Obtain the peer identity for a `struct CadetPeer`.
1152 * @param cp our peer handle
1153 * @return the peer identity
1155 const struct GNUNET_PeerIdentity *
1156 GCP_get_id (struct CadetPeer *cp)
1163 * Iterate over all known peers.
1165 * @param iter Iterator.
1166 * @param cls Closure for @c iter.
1169 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1172 GNUNET_CONTAINER_multipeermap_iterate (peers,
1179 * Count the number of known paths toward the peer.
1181 * @param cp Peer to get path info.
1182 * @return Number of known paths.
1185 GCP_count_paths (const struct CadetPeer *cp)
1187 return cp->num_paths;
1192 * Iterate over the paths to a peer.
1194 * @param cp Peer to get path info.
1195 * @param callback Function to call for every path.
1196 * @param callback_cls Closure for @a callback.
1197 * @return Number of iterated paths.
1200 GCP_iterate_paths (struct CadetPeer *cp,
1201 GCP_PathIterator callback,
1204 unsigned int ret = 0;
1206 LOG (GNUNET_ERROR_TYPE_DEBUG,
1207 "Iterating over paths to peer %s%s\n",
1209 (NULL == cp->core_mq) ? "" : " including direct link");
1210 if (NULL != cp->core_mq)
1212 struct CadetPeerPath *path;
1214 path = GCPP_get_path_from_route (1,
1218 callback (callback_cls,
1223 for (unsigned int i=0;i<cp->path_dll_length;i++)
1225 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1231 callback (callback_cls,
1242 * Iterate over the paths to @a cp where
1243 * @a cp is at distance @a dist from us.
1245 * @param cp Peer to get path info.
1246 * @param dist desired distance of @a cp to us on the path
1247 * @param callback Function to call for every path.
1248 * @param callback_cls Closure for @a callback.
1249 * @return Number of iterated paths.
1252 GCP_iterate_paths_at (struct CadetPeer *cp,
1254 GCP_PathIterator callback,
1257 unsigned int ret = 0;
1259 if (dist >= cp->path_dll_length)
1261 LOG (GNUNET_ERROR_TYPE_DEBUG,
1262 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1264 cp->path_dll_length);
1267 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1272 callback (callback_cls,
1283 * Get the tunnel towards a peer.
1285 * @param cp Peer to get from.
1286 * @param create #GNUNET_YES to create a tunnel if we do not have one
1287 * @return Tunnel towards peer.
1289 struct CadetTunnel *
1290 GCP_get_tunnel (struct CadetPeer *cp,
1295 if ( (NULL != cp->t) ||
1296 (GNUNET_NO == create) )
1298 cp->t = GCT_create_tunnel (cp);
1299 consider_peer_activate (cp);
1305 * Hello offer was passed to the transport service. Mark it
1308 * @param cls the `struct CadetPeer` where the offer completed
1311 hello_offer_done (void *cls)
1313 struct CadetPeer *cp = cls;
1315 cp->hello_offer = NULL;
1320 * We got a HELLO for a @a peer, remember it, and possibly
1321 * trigger adequate actions (like trying to connect).
1323 * @param cp the peer we got a HELLO for
1324 * @param hello the HELLO to remember
1327 GCP_set_hello (struct CadetPeer *cp,
1328 const struct GNUNET_HELLO_Message *hello)
1330 struct GNUNET_HELLO_Message *mrg;
1332 LOG (GNUNET_ERROR_TYPE_DEBUG,
1333 "Got %u byte HELLO for peer %s\n",
1334 (unsigned int) GNUNET_HELLO_size (hello),
1336 if (NULL != cp->hello_offer)
1338 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1339 cp->hello_offer = NULL;
1341 if (NULL != cp->hello)
1343 mrg = GNUNET_HELLO_merge (hello,
1345 GNUNET_free (cp->hello);
1350 cp->hello = GNUNET_memdup (hello,
1351 GNUNET_HELLO_size (hello));
1354 = GNUNET_TRANSPORT_offer_hello (cfg,
1355 GNUNET_HELLO_get_header (cp->hello) ,
1358 /* New HELLO means cp's destruction time may change... */
1359 consider_peer_destroy (cp);
1364 * The tunnel to the given peer no longer exists, remove it from our
1365 * data structures, and possibly clean up the peer itself.
1367 * @param cp the peer affected
1368 * @param t the dead tunnel
1371 GCP_drop_tunnel (struct CadetPeer *cp,
1372 struct CadetTunnel *t)
1374 LOG (GNUNET_ERROR_TYPE_DEBUG,
1375 "Dropping tunnel %s to peer %s\n",
1378 GNUNET_assert (cp->t == t);
1380 consider_peer_destroy (cp);
1385 * Test if @a cp has a core-level connection
1387 * @param cp peer to test
1388 * @return #GNUNET_YES if @a cp has a core-level connection
1391 GCP_has_core_connection (struct CadetPeer *cp)
1393 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1398 * Start message queue change notifications.
1400 * @param cp peer to notify for
1401 * @param cb function to call if mq becomes available or unavailable
1402 * @param cb_cls closure for @a cb
1403 * @return handle to cancel request
1405 struct GCP_MessageQueueManager *
1406 GCP_request_mq (struct CadetPeer *cp,
1407 GCP_MessageQueueNotificationCallback cb,
1410 struct GCP_MessageQueueManager *mqm;
1412 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1414 mqm->cb_cls = cb_cls;
1416 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1419 LOG (GNUNET_ERROR_TYPE_DEBUG,
1420 "Creating MQM %p for peer %s\n",
1423 if (NULL != cp->core_mq)
1431 * Stops message queue change notifications.
1433 * @param mqm handle matching request to cancel
1434 * @param last_env final message to transmit, or NULL
1437 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1438 struct GNUNET_MQ_Envelope *last_env)
1440 struct CadetPeer *cp = mqm->cp;
1442 LOG (GNUNET_ERROR_TYPE_DEBUG,
1443 "Destroying MQM %p for peer %s%s\n",
1446 (NULL == last_env) ? "" : " with last ditch transmission");
1447 if (NULL != mqm->env)
1448 GNUNET_MQ_discard (mqm->env);
1449 if (NULL != last_env)
1451 if (NULL != cp->core_mq)
1453 GNUNET_MQ_notify_sent (last_env,
1456 GNUNET_MQ_send (cp->core_mq,
1461 GNUNET_MQ_discard (last_env);
1464 if (cp->mqm_ready_ptr == mqm)
1465 cp->mqm_ready_ptr = mqm->next;
1466 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1474 * Send the message in @a env to @a cp, overriding queueing logic.
1475 * This function should only be used to send error messages outside
1476 * of flow and congestion control, similar to ICMP. Note that
1477 * the envelope may be silently discarded as well.
1479 * @param cp peer to send the message to
1480 * @param env envelope with the message to send
1483 GCP_send_ooo (struct CadetPeer *cp,
1484 struct GNUNET_MQ_Envelope *env)
1486 LOG (GNUNET_ERROR_TYPE_DEBUG,
1487 "Sending message to %s out of management\n",
1489 if (NULL == cp->core_mq)
1491 GNUNET_MQ_discard (env);
1494 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1496 GNUNET_MQ_discard (env);
1499 GNUNET_MQ_notify_sent (env,
1502 GNUNET_MQ_send (cp->core_mq,
1509 /* end of gnunet-service-cadet-new_peer.c */