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 Affero 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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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)
249 (NULL == &cp->pid.public_key))
253 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
269 * Calculate how desirable a path is for @a cp if @a cp
270 * is at offset @a off.
272 * The 'desirability_table.c' program can be used to compute a list of
273 * sample outputs for different scenarios. Basically, we score paths
274 * lower if there are many alternatives, and higher if they are
275 * shorter than average, and very high if they are much shorter than
276 * average and without many alternatives.
278 * @param cp a peer reachable via a path
279 * @param off offset of @a cp in the path
280 * @return score how useful a path is to reach @a cp,
281 * positive scores mean path is more desirable
284 GCP_get_desirability_of_path (struct CadetPeer *cp,
287 unsigned int num_alts = cp->num_paths;
288 unsigned int off_sum;
293 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
294 GNUNET_assert (0 != cp->path_dll_length);
296 /* We maintain 'off_sum' in 'peer' and thereby
297 avoid the SLOW recalculation each time. Kept here
298 just to document what is going on. */
301 for (unsigned int j=0;j<cp->path_dll_length;j++)
302 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
306 GNUNET_assert (off_sum == cp->off_sum);
308 off_sum = cp->off_sum;
310 avg_sum = off_sum * 1.0 / cp->path_dll_length;
311 path_delta = off - avg_sum;
312 /* path_delta positiv: path off of peer above average (bad path for peer),
313 path_delta negativ: path off of peer below average (good path for peer) */
314 if (path_delta <= - 1.0)
315 weight_alts = - num_alts / path_delta; /* discount alternative paths */
316 else if (path_delta >= 1.0)
317 weight_alts = num_alts * path_delta; /* overcount alternative paths */
319 weight_alts = num_alts; /* count alternative paths normally */
322 /* off+1: long paths are generally harder to find and thus count
323 a bit more as they get longer. However, above-average paths
324 still need to count less, hence the squaring of that factor. */
325 return (off + 1.0) / (weight_alts * weight_alts);
330 * This peer is no longer be needed, clean it up now.
332 * @param cls peer to clean up
335 destroy_peer (void *cls)
337 struct CadetPeer *cp = cls;
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Destroying state about peer %s\n",
342 cp->destroy_task = NULL;
343 GNUNET_assert (NULL == cp->t);
344 GNUNET_assert (NULL == cp->core_mq);
345 GNUNET_assert (0 == cp->num_paths);
346 for (unsigned int i=0;i<cp->path_dll_length;i++)
347 GNUNET_assert (NULL == cp->path_heads[i]);
348 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
349 GNUNET_assert (GNUNET_YES ==
350 GNUNET_CONTAINER_multipeermap_remove (peers,
353 GNUNET_free_non_null (cp->path_heads);
354 GNUNET_free_non_null (cp->path_tails);
355 cp->path_dll_length = 0;
356 if (NULL != cp->search_h)
358 GCD_search_stop (cp->search_h);
361 /* FIXME: clean up search_delayedXXX! */
363 if (NULL != cp->hello_offer)
365 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
366 cp->hello_offer = NULL;
368 if (NULL != cp->connectivity_suggestion)
370 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
371 cp->connectivity_suggestion = NULL;
373 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
374 if (NULL != cp->path_heap)
376 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
377 cp->path_heap = NULL;
379 if (NULL != cp->heap_cleanup_task)
381 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
382 cp->heap_cleanup_task = NULL;
384 GNUNET_free_non_null (cp->hello);
385 /* Peer should not be freed if paths exist; if there are no paths,
386 there ought to be no connections, and without connections, no
387 notifications. Thus we can assert that mqm_head is empty at this
389 GNUNET_assert (NULL == cp->mqm_head);
390 GNUNET_assert (NULL == cp->mqm_ready_ptr);
396 * This peer is now on more "active" duty, activate processes related to it.
398 * @param cp the more-active peer
401 consider_peer_activate (struct CadetPeer *cp)
405 LOG (GNUNET_ERROR_TYPE_DEBUG,
406 "Updating peer %s activation state (%u connections)%s%s\n",
408 GNUNET_CONTAINER_multishortmap_size (cp->connections),
409 (NULL == cp->t) ? "" : " with tunnel",
410 (NULL == cp->core_mq) ? "" : " with CORE link");
411 if (NULL != cp->destroy_task)
413 /* It's active, do not destory! */
414 GNUNET_SCHEDULER_cancel (cp->destroy_task);
415 cp->destroy_task = NULL;
417 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
420 /* We're just on a path or directly connected; don't bother too much */
421 if (NULL != cp->connectivity_suggestion)
423 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
424 cp->connectivity_suggestion = NULL;
426 if (NULL != cp->search_h)
428 GCD_search_stop (cp->search_h);
433 if (NULL == cp->core_mq)
435 /* Lacks direct connection, try to create one by querying the DHT */
436 if ( (NULL == cp->search_h) &&
437 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
439 = GCD_search (&cp->pid);
443 /* Have direct connection, stop DHT search if active */
444 if (NULL != cp->search_h)
446 GCD_search_stop (cp->search_h);
451 /* If we have a tunnel, our urge for connections is much bigger */
452 strength = (NULL != cp->t) ? 32 : 1;
453 if (NULL != cp->connectivity_suggestion)
454 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
455 cp->connectivity_suggestion
456 = GNUNET_ATS_connectivity_suggest (ats_ch,
463 * This peer may no longer be needed, consider cleaning it up.
465 * @param cp peer to clean up
468 consider_peer_destroy (struct CadetPeer *cp);
472 * We really no longere care about a peer, stop hogging memory with paths to it.
473 * Afterwards, see if there is more to be cleaned up about this peer.
475 * @param cls a `struct CadetPeer`.
478 drop_paths (void *cls)
480 struct CadetPeer *cp = cls;
481 struct CadetPeerPath *path;
483 cp->destroy_task = NULL;
484 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
486 consider_peer_destroy (cp);
491 * This peer may no longer be needed, consider cleaning it up.
493 * @param cp peer to clean up
496 consider_peer_destroy (struct CadetPeer *cp)
498 struct GNUNET_TIME_Relative exp;
500 if (NULL != cp->destroy_task)
502 GNUNET_SCHEDULER_cancel (cp->destroy_task);
503 cp->destroy_task = NULL;
506 return; /* still relevant! */
507 if (NULL != cp->core_mq)
508 return; /* still relevant! */
509 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
510 return; /* still relevant! */
511 if ( (NULL != cp->path_heap) &&
512 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
514 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
519 if (0 != cp->num_paths)
520 return; /* still relevant! */
521 if (NULL != cp->hello)
523 /* relevant only until HELLO expires */
524 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
525 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
530 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
537 * Set the message queue to @a mq for peer @a cp and notify watchers.
539 * @param cp peer to modify
540 * @param mq message queue to set (can be NULL)
543 GCP_set_mq (struct CadetPeer *cp,
544 struct GNUNET_MQ_Handle *mq)
546 LOG (GNUNET_ERROR_TYPE_DEBUG,
547 "Message queue for peer %s is now %p\n",
551 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
555 /* Save next pointer in case mqm gets freed by the callback */
559 if (NULL != mqm->env)
561 GNUNET_MQ_discard (mqm->env);
563 mqm->cb (mqm->cb_cls,
568 mqm->cb (mqm->cb_cls,
574 GNUNET_assert (NULL == mqm->env);
575 mqm->cb (mqm->cb_cls,
581 consider_peer_activate (cp);
583 consider_peer_destroy (cp);
588 /* have a new, direct path to the target, notify tunnel */
589 struct CadetPeerPath *path;
591 path = GCPP_get_path_from_route (1,
593 GCT_consider_path (cp->t,
601 * Debug function should NEVER return true in production code, useful to
602 * simulate losses for testcases.
604 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
609 if (0 == drop_percent)
611 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
619 * Function called when CORE took one of the messages from
620 * a message queue manager and transmitted it.
622 * @param cls the `struct CadetPeeer` where we made progress
625 mqm_send_done (void *cls);
629 * Transmit current envelope from this @a mqm.
631 * @param mqm mqm to transmit message for now
634 mqm_execute (struct GCP_MessageQueueManager *mqm)
636 struct CadetPeer *cp = mqm->cp;
638 /* Move ready pointer to the next entry that might be ready. */
639 if ( (mqm == cp->mqm_ready_ptr) &&
640 (NULL != mqm->next) )
641 cp->mqm_ready_ptr = mqm->next;
642 /* Move entry to the end of the DLL, to be fair. */
643 if (mqm != cp->mqm_tail)
645 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
648 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
652 cp->mqm_ready_counter--;
653 if (GNUNET_YES == should_I_drop ())
655 LOG (GNUNET_ERROR_TYPE_DEBUG,
656 "DROPPING message to peer %s from MQM %p\n",
659 GNUNET_MQ_discard (mqm->env);
666 const struct GNUNET_MessageHeader *mh;
668 mh = GNUNET_MQ_env_get_msg (mqm->env);
669 switch (ntohs (mh->type))
671 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
673 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
674 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
675 LOG (GNUNET_ERROR_TYPE_DEBUG,
676 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
677 GNUNET_e2s (&msg->ephemeral_key),
679 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
686 LOG (GNUNET_ERROR_TYPE_DEBUG,
687 "Sending to peer %s from MQM %p\n",
690 GNUNET_MQ_send (cp->core_mq,
694 mqm->cb (mqm->cb_cls,
700 * Find the next ready message in the queue (starting
701 * the search from the `cp->mqm_ready_ptr`) and if possible
702 * execute the transmission.
704 * @param cp peer to try to send the next ready message to
707 send_next_ready (struct CadetPeer *cp)
709 struct GCP_MessageQueueManager *mqm;
711 if (0 == cp->mqm_ready_counter)
713 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
715 cp->mqm_ready_ptr = mqm->next;
717 return; /* nothing to do */
723 * Function called when CORE took one of the messages from
724 * a message queue manager and transmitted it.
726 * @param cls the `struct CadetPeeer` where we made progress
729 mqm_send_done (void *cls)
731 struct CadetPeer *cp = cls;
733 LOG (GNUNET_ERROR_TYPE_DEBUG,
734 "Sending to peer %s completed\n",
736 send_next_ready (cp);
741 * Send the message in @a env to @a cp.
743 * @param mqm the message queue manager to use for transmission
744 * @param env envelope with the message to send; must NOT
745 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
748 GCP_send (struct GCP_MessageQueueManager *mqm,
749 struct GNUNET_MQ_Envelope *env)
751 struct CadetPeer *cp = mqm->cp;
753 GNUNET_assert (NULL != env);
754 LOG (GNUNET_ERROR_TYPE_DEBUG,
755 "Queueing message to peer %s in MQM %p\n",
758 GNUNET_assert (NULL != cp->core_mq);
759 GNUNET_assert (NULL == mqm->env);
760 GNUNET_MQ_notify_sent (env,
764 cp->mqm_ready_counter++;
765 if (mqm != cp->mqm_ready_ptr)
766 cp->mqm_ready_ptr = cp->mqm_head;
767 if (1 == cp->mqm_ready_counter)
768 cp->mqm_ready_ptr = mqm;
769 if (0 != GNUNET_MQ_get_length (cp->core_mq))
771 send_next_ready (cp);
776 * Function called to destroy a peer now.
779 * @param pid identity of the peer (unused)
780 * @param value the `struct CadetPeer` to clean up
781 * @return #GNUNET_OK (continue to iterate)
784 destroy_iterator_cb (void *cls,
785 const struct GNUNET_PeerIdentity *pid,
788 struct CadetPeer *cp = value;
790 if (NULL != cp->destroy_task)
792 GNUNET_SCHEDULER_cancel (cp->destroy_task);
793 cp->destroy_task = NULL;
801 * Clean up all entries about all peers.
802 * Must only be called after all tunnels, CORE-connections and
803 * connections are down.
806 GCP_destroy_all_peers ()
808 LOG (GNUNET_ERROR_TYPE_DEBUG,
809 "Destroying all peers now\n");
810 GNUNET_CONTAINER_multipeermap_iterate (peers,
811 &destroy_iterator_cb,
817 * Drop all paths owned by this peer, and do not
818 * allow new ones to be added: We are shutting down.
820 * @param cp peer to drop paths to
823 GCP_drop_owned_paths (struct CadetPeer *cp)
825 struct CadetPeerPath *path;
827 LOG (GNUNET_ERROR_TYPE_DEBUG,
828 "Destroying all paths to %s\n",
830 while (NULL != (path =
831 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
833 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
834 cp->path_heap = NULL;
839 * Add an entry to the DLL of all of the paths that this peer is on.
841 * @param cp peer to modify
842 * @param entry an entry on a path
843 * @param off offset of this peer on the path
846 GCP_path_entry_add (struct CadetPeer *cp,
847 struct CadetPeerPathEntry *entry,
850 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
852 LOG (GNUNET_ERROR_TYPE_DEBUG,
853 "Discovered that peer %s is on path %s at offset %u\n",
855 GCPP_2s (entry->path),
857 if (off >= cp->path_dll_length)
859 unsigned int len = cp->path_dll_length;
861 GNUNET_array_grow (cp->path_heads,
864 GNUNET_array_grow (cp->path_tails,
868 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
874 /* If we have a tunnel to this peer, tell the tunnel that there is a
875 new path available. */
877 GCT_consider_path (cp->t,
881 if ( (NULL != cp->search_h) &&
882 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
884 /* Now I have enough paths, stop search */
885 GCD_search_stop (cp->search_h);
888 if (NULL != cp->destroy_task)
890 /* paths changed, this resets the destroy timeout counter
891 and aborts a destroy task that may no longer be valid
892 to have (as we now have more paths via this peer). */
893 consider_peer_destroy (cp);
899 * Remove an entry from the DLL of all of the paths that this peer is on.
901 * @param cp peer to modify
902 * @param entry an entry on a path
903 * @param off offset of this peer on the path
906 GCP_path_entry_remove (struct CadetPeer *cp,
907 struct CadetPeerPathEntry *entry,
910 LOG (GNUNET_ERROR_TYPE_DEBUG,
911 "Removing knowledge about peer %s beging on path %s at offset %u\n",
913 GCPP_2s (entry->path),
915 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
918 GNUNET_assert (0 < cp->num_paths);
921 if ( (NULL == cp->core_mq) &&
923 (NULL == cp->search_h) &&
924 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
926 = GCD_search (&cp->pid);
927 if (NULL == cp->destroy_task)
929 /* paths changed, we might now be ready for destruction, check again */
930 consider_peer_destroy (cp);
936 * Prune down the number of paths to this peer, we seem to
939 * @param cls the `struct CadetPeer` to maintain the path heap for
942 path_heap_cleanup (void *cls)
944 struct CadetPeer *cp = cls;
945 struct CadetPeerPath *root;
947 cp->heap_cleanup_task = NULL;
948 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
949 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
951 /* Now we have way too many, drop least desirable UNLESS it is in use!
952 (Note that this intentionally keeps highly desireable, but currently
953 unused paths around in the hope that we might be able to switch, even
954 if the number of paths exceeds the threshold.) */
955 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
956 GNUNET_assert (NULL != root);
958 GCPP_get_connection (root,
960 GCPP_get_length (root) - 1))
961 break; /* can't fix */
962 /* Got plenty of paths to this destination, and this is a low-quality
963 one that we don't care about. Allow it to die. */
964 GNUNET_assert (root ==
965 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
972 * Try adding a @a path to this @a peer. If the peer already
973 * has plenty of paths, return NULL.
975 * @param cp peer to which the @a path leads to
976 * @param path a path looking for an owner; may not be fully initialized yet!
977 * @param off offset of @a cp in @a path
978 * @param force force attaching the path
979 * @return NULL if this peer does not care to become a new owner,
980 * otherwise the node in the peer's path heap for the @a path.
982 struct GNUNET_CONTAINER_HeapNode *
983 GCP_attach_path (struct CadetPeer *cp,
984 struct CadetPeerPath *path,
988 GNUNET_CONTAINER_HeapCostType desirability;
989 struct CadetPeerPath *root;
990 GNUNET_CONTAINER_HeapCostType root_desirability;
991 struct GNUNET_CONTAINER_HeapNode *hn;
993 GNUNET_assert (off == GCPP_get_length (path) - 1);
994 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
996 if (NULL == cp->path_heap)
998 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
999 GNUNET_assert (GNUNET_NO == force);
1002 desirability = GCPP_get_desirability (path);
1003 if (GNUNET_NO == force)
1005 /* FIXME: desirability is not yet initialized; tricky! */
1007 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
1009 &root_desirability))
1012 root_desirability = 0;
1015 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1016 (desirability < root_desirability) )
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "Decided to not attach path %s to peer %s due to undesirability\n",
1026 LOG (GNUNET_ERROR_TYPE_DEBUG,
1027 "Attaching path %s to peer %s (%s)\n",
1030 (GNUNET_NO == force) ? "desirable" : "forced");
1032 /* Yes, we'd like to add this path, add to our heap */
1033 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1037 /* Consider maybe dropping other paths because of the new one */
1038 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1039 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1040 (NULL != cp->heap_cleanup_task) )
1041 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1048 * This peer can no longer own @a path as the path
1049 * has been extended and a peer further down the line
1050 * is now the new owner.
1052 * @param cp old owner of the @a path
1053 * @param path path where the ownership is lost
1054 * @param hn note in @a cp's path heap that must be deleted
1057 GCP_detach_path (struct CadetPeer *cp,
1058 struct CadetPeerPath *path,
1059 struct GNUNET_CONTAINER_HeapNode *hn)
1061 LOG (GNUNET_ERROR_TYPE_DEBUG,
1062 "Detatching path %s from peer %s\n",
1065 GNUNET_assert (path ==
1066 GNUNET_CONTAINER_heap_remove_node (hn));
1071 * Add a @a connection to this @a cp.
1073 * @param cp peer via which the @a connection goes
1074 * @param cc the connection to add
1077 GCP_add_connection (struct CadetPeer *cp,
1078 struct CadetConnection *cc)
1080 LOG (GNUNET_ERROR_TYPE_DEBUG,
1081 "Adding %s to peer %s\n",
1084 GNUNET_assert (GNUNET_OK ==
1085 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1086 &GCC_get_id (cc)->connection_of_tunnel,
1088 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1089 if (NULL != cp->destroy_task)
1091 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1092 cp->destroy_task = NULL;
1098 * Remove a @a connection that went via this @a cp.
1100 * @param cp peer via which the @a connection went
1101 * @param cc the connection to remove
1104 GCP_remove_connection (struct CadetPeer *cp,
1105 struct CadetConnection *cc)
1107 LOG (GNUNET_ERROR_TYPE_DEBUG,
1108 "Removing connection %s from peer %s\n",
1111 GNUNET_assert (GNUNET_YES ==
1112 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1113 &GCC_get_id (cc)->connection_of_tunnel,
1115 consider_peer_destroy (cp);
1120 * Retrieve the CadetPeer stucture associated with the
1121 * peer. Optionally create one and insert it in the appropriate
1122 * structures if the peer is not known yet.
1124 * @param peer_id Full identity of the peer.
1125 * @param create #GNUNET_YES if a new peer should be created if unknown.
1126 * #GNUNET_NO to return NULL if peer is unknown.
1127 * @return Existing or newly created peer structure.
1128 * NULL if unknown and not requested @a create
1131 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1134 struct CadetPeer *cp;
1136 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1140 if (GNUNET_NO == create)
1142 cp = GNUNET_new (struct CadetPeer);
1144 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1146 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1147 GNUNET_assert (GNUNET_YES ==
1148 GNUNET_CONTAINER_multipeermap_put (peers,
1151 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1152 LOG (GNUNET_ERROR_TYPE_DEBUG,
1153 "Creating peer %s\n",
1160 * Obtain the peer identity for a `struct CadetPeer`.
1162 * @param cp our peer handle
1163 * @return the peer identity
1165 const struct GNUNET_PeerIdentity *
1166 GCP_get_id (struct CadetPeer *cp)
1173 * Iterate over all known peers.
1175 * @param iter Iterator.
1176 * @param cls Closure for @c iter.
1179 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1182 GNUNET_CONTAINER_multipeermap_iterate (peers,
1189 * Count the number of known paths toward the peer.
1191 * @param cp Peer to get path info.
1192 * @return Number of known paths.
1195 GCP_count_paths (const struct CadetPeer *cp)
1197 return cp->num_paths;
1202 * Iterate over the paths to a peer.
1204 * @param cp Peer to get path info.
1205 * @param callback Function to call for every path.
1206 * @param callback_cls Closure for @a callback.
1207 * @return Number of iterated paths.
1210 GCP_iterate_paths (struct CadetPeer *cp,
1211 GCP_PathIterator callback,
1214 unsigned int ret = 0;
1216 LOG (GNUNET_ERROR_TYPE_DEBUG,
1217 "Iterating over paths to peer %s%s\n",
1219 (NULL == cp->core_mq) ? "" : " including direct link");
1220 if (NULL != cp->core_mq)
1222 /* FIXME: this branch seems to duplicate the
1223 i=0 case below (direct link). Leave out!??? -CG */
1224 struct CadetPeerPath *path;
1226 path = GCPP_get_path_from_route (1,
1230 callback (callback_cls,
1235 for (unsigned int i=0;i<cp->path_dll_length;i++)
1237 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1243 callback (callback_cls,
1253 * Iterate over the paths to a peer without direct link.
1255 * @param cp Peer to get path info.
1256 * @param callback Function to call for every path.
1257 * @param callback_cls Closure for @a callback.
1258 * @return Number of iterated paths.
1261 GCP_iterate_indirect_paths (struct CadetPeer *cp,
1262 GCP_PathIterator callback,
1265 unsigned int ret = 0;
1267 LOG (GNUNET_ERROR_TYPE_DEBUG,
1268 "Iterating over paths to peer %s without direct link\n",
1270 for (unsigned int i=1;i<cp->path_dll_length;i++)
1272 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1278 callback (callback_cls,
1289 * Iterate over the paths to @a cp where
1290 * @a cp is at distance @a dist from us.
1292 * @param cp Peer to get path info.
1293 * @param dist desired distance of @a cp to us on the path
1294 * @param callback Function to call for every path.
1295 * @param callback_cls Closure for @a callback.
1296 * @return Number of iterated paths.
1299 GCP_iterate_paths_at (struct CadetPeer *cp,
1301 GCP_PathIterator callback,
1304 unsigned int ret = 0;
1306 if (dist >= cp->path_dll_length)
1308 LOG (GNUNET_ERROR_TYPE_DEBUG,
1309 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1311 cp->path_dll_length);
1314 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1319 callback (callback_cls,
1330 * Get the tunnel towards a peer.
1332 * @param cp Peer to get from.
1333 * @param create #GNUNET_YES to create a tunnel if we do not have one
1334 * @return Tunnel towards peer.
1336 struct CadetTunnel *
1337 GCP_get_tunnel (struct CadetPeer *cp,
1342 if ( (NULL != cp->t) ||
1343 (GNUNET_NO == create) )
1345 cp->t = GCT_create_tunnel (cp);
1346 consider_peer_activate (cp);
1352 * Hello offer was passed to the transport service. Mark it
1355 * @param cls the `struct CadetPeer` where the offer completed
1358 hello_offer_done (void *cls)
1360 struct CadetPeer *cp = cls;
1362 cp->hello_offer = NULL;
1367 * We got a HELLO for a @a peer, remember it, and possibly
1368 * trigger adequate actions (like trying to connect).
1370 * @param cp the peer we got a HELLO for
1371 * @param hello the HELLO to remember
1374 GCP_set_hello (struct CadetPeer *cp,
1375 const struct GNUNET_HELLO_Message *hello)
1377 struct GNUNET_HELLO_Message *mrg;
1379 LOG (GNUNET_ERROR_TYPE_DEBUG,
1380 "Got %u byte HELLO for peer %s\n",
1381 (unsigned int) GNUNET_HELLO_size (hello),
1383 if (NULL != cp->hello_offer)
1385 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1386 cp->hello_offer = NULL;
1388 if (NULL != cp->hello)
1390 mrg = GNUNET_HELLO_merge (hello,
1392 GNUNET_free (cp->hello);
1397 cp->hello = GNUNET_memdup (hello,
1398 GNUNET_HELLO_size (hello));
1401 = GNUNET_TRANSPORT_offer_hello (cfg,
1402 GNUNET_HELLO_get_header (cp->hello) ,
1405 /* New HELLO means cp's destruction time may change... */
1406 consider_peer_destroy (cp);
1411 * The tunnel to the given peer no longer exists, remove it from our
1412 * data structures, and possibly clean up the peer itself.
1414 * @param cp the peer affected
1415 * @param t the dead tunnel
1418 GCP_drop_tunnel (struct CadetPeer *cp,
1419 struct CadetTunnel *t)
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "Dropping tunnel %s to peer %s\n",
1425 GNUNET_assert (cp->t == t);
1427 consider_peer_destroy (cp);
1432 * Test if @a cp has a core-level connection
1434 * @param cp peer to test
1435 * @return #GNUNET_YES if @a cp has a core-level connection
1438 GCP_has_core_connection (struct CadetPeer *cp)
1440 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1445 * Start message queue change notifications.
1447 * @param cp peer to notify for
1448 * @param cb function to call if mq becomes available or unavailable
1449 * @param cb_cls closure for @a cb
1450 * @return handle to cancel request
1452 struct GCP_MessageQueueManager *
1453 GCP_request_mq (struct CadetPeer *cp,
1454 GCP_MessageQueueNotificationCallback cb,
1457 struct GCP_MessageQueueManager *mqm;
1459 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1461 mqm->cb_cls = cb_cls;
1463 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1466 LOG (GNUNET_ERROR_TYPE_DEBUG,
1467 "Creating MQM %p for peer %s\n",
1470 if (NULL != cp->core_mq)
1478 * Stops message queue change notifications.
1480 * @param mqm handle matching request to cancel
1481 * @param last_env final message to transmit, or NULL
1484 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1485 struct GNUNET_MQ_Envelope *last_env)
1487 struct CadetPeer *cp = mqm->cp;
1489 LOG (GNUNET_ERROR_TYPE_DEBUG,
1490 "Destroying MQM %p for peer %s%s\n",
1493 (NULL == last_env) ? "" : " with last ditch transmission");
1494 if (NULL != mqm->env)
1495 GNUNET_MQ_discard (mqm->env);
1496 if (NULL != last_env)
1498 if (NULL != cp->core_mq)
1500 GNUNET_MQ_notify_sent (last_env,
1503 GNUNET_MQ_send (cp->core_mq,
1508 GNUNET_MQ_discard (last_env);
1511 if (cp->mqm_ready_ptr == mqm)
1512 cp->mqm_ready_ptr = mqm->next;
1513 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1521 * Send the message in @a env to @a cp, overriding queueing logic.
1522 * This function should only be used to send error messages outside
1523 * of flow and congestion control, similar to ICMP. Note that
1524 * the envelope may be silently discarded as well.
1526 * @param cp peer to send the message to
1527 * @param env envelope with the message to send
1530 GCP_send_ooo (struct CadetPeer *cp,
1531 struct GNUNET_MQ_Envelope *env)
1533 LOG (GNUNET_ERROR_TYPE_DEBUG,
1534 "Sending message to %s out of management\n",
1536 if (NULL == cp->core_mq)
1538 GNUNET_MQ_discard (env);
1541 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1543 GNUNET_MQ_discard (env);
1546 GNUNET_MQ_notify_sent (env,
1549 GNUNET_MQ_send (cp->core_mq,
1556 /* end of gnunet-service-cadet-new_peer.c */