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)
247 NULL == &cp->pid.public_key){
251 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&cp->pid.public_key);
267 * Calculate how desirable a path is for @a cp if @a cp
268 * is at offset @a off.
270 * The 'desirability_table.c' program can be used to compute a list of
271 * sample outputs for different scenarios. Basically, we score paths
272 * lower if there are many alternatives, and higher if they are
273 * shorter than average, and very high if they are much shorter than
274 * average and without many alternatives.
276 * @param cp a peer reachable via a path
277 * @param off offset of @a cp in the path
278 * @return score how useful a path is to reach @a cp,
279 * positive scores mean path is more desirable
282 GCP_get_desirability_of_path (struct CadetPeer *cp,
285 unsigned int num_alts = cp->num_paths;
286 unsigned int off_sum;
291 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
292 GNUNET_assert (0 != cp->path_dll_length);
294 /* We maintain 'off_sum' in 'peer' and thereby
295 avoid the SLOW recalculation each time. Kept here
296 just to document what is going on. */
299 for (unsigned int j=0;j<cp->path_dll_length;j++)
300 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
304 GNUNET_assert (off_sum == cp->off_sum);
306 off_sum = cp->off_sum;
308 avg_sum = off_sum * 1.0 / cp->path_dll_length;
309 path_delta = off - avg_sum;
310 /* path_delta positiv: path off of peer above average (bad path for peer),
311 path_delta negativ: path off of peer below average (good path for peer) */
312 if (path_delta <= - 1.0)
313 weight_alts = - num_alts / path_delta; /* discount alternative paths */
314 else if (path_delta >= 1.0)
315 weight_alts = num_alts * path_delta; /* overcount alternative paths */
317 weight_alts = num_alts; /* count alternative paths normally */
320 /* off+1: long paths are generally harder to find and thus count
321 a bit more as they get longer. However, above-average paths
322 still need to count less, hence the squaring of that factor. */
323 return (off + 1.0) / (weight_alts * weight_alts);
328 * This peer is no longer be needed, clean it up now.
330 * @param cls peer to clean up
333 destroy_peer (void *cls)
335 struct CadetPeer *cp = cls;
337 LOG (GNUNET_ERROR_TYPE_DEBUG,
338 "Destroying state about peer %s\n",
340 cp->destroy_task = NULL;
341 GNUNET_assert (NULL == cp->t);
342 GNUNET_assert (NULL == cp->core_mq);
343 GNUNET_assert (0 == cp->num_paths);
344 for (unsigned int i=0;i<cp->path_dll_length;i++)
345 GNUNET_assert (NULL == cp->path_heads[i]);
346 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
347 GNUNET_assert (GNUNET_YES ==
348 GNUNET_CONTAINER_multipeermap_remove (peers,
351 GNUNET_free_non_null (cp->path_heads);
352 GNUNET_free_non_null (cp->path_tails);
353 cp->path_dll_length = 0;
354 if (NULL != cp->search_h)
356 GCD_search_stop (cp->search_h);
359 /* FIXME: clean up search_delayedXXX! */
361 if (NULL != cp->hello_offer)
363 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
364 cp->hello_offer = NULL;
366 if (NULL != cp->connectivity_suggestion)
368 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
369 cp->connectivity_suggestion = NULL;
371 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
372 if (NULL != cp->path_heap)
374 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
375 cp->path_heap = NULL;
377 if (NULL != cp->heap_cleanup_task)
379 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
380 cp->heap_cleanup_task = NULL;
382 GNUNET_free_non_null (cp->hello);
383 /* Peer should not be freed if paths exist; if there are no paths,
384 there ought to be no connections, and without connections, no
385 notifications. Thus we can assert that mqm_head is empty at this
387 GNUNET_assert (NULL == cp->mqm_head);
388 GNUNET_assert (NULL == cp->mqm_ready_ptr);
394 * This peer is now on more "active" duty, activate processes related to it.
396 * @param cp the more-active peer
399 consider_peer_activate (struct CadetPeer *cp)
403 LOG (GNUNET_ERROR_TYPE_DEBUG,
404 "Updating peer %s activation state (%u connections)%s%s\n",
406 GNUNET_CONTAINER_multishortmap_size (cp->connections),
407 (NULL == cp->t) ? "" : " with tunnel",
408 (NULL == cp->core_mq) ? "" : " with CORE link");
409 if (NULL != cp->destroy_task)
411 /* It's active, do not destory! */
412 GNUNET_SCHEDULER_cancel (cp->destroy_task);
413 cp->destroy_task = NULL;
415 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
418 /* We're just on a path or directly connected; don't bother too much */
419 if (NULL != cp->connectivity_suggestion)
421 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
422 cp->connectivity_suggestion = NULL;
424 if (NULL != cp->search_h)
426 GCD_search_stop (cp->search_h);
431 if (NULL == cp->core_mq)
433 /* Lacks direct connection, try to create one by querying the DHT */
434 if ( (NULL == cp->search_h) &&
435 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
437 = GCD_search (&cp->pid);
441 /* Have direct connection, stop DHT search if active */
442 if (NULL != cp->search_h)
444 GCD_search_stop (cp->search_h);
449 /* If we have a tunnel, our urge for connections is much bigger */
450 strength = (NULL != cp->t) ? 32 : 1;
451 if (NULL != cp->connectivity_suggestion)
452 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
453 cp->connectivity_suggestion
454 = GNUNET_ATS_connectivity_suggest (ats_ch,
461 * This peer may no longer be needed, consider cleaning it up.
463 * @param cp peer to clean up
466 consider_peer_destroy (struct CadetPeer *cp);
470 * We really no longere care about a peer, stop hogging memory with paths to it.
471 * Afterwards, see if there is more to be cleaned up about this peer.
473 * @param cls a `struct CadetPeer`.
476 drop_paths (void *cls)
478 struct CadetPeer *cp = cls;
479 struct CadetPeerPath *path;
481 cp->destroy_task = NULL;
482 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
484 consider_peer_destroy (cp);
489 * This peer may no longer be needed, consider cleaning it up.
491 * @param cp peer to clean up
494 consider_peer_destroy (struct CadetPeer *cp)
496 struct GNUNET_TIME_Relative exp;
498 if (NULL != cp->destroy_task)
500 GNUNET_SCHEDULER_cancel (cp->destroy_task);
501 cp->destroy_task = NULL;
504 return; /* still relevant! */
505 if (NULL != cp->core_mq)
506 return; /* still relevant! */
507 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
508 return; /* still relevant! */
509 if ( (NULL != cp->path_heap) &&
510 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
512 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
517 if (0 != cp->num_paths)
518 return; /* still relevant! */
519 if (NULL != cp->hello)
521 /* relevant only until HELLO expires */
522 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
523 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
528 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
535 * Set the message queue to @a mq for peer @a cp and notify watchers.
537 * @param cp peer to modify
538 * @param mq message queue to set (can be NULL)
541 GCP_set_mq (struct CadetPeer *cp,
542 struct GNUNET_MQ_Handle *mq)
544 LOG (GNUNET_ERROR_TYPE_DEBUG,
545 "Message queue for peer %s is now %p\n",
549 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
553 /* Save next pointer in case mqm gets freed by the callback */
557 if (NULL != mqm->env)
559 GNUNET_MQ_discard (mqm->env);
561 mqm->cb (mqm->cb_cls,
566 mqm->cb (mqm->cb_cls,
572 GNUNET_assert (NULL == mqm->env);
573 mqm->cb (mqm->cb_cls,
579 consider_peer_activate (cp);
581 consider_peer_destroy (cp);
586 /* have a new, direct path to the target, notify tunnel */
587 struct CadetPeerPath *path;
589 path = GCPP_get_path_from_route (1,
591 GCT_consider_path (cp->t,
599 * Debug function should NEVER return true in production code, useful to
600 * simulate losses for testcases.
602 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
607 if (0 == drop_percent)
609 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
617 * Function called when CORE took one of the messages from
618 * a message queue manager and transmitted it.
620 * @param cls the `struct CadetPeeer` where we made progress
623 mqm_send_done (void *cls);
627 * Transmit current envelope from this @a mqm.
629 * @param mqm mqm to transmit message for now
632 mqm_execute (struct GCP_MessageQueueManager *mqm)
634 struct CadetPeer *cp = mqm->cp;
636 /* Move ready pointer to the next entry that might be ready. */
637 if ( (mqm == cp->mqm_ready_ptr) &&
638 (NULL != mqm->next) )
639 cp->mqm_ready_ptr = mqm->next;
640 /* Move entry to the end of the DLL, to be fair. */
641 if (mqm != cp->mqm_tail)
643 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
646 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
650 cp->mqm_ready_counter--;
651 if (GNUNET_YES == should_I_drop ())
653 LOG (GNUNET_ERROR_TYPE_DEBUG,
654 "DROPPING message to peer %s from MQM %p\n",
657 GNUNET_MQ_discard (mqm->env);
664 const struct GNUNET_MessageHeader *mh;
666 mh = GNUNET_MQ_env_get_msg (mqm->env);
667 switch (ntohs (mh->type))
669 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
671 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg
672 = (const struct GNUNET_CADET_TunnelKeyExchangeMessage *) mh;
673 LOG (GNUNET_ERROR_TYPE_DEBUG,
674 "P2P forwarding KX with ephemeral %s to %s on CID %s\n",
675 GNUNET_e2s (&msg->ephemeral_key),
677 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
684 LOG (GNUNET_ERROR_TYPE_DEBUG,
685 "Sending to peer %s from MQM %p\n",
688 GNUNET_MQ_send (cp->core_mq,
692 mqm->cb (mqm->cb_cls,
698 * Find the next ready message in the queue (starting
699 * the search from the `cp->mqm_ready_ptr`) and if possible
700 * execute the transmission.
702 * @param cp peer to try to send the next ready message to
705 send_next_ready (struct CadetPeer *cp)
707 struct GCP_MessageQueueManager *mqm;
709 if (0 == cp->mqm_ready_counter)
711 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
713 cp->mqm_ready_ptr = mqm->next;
715 return; /* nothing to do */
721 * Function called when CORE took one of the messages from
722 * a message queue manager and transmitted it.
724 * @param cls the `struct CadetPeeer` where we made progress
727 mqm_send_done (void *cls)
729 struct CadetPeer *cp = cls;
731 LOG (GNUNET_ERROR_TYPE_DEBUG,
732 "Sending to peer %s completed\n",
734 send_next_ready (cp);
739 * Send the message in @a env to @a cp.
741 * @param mqm the message queue manager to use for transmission
742 * @param env envelope with the message to send; must NOT
743 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
746 GCP_send (struct GCP_MessageQueueManager *mqm,
747 struct GNUNET_MQ_Envelope *env)
749 struct CadetPeer *cp = mqm->cp;
751 GNUNET_assert (NULL != env);
752 LOG (GNUNET_ERROR_TYPE_DEBUG,
753 "Queueing message to peer %s in MQM %p\n",
756 GNUNET_assert (NULL != cp->core_mq);
757 GNUNET_assert (NULL == mqm->env);
758 GNUNET_MQ_notify_sent (env,
762 cp->mqm_ready_counter++;
763 if (mqm != cp->mqm_ready_ptr)
764 cp->mqm_ready_ptr = cp->mqm_head;
765 if (1 == cp->mqm_ready_counter)
766 cp->mqm_ready_ptr = mqm;
767 if (0 != GNUNET_MQ_get_length (cp->core_mq))
769 send_next_ready (cp);
774 * Function called to destroy a peer now.
777 * @param pid identity of the peer (unused)
778 * @param value the `struct CadetPeer` to clean up
779 * @return #GNUNET_OK (continue to iterate)
782 destroy_iterator_cb (void *cls,
783 const struct GNUNET_PeerIdentity *pid,
786 struct CadetPeer *cp = value;
788 if (NULL != cp->destroy_task)
790 GNUNET_SCHEDULER_cancel (cp->destroy_task);
791 cp->destroy_task = NULL;
799 * Clean up all entries about all peers.
800 * Must only be called after all tunnels, CORE-connections and
801 * connections are down.
804 GCP_destroy_all_peers ()
806 LOG (GNUNET_ERROR_TYPE_DEBUG,
807 "Destroying all peers now\n");
808 GNUNET_CONTAINER_multipeermap_iterate (peers,
809 &destroy_iterator_cb,
815 * Drop all paths owned by this peer, and do not
816 * allow new ones to be added: We are shutting down.
818 * @param cp peer to drop paths to
821 GCP_drop_owned_paths (struct CadetPeer *cp)
823 struct CadetPeerPath *path;
825 LOG (GNUNET_ERROR_TYPE_DEBUG,
826 "Destroying all paths to %s\n",
828 while (NULL != (path =
829 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
831 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
832 cp->path_heap = NULL;
837 * Add an entry to the DLL of all of the paths that this peer is on.
839 * @param cp peer to modify
840 * @param entry an entry on a path
841 * @param off offset of this peer on the path
844 GCP_path_entry_add (struct CadetPeer *cp,
845 struct CadetPeerPathEntry *entry,
848 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
850 LOG (GNUNET_ERROR_TYPE_DEBUG,
851 "Discovered that peer %s is on path %s at offset %u\n",
853 GCPP_2s (entry->path),
855 if (off >= cp->path_dll_length)
857 unsigned int len = cp->path_dll_length;
859 GNUNET_array_grow (cp->path_heads,
862 GNUNET_array_grow (cp->path_tails,
866 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
872 /* If we have a tunnel to this peer, tell the tunnel that there is a
873 new path available. */
875 GCT_consider_path (cp->t,
879 if ( (NULL != cp->search_h) &&
880 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
882 /* Now I have enough paths, stop search */
883 GCD_search_stop (cp->search_h);
886 if (NULL != cp->destroy_task)
888 /* paths changed, this resets the destroy timeout counter
889 and aborts a destroy task that may no longer be valid
890 to have (as we now have more paths via this peer). */
891 consider_peer_destroy (cp);
897 * Remove an entry from the DLL of all of the paths that this peer is on.
899 * @param cp peer to modify
900 * @param entry an entry on a path
901 * @param off offset of this peer on the path
904 GCP_path_entry_remove (struct CadetPeer *cp,
905 struct CadetPeerPathEntry *entry,
908 LOG (GNUNET_ERROR_TYPE_DEBUG,
909 "Removing knowledge about peer %s beging on path %s at offset %u\n",
911 GCPP_2s (entry->path),
913 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
916 GNUNET_assert (0 < cp->num_paths);
919 if ( (NULL == cp->core_mq) &&
921 (NULL == cp->search_h) &&
922 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
924 = GCD_search (&cp->pid);
925 if (NULL == cp->destroy_task)
927 /* paths changed, we might now be ready for destruction, check again */
928 consider_peer_destroy (cp);
934 * Prune down the number of paths to this peer, we seem to
937 * @param cls the `struct CadetPeer` to maintain the path heap for
940 path_heap_cleanup (void *cls)
942 struct CadetPeer *cp = cls;
943 struct CadetPeerPath *root;
945 cp->heap_cleanup_task = NULL;
946 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
947 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
949 /* Now we have way too many, drop least desirable UNLESS it is in use!
950 (Note that this intentionally keeps highly desireable, but currently
951 unused paths around in the hope that we might be able to switch, even
952 if the number of paths exceeds the threshold.) */
953 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
954 GNUNET_assert (NULL != root);
956 GCPP_get_connection (root,
958 GCPP_get_length (root) - 1))
959 break; /* can't fix */
960 /* Got plenty of paths to this destination, and this is a low-quality
961 one that we don't care about. Allow it to die. */
962 GNUNET_assert (root ==
963 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
970 * Try adding a @a path to this @a peer. If the peer already
971 * has plenty of paths, return NULL.
973 * @param cp peer to which the @a path leads to
974 * @param path a path looking for an owner; may not be fully initialized yet!
975 * @param off offset of @a cp in @a path
976 * @param force force attaching the path
977 * @return NULL if this peer does not care to become a new owner,
978 * otherwise the node in the peer's path heap for the @a path.
980 struct GNUNET_CONTAINER_HeapNode *
981 GCP_attach_path (struct CadetPeer *cp,
982 struct CadetPeerPath *path,
986 GNUNET_CONTAINER_HeapCostType desirability;
987 struct CadetPeerPath *root;
988 GNUNET_CONTAINER_HeapCostType root_desirability;
989 struct GNUNET_CONTAINER_HeapNode *hn;
991 GNUNET_assert (off == GCPP_get_length (path) - 1);
992 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
994 if (NULL == cp->path_heap)
996 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
997 GNUNET_assert (GNUNET_NO == force);
1000 desirability = GCPP_get_desirability (path);
1001 if (GNUNET_NO == force)
1003 /* FIXME: desirability is not yet initialized; tricky! */
1005 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
1007 &root_desirability))
1010 root_desirability = 0;
1013 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
1014 (desirability < root_desirability) )
1016 LOG (GNUNET_ERROR_TYPE_DEBUG,
1017 "Decided to not attach path %s to peer %s due to undesirability\n",
1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1025 "Attaching path %s to peer %s (%s)\n",
1028 (GNUNET_NO == force) ? "desirable" : "forced");
1030 /* Yes, we'd like to add this path, add to our heap */
1031 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1035 /* Consider maybe dropping other paths because of the new one */
1036 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1037 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1038 (NULL != cp->heap_cleanup_task) )
1039 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1046 * This peer can no longer own @a path as the path
1047 * has been extended and a peer further down the line
1048 * is now the new owner.
1050 * @param cp old owner of the @a path
1051 * @param path path where the ownership is lost
1052 * @param hn note in @a cp's path heap that must be deleted
1055 GCP_detach_path (struct CadetPeer *cp,
1056 struct CadetPeerPath *path,
1057 struct GNUNET_CONTAINER_HeapNode *hn)
1059 LOG (GNUNET_ERROR_TYPE_DEBUG,
1060 "Detatching path %s from peer %s\n",
1063 GNUNET_assert (path ==
1064 GNUNET_CONTAINER_heap_remove_node (hn));
1069 * Add a @a connection to this @a cp.
1071 * @param cp peer via which the @a connection goes
1072 * @param cc the connection to add
1075 GCP_add_connection (struct CadetPeer *cp,
1076 struct CadetConnection *cc)
1078 LOG (GNUNET_ERROR_TYPE_DEBUG,
1079 "Adding %s to peer %s\n",
1082 GNUNET_assert (GNUNET_OK ==
1083 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1084 &GCC_get_id (cc)->connection_of_tunnel,
1086 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1087 if (NULL != cp->destroy_task)
1089 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1090 cp->destroy_task = NULL;
1096 * Remove a @a connection that went via this @a cp.
1098 * @param cp peer via which the @a connection went
1099 * @param cc the connection to remove
1102 GCP_remove_connection (struct CadetPeer *cp,
1103 struct CadetConnection *cc)
1105 LOG (GNUNET_ERROR_TYPE_DEBUG,
1106 "Removing connection %s from peer %s\n",
1109 GNUNET_assert (GNUNET_YES ==
1110 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1111 &GCC_get_id (cc)->connection_of_tunnel,
1113 consider_peer_destroy (cp);
1118 * Retrieve the CadetPeer stucture associated with the
1119 * peer. Optionally create one and insert it in the appropriate
1120 * structures if the peer is not known yet.
1122 * @param peer_id Full identity of the peer.
1123 * @param create #GNUNET_YES if a new peer should be created if unknown.
1124 * #GNUNET_NO to return NULL if peer is unknown.
1125 * @return Existing or newly created peer structure.
1126 * NULL if unknown and not requested @a create
1129 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1132 struct CadetPeer *cp;
1134 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1138 if (GNUNET_NO == create)
1140 cp = GNUNET_new (struct CadetPeer);
1142 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1144 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1145 GNUNET_assert (GNUNET_YES ==
1146 GNUNET_CONTAINER_multipeermap_put (peers,
1149 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1150 LOG (GNUNET_ERROR_TYPE_DEBUG,
1151 "Creating peer %s\n",
1158 * Obtain the peer identity for a `struct CadetPeer`.
1160 * @param cp our peer handle
1161 * @return the peer identity
1163 const struct GNUNET_PeerIdentity *
1164 GCP_get_id (struct CadetPeer *cp)
1171 * Iterate over all known peers.
1173 * @param iter Iterator.
1174 * @param cls Closure for @c iter.
1177 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1180 GNUNET_CONTAINER_multipeermap_iterate (peers,
1187 * Count the number of known paths toward the peer.
1189 * @param cp Peer to get path info.
1190 * @return Number of known paths.
1193 GCP_count_paths (const struct CadetPeer *cp)
1195 return cp->num_paths;
1200 * Iterate over the paths to a peer.
1202 * @param cp Peer to get path info.
1203 * @param callback Function to call for every path.
1204 * @param callback_cls Closure for @a callback.
1205 * @return Number of iterated paths.
1208 GCP_iterate_paths (struct CadetPeer *cp,
1209 GCP_PathIterator callback,
1212 unsigned int ret = 0;
1214 LOG (GNUNET_ERROR_TYPE_DEBUG,
1215 "Iterating over paths to peer %s%s\n",
1217 (NULL == cp->core_mq) ? "" : " including direct link");
1218 if (NULL != cp->core_mq)
1220 struct CadetPeerPath *path;
1222 path = GCPP_get_path_from_route (1,
1226 callback (callback_cls,
1231 for (unsigned int i=0;i<cp->path_dll_length;i++)
1233 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1239 callback (callback_cls,
1249 * Iterate over the paths to a peer without direct link.
1251 * @param cp Peer to get path info.
1252 * @param callback Function to call for every path.
1253 * @param callback_cls Closure for @a callback.
1254 * @return Number of iterated paths.
1257 GCP_iterate_indirect_paths (struct CadetPeer *cp,
1258 GCP_PathIterator callback,
1261 unsigned int ret = 0;
1263 LOG (GNUNET_ERROR_TYPE_DEBUG,
1264 "Iterating over paths to peer %s without direct link\n",
1266 for (unsigned int i=1;i<cp->path_dll_length;i++)
1268 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1274 callback (callback_cls,
1285 * Iterate over the paths to @a cp where
1286 * @a cp is at distance @a dist from us.
1288 * @param cp Peer to get path info.
1289 * @param dist desired distance of @a cp to us on the path
1290 * @param callback Function to call for every path.
1291 * @param callback_cls Closure for @a callback.
1292 * @return Number of iterated paths.
1295 GCP_iterate_paths_at (struct CadetPeer *cp,
1297 GCP_PathIterator callback,
1300 unsigned int ret = 0;
1302 if (dist >= cp->path_dll_length)
1304 LOG (GNUNET_ERROR_TYPE_DEBUG,
1305 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1307 cp->path_dll_length);
1310 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1315 callback (callback_cls,
1326 * Get the tunnel towards a peer.
1328 * @param cp Peer to get from.
1329 * @param create #GNUNET_YES to create a tunnel if we do not have one
1330 * @return Tunnel towards peer.
1332 struct CadetTunnel *
1333 GCP_get_tunnel (struct CadetPeer *cp,
1338 if ( (NULL != cp->t) ||
1339 (GNUNET_NO == create) )
1341 cp->t = GCT_create_tunnel (cp);
1342 consider_peer_activate (cp);
1348 * Hello offer was passed to the transport service. Mark it
1351 * @param cls the `struct CadetPeer` where the offer completed
1354 hello_offer_done (void *cls)
1356 struct CadetPeer *cp = cls;
1358 cp->hello_offer = NULL;
1363 * We got a HELLO for a @a peer, remember it, and possibly
1364 * trigger adequate actions (like trying to connect).
1366 * @param cp the peer we got a HELLO for
1367 * @param hello the HELLO to remember
1370 GCP_set_hello (struct CadetPeer *cp,
1371 const struct GNUNET_HELLO_Message *hello)
1373 struct GNUNET_HELLO_Message *mrg;
1375 LOG (GNUNET_ERROR_TYPE_DEBUG,
1376 "Got %u byte HELLO for peer %s\n",
1377 (unsigned int) GNUNET_HELLO_size (hello),
1379 if (NULL != cp->hello_offer)
1381 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1382 cp->hello_offer = NULL;
1384 if (NULL != cp->hello)
1386 mrg = GNUNET_HELLO_merge (hello,
1388 GNUNET_free (cp->hello);
1393 cp->hello = GNUNET_memdup (hello,
1394 GNUNET_HELLO_size (hello));
1397 = GNUNET_TRANSPORT_offer_hello (cfg,
1398 GNUNET_HELLO_get_header (cp->hello) ,
1401 /* New HELLO means cp's destruction time may change... */
1402 consider_peer_destroy (cp);
1407 * The tunnel to the given peer no longer exists, remove it from our
1408 * data structures, and possibly clean up the peer itself.
1410 * @param cp the peer affected
1411 * @param t the dead tunnel
1414 GCP_drop_tunnel (struct CadetPeer *cp,
1415 struct CadetTunnel *t)
1417 LOG (GNUNET_ERROR_TYPE_DEBUG,
1418 "Dropping tunnel %s to peer %s\n",
1421 GNUNET_assert (cp->t == t);
1423 consider_peer_destroy (cp);
1428 * Test if @a cp has a core-level connection
1430 * @param cp peer to test
1431 * @return #GNUNET_YES if @a cp has a core-level connection
1434 GCP_has_core_connection (struct CadetPeer *cp)
1436 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1441 * Start message queue change notifications.
1443 * @param cp peer to notify for
1444 * @param cb function to call if mq becomes available or unavailable
1445 * @param cb_cls closure for @a cb
1446 * @return handle to cancel request
1448 struct GCP_MessageQueueManager *
1449 GCP_request_mq (struct CadetPeer *cp,
1450 GCP_MessageQueueNotificationCallback cb,
1453 struct GCP_MessageQueueManager *mqm;
1455 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1457 mqm->cb_cls = cb_cls;
1459 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1462 LOG (GNUNET_ERROR_TYPE_DEBUG,
1463 "Creating MQM %p for peer %s\n",
1466 if (NULL != cp->core_mq)
1474 * Stops message queue change notifications.
1476 * @param mqm handle matching request to cancel
1477 * @param last_env final message to transmit, or NULL
1480 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1481 struct GNUNET_MQ_Envelope *last_env)
1483 struct CadetPeer *cp = mqm->cp;
1485 LOG (GNUNET_ERROR_TYPE_DEBUG,
1486 "Destroying MQM %p for peer %s%s\n",
1489 (NULL == last_env) ? "" : " with last ditch transmission");
1490 if (NULL != mqm->env)
1491 GNUNET_MQ_discard (mqm->env);
1492 if (NULL != last_env)
1494 if (NULL != cp->core_mq)
1496 GNUNET_MQ_notify_sent (last_env,
1499 GNUNET_MQ_send (cp->core_mq,
1504 GNUNET_MQ_discard (last_env);
1507 if (cp->mqm_ready_ptr == mqm)
1508 cp->mqm_ready_ptr = mqm->next;
1509 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1517 * Send the message in @a env to @a cp, overriding queueing logic.
1518 * This function should only be used to send error messages outside
1519 * of flow and congestion control, similar to ICMP. Note that
1520 * the envelope may be silently discarded as well.
1522 * @param cp peer to send the message to
1523 * @param env envelope with the message to send
1526 GCP_send_ooo (struct CadetPeer *cp,
1527 struct GNUNET_MQ_Envelope *env)
1529 LOG (GNUNET_ERROR_TYPE_DEBUG,
1530 "Sending message to %s out of management\n",
1532 if (NULL == cp->core_mq)
1534 GNUNET_MQ_discard (env);
1537 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1539 GNUNET_MQ_discard (env);
1542 GNUNET_MQ_notify_sent (env,
1545 GNUNET_MQ_send (cp->core_mq,
1552 /* end of gnunet-service-cadet-new_peer.c */