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/>.
20 * @file cadet/gnunet-service-cadet_peer.c
21 * @brief Information we track per peer.
22 * @author Bartlomiej Polot
23 * @author Christian Grothoff
26 * - optimize stopping/restarting DHT search to situations
27 * where we actually need it (i.e. not if we have a direct connection,
28 * or if we already have plenty of good short ones, or maybe even
29 * to take a break if we have some connections and have searched a lot (?))
32 #include "gnunet_util_lib.h"
33 #include "gnunet_hello_lib.h"
34 #include "gnunet_signatures.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_ats_service.h"
37 #include "gnunet_core_service.h"
38 #include "gnunet_statistics_service.h"
39 #include "cadet_protocol.h"
40 #include "gnunet-service-cadet_connection.h"
41 #include "gnunet-service-cadet_dht.h"
42 #include "gnunet-service-cadet_peer.h"
43 #include "gnunet-service-cadet_paths.h"
44 #include "gnunet-service-cadet_tunnels.h"
47 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
51 * How long do we wait until tearing down an idle peer?
53 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
56 * How long do we keep paths around if we no longer care about the peer?
58 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
61 * Queue size when we start dropping OOO messages.
63 #define MAX_OOO_QUEUE_SIZE 100
67 * Data structure used to track whom we have to notify about changes
68 * to our message queue.
70 struct GCP_MessageQueueManager
76 struct GCP_MessageQueueManager *next;
81 struct GCP_MessageQueueManager *prev;
84 * Function to call with updated message queue object.
86 GCP_MessageQueueNotificationCallback cb;
94 * The peer this is for.
99 * Envelope this manager would like to transmit once it is its turn.
101 struct GNUNET_MQ_Envelope *env;
107 * Struct containing all information regarding a given peer
114 struct GNUNET_PeerIdentity pid;
117 * Last time we heard from this peer (currently not used!)
119 struct GNUNET_TIME_Absolute last_contactXXX;
122 * Array of DLLs of paths traversing the peer, organized by the
123 * offset of the peer on the larger path.
125 struct CadetPeerPathEntry **path_heads;
128 * Array of DLL of paths traversing the peer, organized by the
129 * offset of the peer on the larger path.
131 struct CadetPeerPathEntry **path_tails;
134 * Notifications to call when @e core_mq changes.
136 struct GCP_MessageQueueManager *mqm_head;
139 * Notifications to call when @e core_mq changes.
141 struct GCP_MessageQueueManager *mqm_tail;
144 * Pointer to first "ready" entry in @e mqm_head.
146 struct GCP_MessageQueueManager *mqm_ready_ptr;
149 * MIN-heap of paths owned by this peer (they also end at this
150 * peer). Ordered by desirability.
152 struct GNUNET_CONTAINER_Heap *path_heap;
155 * Handle to stop the DHT search for paths to this peer
157 struct GCD_search_handle *search_h;
160 * Task to clean up @e path_heap asynchronously.
162 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
165 * Task to destroy this entry.
167 struct GNUNET_SCHEDULER_Task *destroy_task;
170 * Tunnel to this peer, if any.
172 struct CadetTunnel *t;
175 * Connections that go through this peer; indexed by tid.
177 struct GNUNET_CONTAINER_MultiShortmap *connections;
180 * Handle for core transmissions.
182 struct GNUNET_MQ_Handle *core_mq;
185 * Hello message of the peer.
187 struct GNUNET_HELLO_Message *hello;
190 * Handle to us offering the HELLO to the transport.
192 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
195 * Handle to our ATS request asking ATS to suggest an address
196 * to TRANSPORT for this peer (to establish a direct link).
198 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
201 * How many messages are in the queue to this peer.
203 unsigned int queue_n;
206 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
208 unsigned int num_paths;
211 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
212 * Used to speed-up @GCP_get_desirability_of_path() calculation.
214 unsigned int off_sum;
217 * Number of message queue managers of this peer that have a message in waiting.
219 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
220 * TODO: could be replaced by another DLL that would then allow us to avoid
221 * the O(n)-scan of the DLL for ready entries!
223 unsigned int mqm_ready_counter;
226 * Current length of the @e path_heads and @path_tails arrays.
227 * The arrays should be grown as needed.
229 unsigned int path_dll_length;
235 * Get the static string for a peer ID.
238 * @return Static string for it's ID.
241 GCP_2s (const struct CadetPeer *cp)
246 if (NULL == cp || NULL == &cp->pid.public_key)
248 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
261 * Calculate how desirable a path is for @a cp if @a cp
262 * is at offset @a off.
264 * The 'desirability_table.c' program can be used to compute a list of
265 * sample outputs for different scenarios. Basically, we score paths
266 * lower if there are many alternatives, and higher if they are
267 * shorter than average, and very high if they are much shorter than
268 * average and without many alternatives.
270 * @param cp a peer reachable via a path
271 * @param off offset of @a cp in the path
272 * @return score how useful a path is to reach @a cp,
273 * positive scores mean path is more desirable
276 GCP_get_desirability_of_path (struct CadetPeer *cp,
279 unsigned int num_alts = cp->num_paths;
280 unsigned int off_sum;
285 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
286 GNUNET_assert (0 != cp->path_dll_length);
288 /* We maintain 'off_sum' in 'peer' and thereby
289 avoid the SLOW recalculation each time. Kept here
290 just to document what is going on. */
293 for (unsigned int j=0;j<cp->path_dll_length;j++)
294 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
298 GNUNET_assert (off_sum == cp->off_sum);
300 off_sum = cp->off_sum;
302 avg_sum = off_sum * 1.0 / cp->path_dll_length;
303 path_delta = off - avg_sum;
304 /* path_delta positiv: path off of peer above average (bad path for peer),
305 path_delta negativ: path off of peer below average (good path for peer) */
306 if (path_delta <= - 1.0)
307 weight_alts = - num_alts / path_delta; /* discount alternative paths */
308 else if (path_delta >= 1.0)
309 weight_alts = num_alts * path_delta; /* overcount alternative paths */
311 weight_alts = num_alts; /* count alternative paths normally */
314 /* off+1: long paths are generally harder to find and thus count
315 a bit more as they get longer. However, above-average paths
316 still need to count less, hence the squaring of that factor. */
317 return (off + 1.0) / (weight_alts * weight_alts);
322 * This peer is no longer be needed, clean it up now.
324 * @param cls peer to clean up
327 destroy_peer (void *cls)
329 struct CadetPeer *cp = cls;
331 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "Destroying state about peer %s\n",
334 cp->destroy_task = NULL;
335 GNUNET_assert (NULL == cp->t);
336 GNUNET_assert (NULL == cp->core_mq);
337 GNUNET_assert (0 == cp->num_paths);
338 for (unsigned int i=0;i<cp->path_dll_length;i++)
339 GNUNET_assert (NULL == cp->path_heads[i]);
340 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
341 GNUNET_assert (GNUNET_YES ==
342 GNUNET_CONTAINER_multipeermap_remove (peers,
345 GNUNET_free_non_null (cp->path_heads);
346 GNUNET_free_non_null (cp->path_tails);
347 cp->path_dll_length = 0;
348 if (NULL != cp->search_h)
350 GCD_search_stop (cp->search_h);
353 /* FIXME: clean up search_delayedXXX! */
355 if (NULL != cp->hello_offer)
357 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
358 cp->hello_offer = NULL;
360 if (NULL != cp->connectivity_suggestion)
362 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
363 cp->connectivity_suggestion = NULL;
365 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
366 if (NULL != cp->path_heap)
368 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
369 cp->path_heap = NULL;
371 if (NULL != cp->heap_cleanup_task)
373 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
374 cp->heap_cleanup_task = NULL;
376 GNUNET_free_non_null (cp->hello);
377 /* Peer should not be freed if paths exist; if there are no paths,
378 there ought to be no connections, and without connections, no
379 notifications. Thus we can assert that mqm_head is empty at this
381 GNUNET_assert (NULL == cp->mqm_head);
382 GNUNET_assert (NULL == cp->mqm_ready_ptr);
388 * This peer is now on more "active" duty, activate processes related to it.
390 * @param cp the more-active peer
393 consider_peer_activate (struct CadetPeer *cp)
397 LOG (GNUNET_ERROR_TYPE_DEBUG,
398 "Updating peer %s activation state (%u connections)%s%s\n",
400 GNUNET_CONTAINER_multishortmap_size (cp->connections),
401 (NULL == cp->t) ? "" : " with tunnel",
402 (NULL == cp->core_mq) ? "" : " with CORE link");
403 if (NULL != cp->destroy_task)
405 /* It's active, do not destory! */
406 GNUNET_SCHEDULER_cancel (cp->destroy_task);
407 cp->destroy_task = NULL;
409 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
412 /* We're just on a path or directly connected; don't bother too much */
413 if (NULL != cp->connectivity_suggestion)
415 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
416 cp->connectivity_suggestion = NULL;
418 if (NULL != cp->search_h)
420 GCD_search_stop (cp->search_h);
425 if (NULL == cp->core_mq)
427 /* Lacks direct connection, try to create one by querying the DHT */
428 if ( (NULL == cp->search_h) &&
429 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
431 = GCD_search (&cp->pid);
435 /* Have direct connection, stop DHT search if active */
436 if (NULL != cp->search_h)
438 GCD_search_stop (cp->search_h);
443 /* If we have a tunnel, our urge for connections is much bigger */
444 strength = (NULL != cp->t) ? 32 : 1;
445 if (NULL != cp->connectivity_suggestion)
446 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
447 cp->connectivity_suggestion
448 = GNUNET_ATS_connectivity_suggest (ats_ch,
455 * This peer may no longer be needed, consider cleaning it up.
457 * @param cp peer to clean up
460 consider_peer_destroy (struct CadetPeer *cp);
464 * We really no longere care about a peer, stop hogging memory with paths to it.
465 * Afterwards, see if there is more to be cleaned up about this peer.
467 * @param cls a `struct CadetPeer`.
470 drop_paths (void *cls)
472 struct CadetPeer *cp = cls;
473 struct CadetPeerPath *path;
475 cp->destroy_task = NULL;
476 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
478 consider_peer_destroy (cp);
483 * This peer may no longer be needed, consider cleaning it up.
485 * @param cp peer to clean up
488 consider_peer_destroy (struct CadetPeer *cp)
490 struct GNUNET_TIME_Relative exp;
492 if (NULL != cp->destroy_task)
494 GNUNET_SCHEDULER_cancel (cp->destroy_task);
495 cp->destroy_task = NULL;
498 return; /* still relevant! */
499 if (NULL != cp->core_mq)
500 return; /* still relevant! */
501 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
502 return; /* still relevant! */
503 if ( (NULL != cp->path_heap) &&
504 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
506 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
511 if (0 != cp->num_paths)
512 return; /* still relevant! */
513 if (NULL != cp->hello)
515 /* relevant only until HELLO expires */
516 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
517 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
522 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
529 * Set the message queue to @a mq for peer @a cp and notify watchers.
531 * @param cp peer to modify
532 * @param mq message queue to set (can be NULL)
535 GCP_set_mq (struct CadetPeer *cp,
536 struct GNUNET_MQ_Handle *mq)
538 LOG (GNUNET_ERROR_TYPE_DEBUG,
539 "Message queue for peer %s is now %p\n",
543 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
547 /* Save next pointer in case mqm gets freed by the callback */
551 if (NULL != mqm->env)
553 GNUNET_MQ_discard (mqm->env);
555 mqm->cb (mqm->cb_cls,
560 mqm->cb (mqm->cb_cls,
566 GNUNET_assert (NULL == mqm->env);
567 mqm->cb (mqm->cb_cls,
573 consider_peer_activate (cp);
575 consider_peer_destroy (cp);
580 /* have a new, direct path to the target, notify tunnel */
581 struct CadetPeerPath *path;
583 path = GCPP_get_path_from_route (1,
585 GCT_consider_path (cp->t,
593 * Debug function should NEVER return true in production code, useful to
594 * simulate losses for testcases.
596 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
601 if (0 == drop_percent)
603 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
611 * Function called when CORE took one of the messages from
612 * a message queue manager and transmitted it.
614 * @param cls the `struct CadetPeeer` where we made progress
617 mqm_send_done (void *cls);
621 * Transmit current envelope from this @a mqm.
623 * @param mqm mqm to transmit message for now
626 mqm_execute (struct GCP_MessageQueueManager *mqm)
628 struct CadetPeer *cp = mqm->cp;
630 /* Move ready pointer to the next entry that might be ready. */
631 if ( (mqm == cp->mqm_ready_ptr) &&
632 (NULL != mqm->next) )
633 cp->mqm_ready_ptr = mqm->next;
634 /* Move entry to the end of the DLL, to be fair. */
635 if (mqm != cp->mqm_tail)
637 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
640 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
644 cp->mqm_ready_counter--;
645 if (GNUNET_YES == should_I_drop ())
647 LOG (GNUNET_ERROR_TYPE_DEBUG,
648 "DROPPING message to peer %s from MQM %p\n",
651 GNUNET_MQ_discard (mqm->env);
658 const struct GNUNET_MessageHeader *mh;
660 mh = GNUNET_MQ_env_get_msg (mqm->env);
661 switch (ntohs (mh->type))
663 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
665 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
666 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
667 LOG (GNUNET_ERROR_TYPE_DEBUG,
668 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
669 GNUNET_e2s (&msg->ephemeral_key),
671 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
678 LOG (GNUNET_ERROR_TYPE_DEBUG,
679 "Sending to peer %s from MQM %p\n",
682 GNUNET_MQ_send (cp->core_mq,
686 mqm->cb (mqm->cb_cls,
692 * Find the next ready message in the queue (starting
693 * the search from the `cp->mqm_ready_ptr`) and if possible
694 * execute the transmission.
696 * @param cp peer to try to send the next ready message to
699 send_next_ready (struct CadetPeer *cp)
701 struct GCP_MessageQueueManager *mqm;
703 if (0 == cp->mqm_ready_counter)
705 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
707 cp->mqm_ready_ptr = mqm->next;
709 return; /* nothing to do */
715 * Function called when CORE took one of the messages from
716 * a message queue manager and transmitted it.
718 * @param cls the `struct CadetPeeer` where we made progress
721 mqm_send_done (void *cls)
723 struct CadetPeer *cp = cls;
725 LOG (GNUNET_ERROR_TYPE_DEBUG,
726 "Sending to peer %s completed\n",
728 send_next_ready (cp);
733 * Send the message in @a env to @a cp.
735 * @param mqm the message queue manager to use for transmission
736 * @param env envelope with the message to send; must NOT
737 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
740 GCP_send (struct GCP_MessageQueueManager *mqm,
741 struct GNUNET_MQ_Envelope *env)
743 struct CadetPeer *cp = mqm->cp;
745 GNUNET_assert (NULL != env);
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Queueing message to peer %s in MQM %p\n",
750 GNUNET_assert (NULL != cp->core_mq);
751 GNUNET_assert (NULL == mqm->env);
752 GNUNET_MQ_notify_sent (env,
756 cp->mqm_ready_counter++;
757 if (mqm != cp->mqm_ready_ptr)
758 cp->mqm_ready_ptr = cp->mqm_head;
759 if (1 == cp->mqm_ready_counter)
760 cp->mqm_ready_ptr = mqm;
761 if (0 != GNUNET_MQ_get_length (cp->core_mq))
763 send_next_ready (cp);
768 * Function called to destroy a peer now.
771 * @param pid identity of the peer (unused)
772 * @param value the `struct CadetPeer` to clean up
773 * @return #GNUNET_OK (continue to iterate)
776 destroy_iterator_cb (void *cls,
777 const struct GNUNET_PeerIdentity *pid,
780 struct CadetPeer *cp = value;
782 if (NULL != cp->destroy_task)
784 GNUNET_SCHEDULER_cancel (cp->destroy_task);
785 cp->destroy_task = NULL;
793 * Clean up all entries about all peers.
794 * Must only be called after all tunnels, CORE-connections and
795 * connections are down.
798 GCP_destroy_all_peers ()
800 LOG (GNUNET_ERROR_TYPE_DEBUG,
801 "Destroying all peers now\n");
802 GNUNET_CONTAINER_multipeermap_iterate (peers,
803 &destroy_iterator_cb,
809 * Drop all paths owned by this peer, and do not
810 * allow new ones to be added: We are shutting down.
812 * @param cp peer to drop paths to
815 GCP_drop_owned_paths (struct CadetPeer *cp)
817 struct CadetPeerPath *path;
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
820 "Destroying all paths to %s\n",
822 while (NULL != (path =
823 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
825 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
826 cp->path_heap = NULL;
831 * Add an entry to the DLL of all of the paths that this peer is on.
833 * @param cp peer to modify
834 * @param entry an entry on a path
835 * @param off offset of this peer on the path
838 GCP_path_entry_add (struct CadetPeer *cp,
839 struct CadetPeerPathEntry *entry,
842 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
844 LOG (GNUNET_ERROR_TYPE_DEBUG,
845 "Discovered that peer %s is on path %s at offset %u\n",
847 GCPP_2s (entry->path),
849 if (off >= cp->path_dll_length)
851 unsigned int len = cp->path_dll_length;
853 GNUNET_array_grow (cp->path_heads,
856 GNUNET_array_grow (cp->path_tails,
860 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
866 /* If we have a tunnel to this peer, tell the tunnel that there is a
867 new path available. */
869 GCT_consider_path (cp->t,
873 if ( (NULL != cp->search_h) &&
874 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
876 /* Now I have enough paths, stop search */
877 GCD_search_stop (cp->search_h);
880 if (NULL != cp->destroy_task)
882 /* paths changed, this resets the destroy timeout counter
883 and aborts a destroy task that may no longer be valid
884 to have (as we now have more paths via this peer). */
885 consider_peer_destroy (cp);
891 * Remove an entry from the DLL of all of the paths that this peer is on.
893 * @param cp peer to modify
894 * @param entry an entry on a path
895 * @param off offset of this peer on the path
898 GCP_path_entry_remove (struct CadetPeer *cp,
899 struct CadetPeerPathEntry *entry,
902 LOG (GNUNET_ERROR_TYPE_DEBUG,
903 "Removing knowledge about peer %s beging on path %s at offset %u\n",
905 GCPP_2s (entry->path),
907 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
910 GNUNET_assert (0 < cp->num_paths);
913 if ( (NULL == cp->core_mq) &&
915 (NULL == cp->search_h) &&
916 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
918 = GCD_search (&cp->pid);
919 if (NULL == cp->destroy_task)
921 /* paths changed, we might now be ready for destruction, check again */
922 consider_peer_destroy (cp);
928 * Prune down the number of paths to this peer, we seem to
931 * @param cls the `struct CadetPeer` to maintain the path heap for
934 path_heap_cleanup (void *cls)
936 struct CadetPeer *cp = cls;
937 struct CadetPeerPath *root;
939 cp->heap_cleanup_task = NULL;
940 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
941 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
943 /* Now we have way too many, drop least desirable UNLESS it is in use!
944 (Note that this intentionally keeps highly desireable, but currently
945 unused paths around in the hope that we might be able to switch, even
946 if the number of paths exceeds the threshold.) */
947 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
948 GNUNET_assert (NULL != root);
950 GCPP_get_connection (root,
952 GCPP_get_length (root) - 1))
953 break; /* can't fix */
954 /* Got plenty of paths to this destination, and this is a low-quality
955 one that we don't care about. Allow it to die. */
956 GNUNET_assert (root ==
957 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
964 * Try adding a @a path to this @a peer. If the peer already
965 * has plenty of paths, return NULL.
967 * @param cp peer to which the @a path leads to
968 * @param path a path looking for an owner; may not be fully initialized yet!
969 * @param off offset of @a cp in @a path
970 * @param force force attaching the path
971 * @return NULL if this peer does not care to become a new owner,
972 * otherwise the node in the peer's path heap for the @a path.
974 struct GNUNET_CONTAINER_HeapNode *
975 GCP_attach_path (struct CadetPeer *cp,
976 struct CadetPeerPath *path,
980 GNUNET_CONTAINER_HeapCostType desirability;
981 struct CadetPeerPath *root;
982 GNUNET_CONTAINER_HeapCostType root_desirability;
983 struct GNUNET_CONTAINER_HeapNode *hn;
985 GNUNET_assert (off == GCPP_get_length (path) - 1);
986 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
988 if (NULL == cp->path_heap)
990 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
991 GNUNET_assert (GNUNET_NO == force);
994 desirability = GCPP_get_desirability (path);
995 if (GNUNET_NO == force)
997 /* FIXME: desirability is not yet initialized; tricky! */
999 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
1001 &root_desirability))
1004 root_desirability = 0;
1007 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1008 (desirability < root_desirability) )
1010 LOG (GNUNET_ERROR_TYPE_DEBUG,
1011 "Decided to not attach path %s to peer %s due to undesirability\n",
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "Attaching path %s to peer %s (%s)\n",
1022 (GNUNET_NO == force) ? "desirable" : "forced");
1024 /* Yes, we'd like to add this path, add to our heap */
1025 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1029 /* Consider maybe dropping other paths because of the new one */
1030 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1031 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1032 (NULL != cp->heap_cleanup_task) )
1033 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1040 * This peer can no longer own @a path as the path
1041 * has been extended and a peer further down the line
1042 * is now the new owner.
1044 * @param cp old owner of the @a path
1045 * @param path path where the ownership is lost
1046 * @param hn note in @a cp's path heap that must be deleted
1049 GCP_detach_path (struct CadetPeer *cp,
1050 struct CadetPeerPath *path,
1051 struct GNUNET_CONTAINER_HeapNode *hn)
1053 LOG (GNUNET_ERROR_TYPE_DEBUG,
1054 "Detatching path %s from peer %s\n",
1057 GNUNET_assert (path ==
1058 GNUNET_CONTAINER_heap_remove_node (hn));
1063 * Add a @a connection to this @a cp.
1065 * @param cp peer via which the @a connection goes
1066 * @param cc the connection to add
1069 GCP_add_connection (struct CadetPeer *cp,
1070 struct CadetConnection *cc)
1072 LOG (GNUNET_ERROR_TYPE_DEBUG,
1073 "Adding %s to peer %s\n",
1076 GNUNET_assert (GNUNET_OK ==
1077 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1078 &GCC_get_id (cc)->connection_of_tunnel,
1080 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1081 if (NULL != cp->destroy_task)
1083 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1084 cp->destroy_task = NULL;
1090 * Remove a @a connection that went via this @a cp.
1092 * @param cp peer via which the @a connection went
1093 * @param cc the connection to remove
1096 GCP_remove_connection (struct CadetPeer *cp,
1097 struct CadetConnection *cc)
1099 LOG (GNUNET_ERROR_TYPE_DEBUG,
1100 "Removing connection %s from peer %s\n",
1103 GNUNET_assert (GNUNET_YES ==
1104 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1105 &GCC_get_id (cc)->connection_of_tunnel,
1107 consider_peer_destroy (cp);
1112 * Retrieve the CadetPeer stucture associated with the
1113 * peer. Optionally create one and insert it in the appropriate
1114 * structures if the peer is not known yet.
1116 * @param peer_id Full identity of the peer.
1117 * @param create #GNUNET_YES if a new peer should be created if unknown.
1118 * #GNUNET_NO to return NULL if peer is unknown.
1119 * @return Existing or newly created peer structure.
1120 * NULL if unknown and not requested @a create
1123 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1126 struct CadetPeer *cp;
1128 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1132 if (GNUNET_NO == create)
1134 cp = GNUNET_new (struct CadetPeer);
1136 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1138 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1139 GNUNET_assert (GNUNET_YES ==
1140 GNUNET_CONTAINER_multipeermap_put (peers,
1143 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1144 LOG (GNUNET_ERROR_TYPE_DEBUG,
1145 "Creating peer %s\n",
1152 * Obtain the peer identity for a `struct CadetPeer`.
1154 * @param cp our peer handle
1155 * @return the peer identity
1157 const struct GNUNET_PeerIdentity *
1158 GCP_get_id (struct CadetPeer *cp)
1165 * Iterate over all known peers.
1167 * @param iter Iterator.
1168 * @param cls Closure for @c iter.
1171 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1174 GNUNET_CONTAINER_multipeermap_iterate (peers,
1181 * Count the number of known paths toward the peer.
1183 * @param cp Peer to get path info.
1184 * @return Number of known paths.
1187 GCP_count_paths (const struct CadetPeer *cp)
1189 return cp->num_paths;
1194 * Iterate over the paths to a peer.
1196 * @param cp Peer to get path info.
1197 * @param callback Function to call for every path.
1198 * @param callback_cls Closure for @a callback.
1199 * @return Number of iterated paths.
1202 GCP_iterate_paths (struct CadetPeer *cp,
1203 GCP_PathIterator callback,
1206 unsigned int ret = 0;
1208 LOG (GNUNET_ERROR_TYPE_DEBUG,
1209 "Iterating over paths to peer %s%s\n",
1211 (NULL == cp->core_mq) ? "" : " including direct link");
1212 if (NULL != cp->core_mq)
1214 struct CadetPeerPath *path;
1216 path = GCPP_get_path_from_route (1,
1220 callback (callback_cls,
1225 for (unsigned int i=0;i<cp->path_dll_length;i++)
1227 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1233 callback (callback_cls,
1243 * Iterate over the paths to a peer without direct link.
1245 * @param cp Peer to get path info.
1246 * @param callback Function to call for every path.
1247 * @param callback_cls Closure for @a callback.
1248 * @return Number of iterated paths.
1251 GCP_iterate_indirect_paths (struct CadetPeer *cp,
1252 GCP_PathIterator callback,
1255 unsigned int ret = 0;
1257 LOG (GNUNET_ERROR_TYPE_DEBUG,
1258 "Iterating over paths to peer %s without direct link\n",
1260 for (unsigned int i=1;i<cp->path_dll_length;i++)
1262 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1268 callback (callback_cls,
1279 * Iterate over the paths to @a cp where
1280 * @a cp is at distance @a dist from us.
1282 * @param cp Peer to get path info.
1283 * @param dist desired distance of @a cp to us on the path
1284 * @param callback Function to call for every path.
1285 * @param callback_cls Closure for @a callback.
1286 * @return Number of iterated paths.
1289 GCP_iterate_paths_at (struct CadetPeer *cp,
1291 GCP_PathIterator callback,
1294 unsigned int ret = 0;
1296 if (dist >= cp->path_dll_length)
1298 LOG (GNUNET_ERROR_TYPE_DEBUG,
1299 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1301 cp->path_dll_length);
1304 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1309 callback (callback_cls,
1320 * Get the tunnel towards a peer.
1322 * @param cp Peer to get from.
1323 * @param create #GNUNET_YES to create a tunnel if we do not have one
1324 * @return Tunnel towards peer.
1326 struct CadetTunnel *
1327 GCP_get_tunnel (struct CadetPeer *cp,
1332 if ( (NULL != cp->t) ||
1333 (GNUNET_NO == create) )
1335 cp->t = GCT_create_tunnel (cp);
1336 consider_peer_activate (cp);
1342 * Hello offer was passed to the transport service. Mark it
1345 * @param cls the `struct CadetPeer` where the offer completed
1348 hello_offer_done (void *cls)
1350 struct CadetPeer *cp = cls;
1352 cp->hello_offer = NULL;
1357 * We got a HELLO for a @a peer, remember it, and possibly
1358 * trigger adequate actions (like trying to connect).
1360 * @param cp the peer we got a HELLO for
1361 * @param hello the HELLO to remember
1364 GCP_set_hello (struct CadetPeer *cp,
1365 const struct GNUNET_HELLO_Message *hello)
1367 struct GNUNET_HELLO_Message *mrg;
1369 LOG (GNUNET_ERROR_TYPE_DEBUG,
1370 "Got %u byte HELLO for peer %s\n",
1371 (unsigned int) GNUNET_HELLO_size (hello),
1373 if (NULL != cp->hello_offer)
1375 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1376 cp->hello_offer = NULL;
1378 if (NULL != cp->hello)
1380 mrg = GNUNET_HELLO_merge (hello,
1382 GNUNET_free (cp->hello);
1387 cp->hello = GNUNET_memdup (hello,
1388 GNUNET_HELLO_size (hello));
1391 = GNUNET_TRANSPORT_offer_hello (cfg,
1392 GNUNET_HELLO_get_header (cp->hello) ,
1395 /* New HELLO means cp's destruction time may change... */
1396 consider_peer_destroy (cp);
1401 * The tunnel to the given peer no longer exists, remove it from our
1402 * data structures, and possibly clean up the peer itself.
1404 * @param cp the peer affected
1405 * @param t the dead tunnel
1408 GCP_drop_tunnel (struct CadetPeer *cp,
1409 struct CadetTunnel *t)
1411 LOG (GNUNET_ERROR_TYPE_DEBUG,
1412 "Dropping tunnel %s to peer %s\n",
1415 GNUNET_assert (cp->t == t);
1417 consider_peer_destroy (cp);
1422 * Test if @a cp has a core-level connection
1424 * @param cp peer to test
1425 * @return #GNUNET_YES if @a cp has a core-level connection
1428 GCP_has_core_connection (struct CadetPeer *cp)
1430 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1435 * Start message queue change notifications.
1437 * @param cp peer to notify for
1438 * @param cb function to call if mq becomes available or unavailable
1439 * @param cb_cls closure for @a cb
1440 * @return handle to cancel request
1442 struct GCP_MessageQueueManager *
1443 GCP_request_mq (struct CadetPeer *cp,
1444 GCP_MessageQueueNotificationCallback cb,
1447 struct GCP_MessageQueueManager *mqm;
1449 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1451 mqm->cb_cls = cb_cls;
1453 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1456 LOG (GNUNET_ERROR_TYPE_DEBUG,
1457 "Creating MQM %p for peer %s\n",
1460 if (NULL != cp->core_mq)
1468 * Stops message queue change notifications.
1470 * @param mqm handle matching request to cancel
1471 * @param last_env final message to transmit, or NULL
1474 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1475 struct GNUNET_MQ_Envelope *last_env)
1477 struct CadetPeer *cp = mqm->cp;
1479 LOG (GNUNET_ERROR_TYPE_DEBUG,
1480 "Destroying MQM %p for peer %s%s\n",
1483 (NULL == last_env) ? "" : " with last ditch transmission");
1484 if (NULL != mqm->env)
1485 GNUNET_MQ_discard (mqm->env);
1486 if (NULL != last_env)
1488 if (NULL != cp->core_mq)
1490 GNUNET_MQ_notify_sent (last_env,
1493 GNUNET_MQ_send (cp->core_mq,
1498 GNUNET_MQ_discard (last_env);
1501 if (cp->mqm_ready_ptr == mqm)
1502 cp->mqm_ready_ptr = mqm->next;
1503 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1511 * Send the message in @a env to @a cp, overriding queueing logic.
1512 * This function should only be used to send error messages outside
1513 * of flow and congestion control, similar to ICMP. Note that
1514 * the envelope may be silently discarded as well.
1516 * @param cp peer to send the message to
1517 * @param env envelope with the message to send
1520 GCP_send_ooo (struct CadetPeer *cp,
1521 struct GNUNET_MQ_Envelope *env)
1523 LOG (GNUNET_ERROR_TYPE_DEBUG,
1524 "Sending message to %s out of management\n",
1526 if (NULL == cp->core_mq)
1528 GNUNET_MQ_discard (env);
1531 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1533 GNUNET_MQ_discard (env);
1536 GNUNET_MQ_notify_sent (env,
1539 GNUNET_MQ_send (cp->core_mq,
1546 /* end of gnunet-service-cadet-new_peer.c */