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 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
257 * Calculate how desirable a path is for @a cp if @a cp
258 * is at offset @a off.
260 * The 'desirability_table.c' program can be used to compute a list of
261 * sample outputs for different scenarios. Basically, we score paths
262 * lower if there are many alternatives, and higher if they are
263 * shorter than average, and very high if they are much shorter than
264 * average and without many alternatives.
266 * @param cp a peer reachable via a path
267 * @param off offset of @a cp in the path
268 * @return score how useful a path is to reach @a cp,
269 * positive scores mean path is more desirable
272 GCP_get_desirability_of_path (struct CadetPeer *cp,
275 unsigned int num_alts = cp->num_paths;
276 unsigned int off_sum;
281 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
282 GNUNET_assert (0 != cp->path_dll_length);
284 /* We maintain 'off_sum' in 'peer' and thereby
285 avoid the SLOW recalculation each time. Kept here
286 just to document what is going on. */
289 for (unsigned int j=0;j<cp->path_dll_length;j++)
290 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
294 GNUNET_assert (off_sum == cp->off_sum);
296 off_sum = cp->off_sum;
298 avg_sum = off_sum * 1.0 / cp->path_dll_length;
299 path_delta = off - avg_sum;
300 /* path_delta positiv: path off of peer above average (bad path for peer),
301 path_delta negativ: path off of peer below average (good path for peer) */
302 if (path_delta <= - 1.0)
303 weight_alts = - num_alts / path_delta; /* discount alternative paths */
304 else if (path_delta >= 1.0)
305 weight_alts = num_alts * path_delta; /* overcount alternative paths */
307 weight_alts = num_alts; /* count alternative paths normally */
310 /* off+1: long paths are generally harder to find and thus count
311 a bit more as they get longer. However, above-average paths
312 still need to count less, hence the squaring of that factor. */
313 return (off + 1.0) / (weight_alts * weight_alts);
318 * This peer is no longer be needed, clean it up now.
320 * @param cls peer to clean up
323 destroy_peer (void *cls)
325 struct CadetPeer *cp = cls;
327 LOG (GNUNET_ERROR_TYPE_DEBUG,
328 "Destroying state about peer %s\n",
330 cp->destroy_task = NULL;
331 GNUNET_assert (NULL == cp->t);
332 GNUNET_assert (NULL == cp->core_mq);
333 GNUNET_assert (0 == cp->num_paths);
334 for (unsigned int i=0;i<cp->path_dll_length;i++)
335 GNUNET_assert (NULL == cp->path_heads[i]);
336 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
337 GNUNET_assert (GNUNET_YES ==
338 GNUNET_CONTAINER_multipeermap_remove (peers,
341 GNUNET_free_non_null (cp->path_heads);
342 GNUNET_free_non_null (cp->path_tails);
343 cp->path_dll_length = 0;
344 if (NULL != cp->search_h)
346 GCD_search_stop (cp->search_h);
349 /* FIXME: clean up search_delayedXXX! */
351 if (NULL != cp->hello_offer)
353 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
354 cp->hello_offer = NULL;
356 if (NULL != cp->connectivity_suggestion)
358 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
359 cp->connectivity_suggestion = NULL;
361 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
362 if (NULL != cp->path_heap)
364 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
365 cp->path_heap = NULL;
367 if (NULL != cp->heap_cleanup_task)
369 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
370 cp->heap_cleanup_task = NULL;
372 GNUNET_free_non_null (cp->hello);
373 /* Peer should not be freed if paths exist; if there are no paths,
374 there ought to be no connections, and without connections, no
375 notifications. Thus we can assert that mqm_head is empty at this
377 GNUNET_assert (NULL == cp->mqm_head);
378 GNUNET_assert (NULL == cp->mqm_ready_ptr);
384 * This peer is now on more "active" duty, activate processes related to it.
386 * @param cp the more-active peer
389 consider_peer_activate (struct CadetPeer *cp)
393 LOG (GNUNET_ERROR_TYPE_DEBUG,
394 "Updating peer %s activation state (%u connections)%s%s\n",
396 GNUNET_CONTAINER_multishortmap_size (cp->connections),
397 (NULL == cp->t) ? "" : " with tunnel",
398 (NULL == cp->core_mq) ? "" : " with CORE link");
399 if (NULL != cp->destroy_task)
401 /* It's active, do not destory! */
402 GNUNET_SCHEDULER_cancel (cp->destroy_task);
403 cp->destroy_task = NULL;
405 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
408 /* We're just on a path or directly connected; don't bother too much */
409 if (NULL != cp->connectivity_suggestion)
411 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
412 cp->connectivity_suggestion = NULL;
414 if (NULL != cp->search_h)
416 GCD_search_stop (cp->search_h);
421 if (NULL == cp->core_mq)
423 /* Lacks direct connection, try to create one by querying the DHT */
424 if ( (NULL == cp->search_h) &&
425 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
427 = GCD_search (&cp->pid);
431 /* Have direct connection, stop DHT search if active */
432 if (NULL != cp->search_h)
434 GCD_search_stop (cp->search_h);
439 /* If we have a tunnel, our urge for connections is much bigger */
440 strength = (NULL != cp->t) ? 32 : 1;
441 if (NULL != cp->connectivity_suggestion)
442 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
443 cp->connectivity_suggestion
444 = GNUNET_ATS_connectivity_suggest (ats_ch,
451 * This peer may no longer be needed, consider cleaning it up.
453 * @param cp peer to clean up
456 consider_peer_destroy (struct CadetPeer *cp);
460 * We really no longere care about a peer, stop hogging memory with paths to it.
461 * Afterwards, see if there is more to be cleaned up about this peer.
463 * @param cls a `struct CadetPeer`.
466 drop_paths (void *cls)
468 struct CadetPeer *cp = cls;
469 struct CadetPeerPath *path;
471 cp->destroy_task = NULL;
472 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
474 consider_peer_destroy (cp);
479 * This peer may no longer be needed, consider cleaning it up.
481 * @param cp peer to clean up
484 consider_peer_destroy (struct CadetPeer *cp)
486 struct GNUNET_TIME_Relative exp;
488 if (NULL != cp->destroy_task)
490 GNUNET_SCHEDULER_cancel (cp->destroy_task);
491 cp->destroy_task = NULL;
494 return; /* still relevant! */
495 if (NULL != cp->core_mq)
496 return; /* still relevant! */
497 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
498 return; /* still relevant! */
499 if ( (NULL != cp->path_heap) &&
500 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
502 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
507 if (0 != cp->num_paths)
508 return; /* still relevant! */
509 if (NULL != cp->hello)
511 /* relevant only until HELLO expires */
512 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
513 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
518 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
525 * Set the message queue to @a mq for peer @a cp and notify watchers.
527 * @param cp peer to modify
528 * @param mq message queue to set (can be NULL)
531 GCP_set_mq (struct CadetPeer *cp,
532 struct GNUNET_MQ_Handle *mq)
534 LOG (GNUNET_ERROR_TYPE_DEBUG,
535 "Message queue for peer %s is now %p\n",
539 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
543 /* Save next pointer in case mqm gets freed by the callback */
547 if (NULL != mqm->env)
549 GNUNET_MQ_discard (mqm->env);
551 mqm->cb (mqm->cb_cls,
556 mqm->cb (mqm->cb_cls,
562 GNUNET_assert (NULL == mqm->env);
563 mqm->cb (mqm->cb_cls,
569 consider_peer_activate (cp);
571 consider_peer_destroy (cp);
576 /* have a new, direct path to the target, notify tunnel */
577 struct CadetPeerPath *path;
579 path = GCPP_get_path_from_route (1,
581 GCT_consider_path (cp->t,
589 * Debug function should NEVER return true in production code, useful to
590 * simulate losses for testcases.
592 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
597 if (0 == drop_percent)
599 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
607 * Function called when CORE took one of the messages from
608 * a message queue manager and transmitted it.
610 * @param cls the `struct CadetPeeer` where we made progress
613 mqm_send_done (void *cls);
617 * Transmit current envelope from this @a mqm.
619 * @param mqm mqm to transmit message for now
622 mqm_execute (struct GCP_MessageQueueManager *mqm)
624 struct CadetPeer *cp = mqm->cp;
626 /* Move ready pointer to the next entry that might be ready. */
627 if ( (mqm == cp->mqm_ready_ptr) &&
628 (NULL != mqm->next) )
629 cp->mqm_ready_ptr = mqm->next;
630 /* Move entry to the end of the DLL, to be fair. */
631 if (mqm != cp->mqm_tail)
633 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
636 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
640 cp->mqm_ready_counter--;
641 if (GNUNET_YES == should_I_drop ())
643 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 "DROPPING message to peer %s from MQM %p\n",
647 GNUNET_MQ_discard (mqm->env);
654 const struct GNUNET_MessageHeader *mh;
656 mh = GNUNET_MQ_env_get_msg (mqm->env);
657 switch (ntohs (mh->type))
659 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
661 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
662 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
663 LOG (GNUNET_ERROR_TYPE_DEBUG,
664 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
665 GNUNET_e2s (&msg->ephemeral_key),
667 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
674 LOG (GNUNET_ERROR_TYPE_DEBUG,
675 "Sending to peer %s from MQM %p\n",
678 GNUNET_MQ_send (cp->core_mq,
682 mqm->cb (mqm->cb_cls,
688 * Find the next ready message in the queue (starting
689 * the search from the `cp->mqm_ready_ptr`) and if possible
690 * execute the transmission.
692 * @param cp peer to try to send the next ready message to
695 send_next_ready (struct CadetPeer *cp)
697 struct GCP_MessageQueueManager *mqm;
699 if (0 == cp->mqm_ready_counter)
701 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
703 cp->mqm_ready_ptr = mqm->next;
705 return; /* nothing to do */
711 * Function called when CORE took one of the messages from
712 * a message queue manager and transmitted it.
714 * @param cls the `struct CadetPeeer` where we made progress
717 mqm_send_done (void *cls)
719 struct CadetPeer *cp = cls;
721 LOG (GNUNET_ERROR_TYPE_DEBUG,
722 "Sending to peer %s completed\n",
724 send_next_ready (cp);
729 * Send the message in @a env to @a cp.
731 * @param mqm the message queue manager to use for transmission
732 * @param env envelope with the message to send; must NOT
733 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
736 GCP_send (struct GCP_MessageQueueManager *mqm,
737 struct GNUNET_MQ_Envelope *env)
739 struct CadetPeer *cp = mqm->cp;
741 GNUNET_assert (NULL != env);
742 LOG (GNUNET_ERROR_TYPE_DEBUG,
743 "Queueing message to peer %s in MQM %p\n",
746 GNUNET_assert (NULL != cp->core_mq);
747 GNUNET_assert (NULL == mqm->env);
748 GNUNET_MQ_notify_sent (env,
752 cp->mqm_ready_counter++;
753 if (mqm != cp->mqm_ready_ptr)
754 cp->mqm_ready_ptr = cp->mqm_head;
755 if (1 == cp->mqm_ready_counter)
756 cp->mqm_ready_ptr = mqm;
757 if (0 != GNUNET_MQ_get_length (cp->core_mq))
759 send_next_ready (cp);
764 * Function called to destroy a peer now.
767 * @param pid identity of the peer (unused)
768 * @param value the `struct CadetPeer` to clean up
769 * @return #GNUNET_OK (continue to iterate)
772 destroy_iterator_cb (void *cls,
773 const struct GNUNET_PeerIdentity *pid,
776 struct CadetPeer *cp = value;
778 if (NULL != cp->destroy_task)
780 GNUNET_SCHEDULER_cancel (cp->destroy_task);
781 cp->destroy_task = NULL;
789 * Clean up all entries about all peers.
790 * Must only be called after all tunnels, CORE-connections and
791 * connections are down.
794 GCP_destroy_all_peers ()
796 LOG (GNUNET_ERROR_TYPE_DEBUG,
797 "Destroying all peers now\n");
798 GNUNET_CONTAINER_multipeermap_iterate (peers,
799 &destroy_iterator_cb,
805 * Drop all paths owned by this peer, and do not
806 * allow new ones to be added: We are shutting down.
808 * @param cp peer to drop paths to
811 GCP_drop_owned_paths (struct CadetPeer *cp)
813 struct CadetPeerPath *path;
815 LOG (GNUNET_ERROR_TYPE_DEBUG,
816 "Destroying all paths to %s\n",
818 while (NULL != (path =
819 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
821 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
822 cp->path_heap = NULL;
827 * Add an entry to the DLL of all of the paths that this peer is on.
829 * @param cp peer to modify
830 * @param entry an entry on a path
831 * @param off offset of this peer on the path
834 GCP_path_entry_add (struct CadetPeer *cp,
835 struct CadetPeerPathEntry *entry,
838 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
840 LOG (GNUNET_ERROR_TYPE_DEBUG,
841 "Discovered that peer %s is on path %s at offset %u\n",
843 GCPP_2s (entry->path),
845 if (off >= cp->path_dll_length)
847 unsigned int len = cp->path_dll_length;
849 GNUNET_array_grow (cp->path_heads,
852 GNUNET_array_grow (cp->path_tails,
856 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
862 /* If we have a tunnel to this peer, tell the tunnel that there is a
863 new path available. */
865 GCT_consider_path (cp->t,
869 if ( (NULL != cp->search_h) &&
870 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
872 /* Now I have enough paths, stop search */
873 GCD_search_stop (cp->search_h);
876 if (NULL != cp->destroy_task)
878 /* paths changed, this resets the destroy timeout counter
879 and aborts a destroy task that may no longer be valid
880 to have (as we now have more paths via this peer). */
881 consider_peer_destroy (cp);
887 * Remove an entry from the DLL of all of the paths that this peer is on.
889 * @param cp peer to modify
890 * @param entry an entry on a path
891 * @param off offset of this peer on the path
894 GCP_path_entry_remove (struct CadetPeer *cp,
895 struct CadetPeerPathEntry *entry,
898 LOG (GNUNET_ERROR_TYPE_DEBUG,
899 "Removing knowledge about peer %s beging on path %s at offset %u\n",
901 GCPP_2s (entry->path),
903 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
906 GNUNET_assert (0 < cp->num_paths);
909 if ( (NULL == cp->core_mq) &&
911 (NULL == cp->search_h) &&
912 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
914 = GCD_search (&cp->pid);
915 if (NULL == cp->destroy_task)
917 /* paths changed, we might now be ready for destruction, check again */
918 consider_peer_destroy (cp);
924 * Prune down the number of paths to this peer, we seem to
927 * @param cls the `struct CadetPeer` to maintain the path heap for
930 path_heap_cleanup (void *cls)
932 struct CadetPeer *cp = cls;
933 struct CadetPeerPath *root;
935 cp->heap_cleanup_task = NULL;
936 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
937 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
939 /* Now we have way too many, drop least desirable UNLESS it is in use!
940 (Note that this intentionally keeps highly desireable, but currently
941 unused paths around in the hope that we might be able to switch, even
942 if the number of paths exceeds the threshold.) */
943 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
944 GNUNET_assert (NULL != root);
946 GCPP_get_connection (root,
948 GCPP_get_length (root) - 1))
949 break; /* can't fix */
950 /* Got plenty of paths to this destination, and this is a low-quality
951 one that we don't care about. Allow it to die. */
952 GNUNET_assert (root ==
953 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
960 * Try adding a @a path to this @a peer. If the peer already
961 * has plenty of paths, return NULL.
963 * @param cp peer to which the @a path leads to
964 * @param path a path looking for an owner; may not be fully initialized yet!
965 * @param off offset of @a cp in @a path
966 * @param force force attaching the path
967 * @return NULL if this peer does not care to become a new owner,
968 * otherwise the node in the peer's path heap for the @a path.
970 struct GNUNET_CONTAINER_HeapNode *
971 GCP_attach_path (struct CadetPeer *cp,
972 struct CadetPeerPath *path,
976 GNUNET_CONTAINER_HeapCostType desirability;
977 struct CadetPeerPath *root;
978 GNUNET_CONTAINER_HeapCostType root_desirability;
979 struct GNUNET_CONTAINER_HeapNode *hn;
981 GNUNET_assert (off == GCPP_get_length (path) - 1);
982 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
984 if (NULL == cp->path_heap)
986 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
987 GNUNET_assert (GNUNET_NO == force);
990 desirability = GCPP_get_desirability (path);
991 if (GNUNET_NO == force)
993 /* FIXME: desirability is not yet initialized; tricky! */
995 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
1000 root_desirability = 0;
1003 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1004 (desirability < root_desirability) )
1006 LOG (GNUNET_ERROR_TYPE_DEBUG,
1007 "Decided to not attach path %s to peer %s due to undesirability\n",
1014 LOG (GNUNET_ERROR_TYPE_DEBUG,
1015 "Attaching path %s to peer %s (%s)\n",
1018 (GNUNET_NO == force) ? "desirable" : "forced");
1020 /* Yes, we'd like to add this path, add to our heap */
1021 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1025 /* Consider maybe dropping other paths because of the new one */
1026 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1027 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1028 (NULL != cp->heap_cleanup_task) )
1029 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1036 * This peer can no longer own @a path as the path
1037 * has been extended and a peer further down the line
1038 * is now the new owner.
1040 * @param cp old owner of the @a path
1041 * @param path path where the ownership is lost
1042 * @param hn note in @a cp's path heap that must be deleted
1045 GCP_detach_path (struct CadetPeer *cp,
1046 struct CadetPeerPath *path,
1047 struct GNUNET_CONTAINER_HeapNode *hn)
1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
1050 "Detatching path %s from peer %s\n",
1053 GNUNET_assert (path ==
1054 GNUNET_CONTAINER_heap_remove_node (hn));
1059 * Add a @a connection to this @a cp.
1061 * @param cp peer via which the @a connection goes
1062 * @param cc the connection to add
1065 GCP_add_connection (struct CadetPeer *cp,
1066 struct CadetConnection *cc)
1068 LOG (GNUNET_ERROR_TYPE_DEBUG,
1069 "Adding %s to peer %s\n",
1072 GNUNET_assert (GNUNET_OK ==
1073 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1074 &GCC_get_id (cc)->connection_of_tunnel,
1076 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1077 if (NULL != cp->destroy_task)
1079 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1080 cp->destroy_task = NULL;
1086 * Remove a @a connection that went via this @a cp.
1088 * @param cp peer via which the @a connection went
1089 * @param cc the connection to remove
1092 GCP_remove_connection (struct CadetPeer *cp,
1093 struct CadetConnection *cc)
1095 LOG (GNUNET_ERROR_TYPE_DEBUG,
1096 "Removing connection %s from peer %s\n",
1099 GNUNET_assert (GNUNET_YES ==
1100 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1101 &GCC_get_id (cc)->connection_of_tunnel,
1103 consider_peer_destroy (cp);
1108 * Retrieve the CadetPeer stucture associated with the
1109 * peer. Optionally create one and insert it in the appropriate
1110 * structures if the peer is not known yet.
1112 * @param peer_id Full identity of the peer.
1113 * @param create #GNUNET_YES if a new peer should be created if unknown.
1114 * #GNUNET_NO to return NULL if peer is unknown.
1115 * @return Existing or newly created peer structure.
1116 * NULL if unknown and not requested @a create
1119 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1122 struct CadetPeer *cp;
1124 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1128 if (GNUNET_NO == create)
1130 cp = GNUNET_new (struct CadetPeer);
1132 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1134 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1135 GNUNET_assert (GNUNET_YES ==
1136 GNUNET_CONTAINER_multipeermap_put (peers,
1139 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1140 LOG (GNUNET_ERROR_TYPE_DEBUG,
1141 "Creating peer %s\n",
1148 * Obtain the peer identity for a `struct CadetPeer`.
1150 * @param cp our peer handle
1151 * @return the peer identity
1153 const struct GNUNET_PeerIdentity *
1154 GCP_get_id (struct CadetPeer *cp)
1161 * Iterate over all known peers.
1163 * @param iter Iterator.
1164 * @param cls Closure for @c iter.
1167 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1170 GNUNET_CONTAINER_multipeermap_iterate (peers,
1177 * Count the number of known paths toward the peer.
1179 * @param cp Peer to get path info.
1180 * @return Number of known paths.
1183 GCP_count_paths (const struct CadetPeer *cp)
1185 return cp->num_paths;
1190 * Iterate over the paths to a peer.
1192 * @param cp Peer to get path info.
1193 * @param callback Function to call for every path.
1194 * @param callback_cls Closure for @a callback.
1195 * @return Number of iterated paths.
1198 GCP_iterate_paths (struct CadetPeer *cp,
1199 GCP_PathIterator callback,
1202 unsigned int ret = 0;
1204 LOG (GNUNET_ERROR_TYPE_DEBUG,
1205 "Iterating over paths to peer %s%s\n",
1207 (NULL == cp->core_mq) ? "" : " including direct link");
1208 if (NULL != cp->core_mq)
1210 struct CadetPeerPath *path;
1212 path = GCPP_get_path_from_route (1,
1216 callback (callback_cls,
1221 for (unsigned int i=0;i<cp->path_dll_length;i++)
1223 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1229 callback (callback_cls,
1239 * Iterate over the paths to a peer without direct link.
1241 * @param cp Peer to get path info.
1242 * @param callback Function to call for every path.
1243 * @param callback_cls Closure for @a callback.
1244 * @return Number of iterated paths.
1247 GCP_iterate_indirect_paths (struct CadetPeer *cp,
1248 GCP_PathIterator callback,
1251 unsigned int ret = 0;
1253 LOG (GNUNET_ERROR_TYPE_DEBUG,
1254 "Iterating over paths to peer %s without direct link\n",
1256 for (unsigned int i=1;i<cp->path_dll_length;i++)
1258 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1264 callback (callback_cls,
1275 * Iterate over the paths to @a cp where
1276 * @a cp is at distance @a dist from us.
1278 * @param cp Peer to get path info.
1279 * @param dist desired distance of @a cp to us on the path
1280 * @param callback Function to call for every path.
1281 * @param callback_cls Closure for @a callback.
1282 * @return Number of iterated paths.
1285 GCP_iterate_paths_at (struct CadetPeer *cp,
1287 GCP_PathIterator callback,
1290 unsigned int ret = 0;
1292 if (dist >= cp->path_dll_length)
1294 LOG (GNUNET_ERROR_TYPE_DEBUG,
1295 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1297 cp->path_dll_length);
1300 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1305 callback (callback_cls,
1316 * Get the tunnel towards a peer.
1318 * @param cp Peer to get from.
1319 * @param create #GNUNET_YES to create a tunnel if we do not have one
1320 * @return Tunnel towards peer.
1322 struct CadetTunnel *
1323 GCP_get_tunnel (struct CadetPeer *cp,
1328 if ( (NULL != cp->t) ||
1329 (GNUNET_NO == create) )
1331 cp->t = GCT_create_tunnel (cp);
1332 consider_peer_activate (cp);
1338 * Hello offer was passed to the transport service. Mark it
1341 * @param cls the `struct CadetPeer` where the offer completed
1344 hello_offer_done (void *cls)
1346 struct CadetPeer *cp = cls;
1348 cp->hello_offer = NULL;
1353 * We got a HELLO for a @a peer, remember it, and possibly
1354 * trigger adequate actions (like trying to connect).
1356 * @param cp the peer we got a HELLO for
1357 * @param hello the HELLO to remember
1360 GCP_set_hello (struct CadetPeer *cp,
1361 const struct GNUNET_HELLO_Message *hello)
1363 struct GNUNET_HELLO_Message *mrg;
1365 LOG (GNUNET_ERROR_TYPE_DEBUG,
1366 "Got %u byte HELLO for peer %s\n",
1367 (unsigned int) GNUNET_HELLO_size (hello),
1369 if (NULL != cp->hello_offer)
1371 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1372 cp->hello_offer = NULL;
1374 if (NULL != cp->hello)
1376 mrg = GNUNET_HELLO_merge (hello,
1378 GNUNET_free (cp->hello);
1383 cp->hello = GNUNET_memdup (hello,
1384 GNUNET_HELLO_size (hello));
1387 = GNUNET_TRANSPORT_offer_hello (cfg,
1388 GNUNET_HELLO_get_header (cp->hello) ,
1391 /* New HELLO means cp's destruction time may change... */
1392 consider_peer_destroy (cp);
1397 * The tunnel to the given peer no longer exists, remove it from our
1398 * data structures, and possibly clean up the peer itself.
1400 * @param cp the peer affected
1401 * @param t the dead tunnel
1404 GCP_drop_tunnel (struct CadetPeer *cp,
1405 struct CadetTunnel *t)
1407 LOG (GNUNET_ERROR_TYPE_DEBUG,
1408 "Dropping tunnel %s to peer %s\n",
1411 GNUNET_assert (cp->t == t);
1413 consider_peer_destroy (cp);
1418 * Test if @a cp has a core-level connection
1420 * @param cp peer to test
1421 * @return #GNUNET_YES if @a cp has a core-level connection
1424 GCP_has_core_connection (struct CadetPeer *cp)
1426 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1431 * Start message queue change notifications.
1433 * @param cp peer to notify for
1434 * @param cb function to call if mq becomes available or unavailable
1435 * @param cb_cls closure for @a cb
1436 * @return handle to cancel request
1438 struct GCP_MessageQueueManager *
1439 GCP_request_mq (struct CadetPeer *cp,
1440 GCP_MessageQueueNotificationCallback cb,
1443 struct GCP_MessageQueueManager *mqm;
1445 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1447 mqm->cb_cls = cb_cls;
1449 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1452 LOG (GNUNET_ERROR_TYPE_DEBUG,
1453 "Creating MQM %p for peer %s\n",
1456 if (NULL != cp->core_mq)
1464 * Stops message queue change notifications.
1466 * @param mqm handle matching request to cancel
1467 * @param last_env final message to transmit, or NULL
1470 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1471 struct GNUNET_MQ_Envelope *last_env)
1473 struct CadetPeer *cp = mqm->cp;
1475 LOG (GNUNET_ERROR_TYPE_DEBUG,
1476 "Destroying MQM %p for peer %s%s\n",
1479 (NULL == last_env) ? "" : " with last ditch transmission");
1480 if (NULL != mqm->env)
1481 GNUNET_MQ_discard (mqm->env);
1482 if (NULL != last_env)
1484 if (NULL != cp->core_mq)
1486 GNUNET_MQ_notify_sent (last_env,
1489 GNUNET_MQ_send (cp->core_mq,
1494 GNUNET_MQ_discard (last_env);
1497 if (cp->mqm_ready_ptr == mqm)
1498 cp->mqm_ready_ptr = mqm->next;
1499 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1507 * Send the message in @a env to @a cp, overriding queueing logic.
1508 * This function should only be used to send error messages outside
1509 * of flow and congestion control, similar to ICMP. Note that
1510 * the envelope may be silently discarded as well.
1512 * @param cp peer to send the message to
1513 * @param env envelope with the message to send
1516 GCP_send_ooo (struct CadetPeer *cp,
1517 struct GNUNET_MQ_Envelope *env)
1519 LOG (GNUNET_ERROR_TYPE_DEBUG,
1520 "Sending message to %s out of management\n",
1522 if (NULL == cp->core_mq)
1524 GNUNET_MQ_discard (env);
1527 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1529 GNUNET_MQ_discard (env);
1532 GNUNET_MQ_notify_sent (env,
1535 GNUNET_MQ_send (cp->core_mq,
1542 /* end of gnunet-service-cadet-new_peer.c */