2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file cadet/gnunet-service-cadet_peer.c
23 * @brief Information we track per peer.
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
28 * - optimize stopping/restarting DHT search to situations
29 * where we actually need it (i.e. not if we have a direct connection,
30 * or if we already have plenty of good short ones, or maybe even
31 * to take a break if we have some connections and have searched a lot (?))
34 #include "gnunet_util_lib.h"
35 #include "gnunet_hello_lib.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_ats_service.h"
39 #include "gnunet_core_service.h"
40 #include "gnunet_statistics_service.h"
41 #include "cadet_protocol.h"
42 #include "gnunet-service-cadet_connection.h"
43 #include "gnunet-service-cadet_dht.h"
44 #include "gnunet-service-cadet_peer.h"
45 #include "gnunet-service-cadet_paths.h"
46 #include "gnunet-service-cadet_tunnels.h"
49 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
53 * How long do we wait until tearing down an idle peer?
55 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
58 * How long do we keep paths around if we no longer care about the peer?
60 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
66 * Data structure used to track whom we have to notify about changes
67 * to our message queue.
69 struct GCP_MessageQueueManager
75 struct GCP_MessageQueueManager *next;
80 struct GCP_MessageQueueManager *prev;
83 * Function to call with updated message queue object.
85 GCP_MessageQueueNotificationCallback cb;
93 * The peer this is for.
98 * Envelope this manager would like to transmit once it is its turn.
100 struct GNUNET_MQ_Envelope *env;
106 * Struct containing all information regarding a given peer
113 struct GNUNET_PeerIdentity pid;
116 * Last time we heard from this peer (currently not used!)
118 struct GNUNET_TIME_Absolute last_contactXXX;
121 * Array of DLLs of paths traversing the peer, organized by the
122 * offset of the peer on the larger path.
124 struct CadetPeerPathEntry **path_heads;
127 * Array of DLL of paths traversing the peer, organized by the
128 * offset of the peer on the larger path.
130 struct CadetPeerPathEntry **path_tails;
133 * Notifications to call when @e core_mq changes.
135 struct GCP_MessageQueueManager *mqm_head;
138 * Notifications to call when @e core_mq changes.
140 struct GCP_MessageQueueManager *mqm_tail;
143 * Pointer to first "ready" entry in @e mqm_head.
145 struct GCP_MessageQueueManager *mqm_ready_ptr;
148 * MIN-heap of paths owned by this peer (they also end at this
149 * peer). Ordered by desirability.
151 struct GNUNET_CONTAINER_Heap *path_heap;
154 * Handle to stop the DHT search for paths to this peer
156 struct GCD_search_handle *search_h;
159 * Task to clean up @e path_heap asynchronously.
161 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
164 * Task to destroy this entry.
166 struct GNUNET_SCHEDULER_Task *destroy_task;
169 * Tunnel to this peer, if any.
171 struct CadetTunnel *t;
174 * Connections that go through this peer; indexed by tid.
176 struct GNUNET_CONTAINER_MultiShortmap *connections;
179 * Handle for core transmissions.
181 struct GNUNET_MQ_Handle *core_mq;
184 * Hello message of the peer.
186 struct GNUNET_HELLO_Message *hello;
189 * Handle to us offering the HELLO to the transport.
191 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
194 * Handle to our ATS request asking ATS to suggest an address
195 * to TRANSPORT for this peer (to establish a direct link).
197 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
200 * How many messages are in the queue to this peer.
202 unsigned int queue_n;
205 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
207 unsigned int num_paths;
210 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
211 * Used to speed-up @GCP_get_desirability_of_path() calculation.
213 unsigned int off_sum;
216 * Number of message queue managers of this peer that have a message in waiting.
218 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
219 * TODO: could be replaced by another DLL that would then allow us to avoid
220 * the O(n)-scan of the DLL for ready entries!
222 unsigned int mqm_ready_counter;
225 * Current length of the @e path_heads and @path_tails arrays.
226 * The arrays should be grown as needed.
228 unsigned int path_dll_length;
234 * Get the static string for a peer ID.
237 * @return Static string for it's ID.
240 GCP_2s (const struct CadetPeer *cp)
244 GNUNET_snprintf (buf,
247 GNUNET_i2s (&cp->pid));
253 * Calculate how desirable a path is for @a cp if @a cp
254 * is at offset @a off.
256 * The 'desirability_table.c' program can be used to compute a list of
257 * sample outputs for different scenarios. Basically, we score paths
258 * lower if there are many alternatives, and higher if they are
259 * shorter than average, and very high if they are much shorter than
260 * average and without many alternatives.
262 * @param cp a peer reachable via a path
263 * @param off offset of @a cp in the path
264 * @return score how useful a path is to reach @a cp,
265 * positive scores mean path is more desirable
268 GCP_get_desirability_of_path (struct CadetPeer *cp,
271 unsigned int num_alts = cp->num_paths;
272 unsigned int off_sum;
277 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
278 GNUNET_assert (0 != cp->path_dll_length);
280 /* We maintain 'off_sum' in 'peer' and thereby
281 avoid the SLOW recalculation each time. Kept here
282 just to document what is going on. */
285 for (unsigned int j=0;j<cp->path_dll_length;j++)
286 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
290 GNUNET_assert (off_sum == cp->off_sum);
292 off_sum = cp->off_sum;
294 avg_sum = off_sum * 1.0 / cp->path_dll_length;
295 path_delta = off - avg_sum;
296 /* path_delta positiv: path off of peer above average (bad path for peer),
297 path_delta negativ: path off of peer below average (good path for peer) */
298 if (path_delta <= - 1.0)
299 weight_alts = - num_alts / path_delta; /* discount alternative paths */
300 else if (path_delta >= 1.0)
301 weight_alts = num_alts * path_delta; /* overcount alternative paths */
303 weight_alts = num_alts; /* count alternative paths normally */
306 /* off+1: long paths are generally harder to find and thus count
307 a bit more as they get longer. However, above-average paths
308 still need to count less, hence the squaring of that factor. */
309 return (off + 1.0) / (weight_alts * weight_alts);
314 * This peer is no longer be needed, clean it up now.
316 * @param cls peer to clean up
319 destroy_peer (void *cls)
321 struct CadetPeer *cp = cls;
323 LOG (GNUNET_ERROR_TYPE_DEBUG,
324 "Destroying state about peer %s\n",
326 cp->destroy_task = NULL;
327 GNUNET_assert (NULL == cp->t);
328 GNUNET_assert (NULL == cp->core_mq);
329 GNUNET_assert (0 == cp->num_paths);
330 for (unsigned int i=0;i<cp->path_dll_length;i++)
331 GNUNET_assert (NULL == cp->path_heads[i]);
332 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
333 GNUNET_assert (GNUNET_YES ==
334 GNUNET_CONTAINER_multipeermap_remove (peers,
337 GNUNET_free_non_null (cp->path_heads);
338 GNUNET_free_non_null (cp->path_tails);
339 cp->path_dll_length = 0;
340 if (NULL != cp->search_h)
342 GCD_search_stop (cp->search_h);
345 /* FIXME: clean up search_delayedXXX! */
347 if (NULL != cp->hello_offer)
349 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
350 cp->hello_offer = NULL;
352 if (NULL != cp->connectivity_suggestion)
354 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
355 cp->connectivity_suggestion = NULL;
357 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
358 if (NULL != cp->path_heap)
360 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
361 cp->path_heap = NULL;
363 if (NULL != cp->heap_cleanup_task)
365 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
366 cp->heap_cleanup_task = NULL;
368 GNUNET_free_non_null (cp->hello);
369 /* Peer should not be freed if paths exist; if there are no paths,
370 there ought to be no connections, and without connections, no
371 notifications. Thus we can assert that mqm_head is empty at this
373 GNUNET_assert (NULL == cp->mqm_head);
374 GNUNET_assert (NULL == cp->mqm_ready_ptr);
380 * This peer is now on more "active" duty, activate processes related to it.
382 * @param cp the more-active peer
385 consider_peer_activate (struct CadetPeer *cp)
389 LOG (GNUNET_ERROR_TYPE_DEBUG,
390 "Updating peer %s activation state (%u connections)%s%s\n",
392 GNUNET_CONTAINER_multishortmap_size (cp->connections),
393 (NULL == cp->t) ? "" : " with tunnel",
394 (NULL == cp->core_mq) ? "" : " with CORE link");
395 if (NULL != cp->destroy_task)
397 /* It's active, do not destory! */
398 GNUNET_SCHEDULER_cancel (cp->destroy_task);
399 cp->destroy_task = NULL;
401 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
404 /* We're just on a path or directly connected; don't bother too much */
405 if (NULL != cp->connectivity_suggestion)
407 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
408 cp->connectivity_suggestion = NULL;
410 if (NULL != cp->search_h)
412 GCD_search_stop (cp->search_h);
417 if (NULL == cp->core_mq)
419 /* Lacks direct connection, try to create one by querying the DHT */
420 if ( (NULL == cp->search_h) &&
421 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
423 = GCD_search (&cp->pid);
427 /* Have direct connection, stop DHT search if active */
428 if (NULL != cp->search_h)
430 GCD_search_stop (cp->search_h);
435 /* If we have a tunnel, our urge for connections is much bigger */
436 strength = (NULL != cp->t) ? 32 : 1;
437 if (NULL != cp->connectivity_suggestion)
438 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
439 cp->connectivity_suggestion
440 = GNUNET_ATS_connectivity_suggest (ats_ch,
447 * This peer may no longer be needed, consider cleaning it up.
449 * @param cp peer to clean up
452 consider_peer_destroy (struct CadetPeer *cp);
456 * We really no longere care about a peer, stop hogging memory with paths to it.
457 * Afterwards, see if there is more to be cleaned up about this peer.
459 * @param cls a `struct CadetPeer`.
462 drop_paths (void *cls)
464 struct CadetPeer *cp = cls;
465 struct CadetPeerPath *path;
467 cp->destroy_task = NULL;
468 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
470 consider_peer_destroy (cp);
475 * This peer may no longer be needed, consider cleaning it up.
477 * @param cp peer to clean up
480 consider_peer_destroy (struct CadetPeer *cp)
482 struct GNUNET_TIME_Relative exp;
484 if (NULL != cp->destroy_task)
486 GNUNET_SCHEDULER_cancel (cp->destroy_task);
487 cp->destroy_task = NULL;
490 return; /* still relevant! */
491 if (NULL != cp->core_mq)
492 return; /* still relevant! */
493 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
494 return; /* still relevant! */
495 if ( (NULL != cp->path_heap) &&
496 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
498 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
503 if (0 != cp->num_paths)
504 return; /* still relevant! */
505 if (NULL != cp->hello)
507 /* relevant only until HELLO expires */
508 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
509 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
514 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
521 * Set the message queue to @a mq for peer @a cp and notify watchers.
523 * @param cp peer to modify
524 * @param mq message queue to set (can be NULL)
527 GCP_set_mq (struct CadetPeer *cp,
528 struct GNUNET_MQ_Handle *mq)
530 LOG (GNUNET_ERROR_TYPE_DEBUG,
531 "Message queue for peer %s is now %p\n",
535 /* Since these callbacks can remove any items from this list, we must take a
536 * snapshot and then test each one to see if it's still in the list. */
538 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
542 struct GCP_MessageQueueManager *mqms[count];
544 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
548 for (i = 0; i < count; ++i)
550 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
558 if (NULL != mqm->env)
560 GNUNET_MQ_discard (mqm->env);
562 mqm->cb (mqm->cb_cls,
567 mqm->cb (mqm->cb_cls,
573 GNUNET_assert (NULL == mqm->env);
574 mqm->cb (mqm->cb_cls,
582 consider_peer_activate (cp);
584 consider_peer_destroy (cp);
589 /* have a new, direct path to the target, notify tunnel */
590 struct CadetPeerPath *path;
592 path = GCPP_get_path_from_route (1,
594 GCT_consider_path (cp->t,
602 * Debug function should NEVER return true in production code, useful to
603 * simulate losses for testcases.
605 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
610 if (0 == drop_percent)
612 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
620 * Function called when CORE took one of the messages from
621 * a message queue manager and transmitted it.
623 * @param cls the `struct CadetPeeer` where we made progress
626 mqm_send_done (void *cls);
630 * Transmit current envelope from this @a mqm.
632 * @param mqm mqm to transmit message for now
635 mqm_execute (struct GCP_MessageQueueManager *mqm)
637 struct CadetPeer *cp = mqm->cp;
639 /* Move ready pointer to the next entry that might be ready. */
640 if ( (mqm == cp->mqm_ready_ptr) &&
641 (NULL != mqm->next) )
642 cp->mqm_ready_ptr = mqm->next;
643 /* Move entry to the end of the DLL, to be fair. */
644 if (mqm != cp->mqm_tail)
646 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
649 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
653 cp->mqm_ready_counter--;
654 if (GNUNET_YES == should_I_drop ())
656 LOG (GNUNET_ERROR_TYPE_DEBUG,
657 "DROPPING message to peer %s from MQM %p\n",
660 GNUNET_MQ_discard (mqm->env);
666 LOG (GNUNET_ERROR_TYPE_DEBUG,
667 "Sending to peer %s from MQM %p\n",
670 GNUNET_MQ_send (cp->core_mq,
674 mqm->cb (mqm->cb_cls,
680 * Find the next ready message in the queue (starting
681 * the search from the `cp->mqm_ready_ptr`) and if possible
682 * execute the transmission.
684 * @param cp peer to try to send the next ready message to
687 send_next_ready (struct CadetPeer *cp)
689 struct GCP_MessageQueueManager *mqm;
691 if (0 == cp->mqm_ready_counter)
693 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
695 cp->mqm_ready_ptr = mqm->next;
697 return; /* nothing to do */
703 * Function called when CORE took one of the messages from
704 * a message queue manager and transmitted it.
706 * @param cls the `struct CadetPeeer` where we made progress
709 mqm_send_done (void *cls)
711 struct CadetPeer *cp = cls;
713 LOG (GNUNET_ERROR_TYPE_DEBUG,
714 "Sending to peer %s completed\n",
716 send_next_ready (cp);
721 * Send the message in @a env to @a cp.
723 * @param mqm the message queue manager to use for transmission
724 * @param env envelope with the message to send; must NOT
725 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
728 GCP_send (struct GCP_MessageQueueManager *mqm,
729 struct GNUNET_MQ_Envelope *env)
731 struct CadetPeer *cp = mqm->cp;
733 GNUNET_assert (NULL != env);
734 LOG (GNUNET_ERROR_TYPE_DEBUG,
735 "Queueing message to peer %s in MQM %p\n",
738 GNUNET_assert (NULL != cp->core_mq);
739 GNUNET_assert (NULL == mqm->env);
740 GNUNET_MQ_notify_sent (env,
744 cp->mqm_ready_counter++;
745 if (mqm != cp->mqm_ready_ptr)
746 cp->mqm_ready_ptr = cp->mqm_head;
747 if (1 == cp->mqm_ready_counter)
748 cp->mqm_ready_ptr = mqm;
749 if (0 != GNUNET_MQ_get_length (cp->core_mq))
751 send_next_ready (cp);
756 * Function called to destroy a peer now.
759 * @param pid identity of the peer (unused)
760 * @param value the `struct CadetPeer` to clean up
761 * @return #GNUNET_OK (continue to iterate)
764 destroy_iterator_cb (void *cls,
765 const struct GNUNET_PeerIdentity *pid,
768 struct CadetPeer *cp = value;
770 if (NULL != cp->destroy_task)
772 GNUNET_SCHEDULER_cancel (cp->destroy_task);
773 cp->destroy_task = NULL;
781 * Clean up all entries about all peers.
782 * Must only be called after all tunnels, CORE-connections and
783 * connections are down.
786 GCP_destroy_all_peers ()
788 LOG (GNUNET_ERROR_TYPE_DEBUG,
789 "Destroying all peers now\n");
790 GNUNET_CONTAINER_multipeermap_iterate (peers,
791 &destroy_iterator_cb,
797 * Drop all paths owned by this peer, and do not
798 * allow new ones to be added: We are shutting down.
800 * @param cp peer to drop paths to
803 GCP_drop_owned_paths (struct CadetPeer *cp)
805 struct CadetPeerPath *path;
807 LOG (GNUNET_ERROR_TYPE_DEBUG,
808 "Destroying all paths to %s\n",
810 while (NULL != (path =
811 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
813 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
814 cp->path_heap = NULL;
819 * Add an entry to the DLL of all of the paths that this peer is on.
821 * @param cp peer to modify
822 * @param entry an entry on a path
823 * @param off offset of this peer on the path
826 GCP_path_entry_add (struct CadetPeer *cp,
827 struct CadetPeerPathEntry *entry,
830 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
832 LOG (GNUNET_ERROR_TYPE_DEBUG,
833 "Discovered that peer %s is on path %s at offset %u\n",
835 GCPP_2s (entry->path),
837 if (off >= cp->path_dll_length)
839 unsigned int len = cp->path_dll_length;
841 GNUNET_array_grow (cp->path_heads,
844 GNUNET_array_grow (cp->path_tails,
848 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
854 /* If we have a tunnel to this peer, tell the tunnel that there is a
855 new path available. */
857 GCT_consider_path (cp->t,
861 if ( (NULL != cp->search_h) &&
862 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
864 /* Now I have enough paths, stop search */
865 GCD_search_stop (cp->search_h);
868 if (NULL != cp->destroy_task)
870 /* paths changed, this resets the destroy timeout counter
871 and aborts a destroy task that may no longer be valid
872 to have (as we now have more paths via this peer). */
873 consider_peer_destroy (cp);
879 * Remove an entry from the DLL of all of the paths that this peer is on.
881 * @param cp peer to modify
882 * @param entry an entry on a path
883 * @param off offset of this peer on the path
886 GCP_path_entry_remove (struct CadetPeer *cp,
887 struct CadetPeerPathEntry *entry,
890 LOG (GNUNET_ERROR_TYPE_DEBUG,
891 "Removing knowledge about peer %s beging on path %s at offset %u\n",
893 GCPP_2s (entry->path),
895 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
898 GNUNET_assert (0 < cp->num_paths);
901 if ( (NULL == cp->core_mq) &&
903 (NULL == cp->search_h) &&
904 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
906 = GCD_search (&cp->pid);
907 if (NULL == cp->destroy_task)
909 /* paths changed, we might now be ready for destruction, check again */
910 consider_peer_destroy (cp);
916 * Prune down the number of paths to this peer, we seem to
919 * @param cls the `struct CadetPeer` to maintain the path heap for
922 path_heap_cleanup (void *cls)
924 struct CadetPeer *cp = cls;
925 struct CadetPeerPath *root;
927 cp->heap_cleanup_task = NULL;
928 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
929 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
931 /* Now we have way too many, drop least desirable UNLESS it is in use!
932 (Note that this intentionally keeps highly desireable, but currently
933 unused paths around in the hope that we might be able to switch, even
934 if the number of paths exceeds the threshold.) */
935 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
936 GNUNET_assert (NULL != root);
938 GCPP_get_connection (root,
940 GCPP_get_length (root) - 1))
941 break; /* can't fix */
942 /* Got plenty of paths to this destination, and this is a low-quality
943 one that we don't care about. Allow it to die. */
944 GNUNET_assert (root ==
945 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
952 * Try adding a @a path to this @a peer. If the peer already
953 * has plenty of paths, return NULL.
955 * @param cp peer to which the @a path leads to
956 * @param path a path looking for an owner; may not be fully initialized yet!
957 * @param off offset of @a cp in @a path
958 * @param force force attaching the path
959 * @return NULL if this peer does not care to become a new owner,
960 * otherwise the node in the peer's path heap for the @a path.
962 struct GNUNET_CONTAINER_HeapNode *
963 GCP_attach_path (struct CadetPeer *cp,
964 struct CadetPeerPath *path,
968 GNUNET_CONTAINER_HeapCostType desirability;
969 struct CadetPeerPath *root;
970 GNUNET_CONTAINER_HeapCostType root_desirability;
971 struct GNUNET_CONTAINER_HeapNode *hn;
973 GNUNET_assert (off == GCPP_get_length (path) - 1);
974 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
976 if (NULL == cp->path_heap)
978 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
979 GNUNET_assert (GNUNET_NO == force);
982 desirability = GCPP_get_desirability (path);
983 if (GNUNET_NO == force)
985 /* FIXME: desirability is not yet initialized; tricky! */
987 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
992 root_desirability = 0;
995 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
996 (desirability < root_desirability) )
998 LOG (GNUNET_ERROR_TYPE_DEBUG,
999 "Decided to not attach path %p to peer %s due to undesirability\n",
1006 LOG (GNUNET_ERROR_TYPE_DEBUG,
1007 "Attaching path %s to peer %s (%s)\n",
1010 (GNUNET_NO == force) ? "desirable" : "forced");
1012 /* Yes, we'd like to add this path, add to our heap */
1013 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1017 /* Consider maybe dropping other paths because of the new one */
1018 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1019 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1020 (NULL != cp->heap_cleanup_task) )
1021 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1028 * This peer can no longer own @a path as the path
1029 * has been extended and a peer further down the line
1030 * is now the new owner.
1032 * @param cp old owner of the @a path
1033 * @param path path where the ownership is lost
1034 * @param hn note in @a cp's path heap that must be deleted
1037 GCP_detach_path (struct CadetPeer *cp,
1038 struct CadetPeerPath *path,
1039 struct GNUNET_CONTAINER_HeapNode *hn)
1041 LOG (GNUNET_ERROR_TYPE_DEBUG,
1042 "Detatching path %s from peer %s\n",
1045 GNUNET_assert (path ==
1046 GNUNET_CONTAINER_heap_remove_node (hn));
1051 * Add a @a connection to this @a cp.
1053 * @param cp peer via which the @a connection goes
1054 * @param cc the connection to add
1057 GCP_add_connection (struct CadetPeer *cp,
1058 struct CadetConnection *cc)
1060 LOG (GNUNET_ERROR_TYPE_DEBUG,
1061 "Adding connection %s to peer %s\n",
1064 GNUNET_assert (GNUNET_OK ==
1065 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1066 &GCC_get_id (cc)->connection_of_tunnel,
1068 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1069 if (NULL != cp->destroy_task)
1071 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1072 cp->destroy_task = NULL;
1078 * Remove a @a connection that went via this @a cp.
1080 * @param cp peer via which the @a connection went
1081 * @param cc the connection to remove
1084 GCP_remove_connection (struct CadetPeer *cp,
1085 struct CadetConnection *cc)
1087 LOG (GNUNET_ERROR_TYPE_DEBUG,
1088 "Removing connection %s from peer %s\n",
1091 GNUNET_assert (GNUNET_YES ==
1092 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1093 &GCC_get_id (cc)->connection_of_tunnel,
1095 consider_peer_destroy (cp);
1100 * Retrieve the CadetPeer stucture associated with the
1101 * peer. Optionally create one and insert it in the appropriate
1102 * structures if the peer is not known yet.
1104 * @param peer_id Full identity of the peer.
1105 * @param create #GNUNET_YES if a new peer should be created if unknown.
1106 * #GNUNET_NO to return NULL if peer is unknown.
1107 * @return Existing or newly created peer structure.
1108 * NULL if unknown and not requested @a create
1111 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1114 struct CadetPeer *cp;
1116 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1120 if (GNUNET_NO == create)
1122 cp = GNUNET_new (struct CadetPeer);
1124 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1126 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1127 GNUNET_assert (GNUNET_YES ==
1128 GNUNET_CONTAINER_multipeermap_put (peers,
1131 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1132 LOG (GNUNET_ERROR_TYPE_DEBUG,
1133 "Creating peer %s\n",
1140 * Obtain the peer identity for a `struct CadetPeer`.
1142 * @param cp our peer handle
1143 * @return the peer identity
1145 const struct GNUNET_PeerIdentity *
1146 GCP_get_id (struct CadetPeer *cp)
1153 * Iterate over all known peers.
1155 * @param iter Iterator.
1156 * @param cls Closure for @c iter.
1159 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1162 GNUNET_CONTAINER_multipeermap_iterate (peers,
1169 * Count the number of known paths toward the peer.
1171 * @param cp Peer to get path info.
1172 * @return Number of known paths.
1175 GCP_count_paths (const struct CadetPeer *cp)
1177 return cp->num_paths;
1182 * Iterate over the paths to a peer.
1184 * @param cp Peer to get path info.
1185 * @param callback Function to call for every path.
1186 * @param callback_cls Closure for @a callback.
1187 * @return Number of iterated paths.
1190 GCP_iterate_paths (struct CadetPeer *cp,
1191 GCP_PathIterator callback,
1194 unsigned int ret = 0;
1196 LOG (GNUNET_ERROR_TYPE_DEBUG,
1197 "Iterating over paths to peer %s%s\n",
1199 (NULL == cp->core_mq) ? "" : " including direct link");
1200 if (NULL != cp->core_mq)
1202 struct CadetPeerPath *path;
1204 path = GCPP_get_path_from_route (1,
1208 callback (callback_cls,
1213 for (unsigned int i=0;i<cp->path_dll_length;i++)
1215 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1221 callback (callback_cls,
1232 * Iterate over the paths to @a cp where
1233 * @a cp is at distance @a dist from us.
1235 * @param cp Peer to get path info.
1236 * @param dist desired distance of @a cp to us on the path
1237 * @param callback Function to call for every path.
1238 * @param callback_cls Closure for @a callback.
1239 * @return Number of iterated paths.
1242 GCP_iterate_paths_at (struct CadetPeer *cp,
1244 GCP_PathIterator callback,
1247 unsigned int ret = 0;
1249 if (dist >= cp->path_dll_length)
1251 LOG (GNUNET_ERROR_TYPE_DEBUG,
1252 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1254 cp->path_dll_length);
1257 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1262 callback (callback_cls,
1273 * Get the tunnel towards a peer.
1275 * @param cp Peer to get from.
1276 * @param create #GNUNET_YES to create a tunnel if we do not have one
1277 * @return Tunnel towards peer.
1279 struct CadetTunnel *
1280 GCP_get_tunnel (struct CadetPeer *cp,
1285 if ( (NULL != cp->t) ||
1286 (GNUNET_NO == create) )
1288 cp->t = GCT_create_tunnel (cp);
1289 consider_peer_activate (cp);
1295 * Hello offer was passed to the transport service. Mark it
1298 * @param cls the `struct CadetPeer` where the offer completed
1301 hello_offer_done (void *cls)
1303 struct CadetPeer *cp = cls;
1305 cp->hello_offer = NULL;
1310 * We got a HELLO for a @a peer, remember it, and possibly
1311 * trigger adequate actions (like trying to connect).
1313 * @param cp the peer we got a HELLO for
1314 * @param hello the HELLO to remember
1317 GCP_set_hello (struct CadetPeer *cp,
1318 const struct GNUNET_HELLO_Message *hello)
1320 struct GNUNET_HELLO_Message *mrg;
1322 LOG (GNUNET_ERROR_TYPE_DEBUG,
1323 "Got %u byte HELLO for peer %s\n",
1324 (unsigned int) GNUNET_HELLO_size (hello),
1326 if (NULL != cp->hello_offer)
1328 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1329 cp->hello_offer = NULL;
1331 if (NULL != cp->hello)
1333 mrg = GNUNET_HELLO_merge (hello,
1335 GNUNET_free (cp->hello);
1340 cp->hello = GNUNET_memdup (hello,
1341 GNUNET_HELLO_size (hello));
1344 = GNUNET_TRANSPORT_offer_hello (cfg,
1345 GNUNET_HELLO_get_header (cp->hello) ,
1348 /* New HELLO means cp's destruction time may change... */
1349 consider_peer_destroy (cp);
1354 * The tunnel to the given peer no longer exists, remove it from our
1355 * data structures, and possibly clean up the peer itself.
1357 * @param cp the peer affected
1358 * @param t the dead tunnel
1361 GCP_drop_tunnel (struct CadetPeer *cp,
1362 struct CadetTunnel *t)
1364 LOG (GNUNET_ERROR_TYPE_DEBUG,
1365 "Dropping tunnel %s to peer %s\n",
1368 GNUNET_assert (cp->t == t);
1370 consider_peer_destroy (cp);
1375 * Test if @a cp has a core-level connection
1377 * @param cp peer to test
1378 * @return #GNUNET_YES if @a cp has a core-level connection
1381 GCP_has_core_connection (struct CadetPeer *cp)
1383 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1388 * Start message queue change notifications.
1390 * @param cp peer to notify for
1391 * @param cb function to call if mq becomes available or unavailable
1392 * @param cb_cls closure for @a cb
1393 * @return handle to cancel request
1395 struct GCP_MessageQueueManager *
1396 GCP_request_mq (struct CadetPeer *cp,
1397 GCP_MessageQueueNotificationCallback cb,
1400 struct GCP_MessageQueueManager *mqm;
1402 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1404 mqm->cb_cls = cb_cls;
1406 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1409 LOG (GNUNET_ERROR_TYPE_DEBUG,
1410 "Creating MQM %p for peer %s\n",
1413 if (NULL != cp->core_mq)
1421 * Stops message queue change notifications.
1423 * @param mqm handle matching request to cancel
1424 * @param last_env final message to transmit, or NULL
1427 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1428 struct GNUNET_MQ_Envelope *last_env)
1430 struct CadetPeer *cp = mqm->cp;
1432 LOG (GNUNET_ERROR_TYPE_DEBUG,
1433 "Destroying MQM %p for peer %s%s\n",
1436 (NULL == last_env) ? "" : " with last ditch transmission");
1437 if (NULL != mqm->env)
1438 GNUNET_MQ_discard (mqm->env);
1439 if (NULL != last_env)
1441 if (NULL != cp->core_mq)
1443 GNUNET_MQ_notify_sent (last_env,
1446 GNUNET_MQ_send (cp->core_mq,
1451 GNUNET_MQ_discard (last_env);
1454 if (cp->mqm_ready_ptr == mqm)
1455 cp->mqm_ready_ptr = mqm->next;
1456 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1464 * Send the message in @a env to @a cp, overriding queueing logic.
1465 * This function should only be used to send error messages outside
1466 * of flow and congestion control, similar to ICMP. Note that
1467 * the envelope may be silently discarded as well.
1469 * @param cp peer to send the message to
1470 * @param env envelope with the message to send
1473 GCP_send_ooo (struct CadetPeer *cp,
1474 struct GNUNET_MQ_Envelope *env)
1476 LOG (GNUNET_ERROR_TYPE_DEBUG,
1477 "Sending message to %s out of management\n",
1479 if (NULL == cp->core_mq)
1481 GNUNET_MQ_discard (env);
1484 GNUNET_MQ_notify_sent (env,
1487 GNUNET_MQ_send (cp->core_mq,
1494 /* end of gnunet-service-cadet-new_peer.c */