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)
63 * Queue size when we start dropping OOO messages.
65 #define MAX_OOO_QUEUE_SIZE 100
69 * Data structure used to track whom we have to notify about changes
70 * to our message queue.
72 struct GCP_MessageQueueManager
78 struct GCP_MessageQueueManager *next;
83 struct GCP_MessageQueueManager *prev;
86 * Function to call with updated message queue object.
88 GCP_MessageQueueNotificationCallback cb;
96 * The peer this is for.
101 * Envelope this manager would like to transmit once it is its turn.
103 struct GNUNET_MQ_Envelope *env;
109 * Struct containing all information regarding a given peer
116 struct GNUNET_PeerIdentity pid;
119 * Last time we heard from this peer (currently not used!)
121 struct GNUNET_TIME_Absolute last_contactXXX;
124 * Array of DLLs of paths traversing the peer, organized by the
125 * offset of the peer on the larger path.
127 struct CadetPeerPathEntry **path_heads;
130 * Array of DLL of paths traversing the peer, organized by the
131 * offset of the peer on the larger path.
133 struct CadetPeerPathEntry **path_tails;
136 * Notifications to call when @e core_mq changes.
138 struct GCP_MessageQueueManager *mqm_head;
141 * Notifications to call when @e core_mq changes.
143 struct GCP_MessageQueueManager *mqm_tail;
146 * Pointer to first "ready" entry in @e mqm_head.
148 struct GCP_MessageQueueManager *mqm_ready_ptr;
151 * MIN-heap of paths owned by this peer (they also end at this
152 * peer). Ordered by desirability.
154 struct GNUNET_CONTAINER_Heap *path_heap;
157 * Handle to stop the DHT search for paths to this peer
159 struct GCD_search_handle *search_h;
162 * Task to clean up @e path_heap asynchronously.
164 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
167 * Task to destroy this entry.
169 struct GNUNET_SCHEDULER_Task *destroy_task;
172 * Tunnel to this peer, if any.
174 struct CadetTunnel *t;
177 * Connections that go through this peer; indexed by tid.
179 struct GNUNET_CONTAINER_MultiShortmap *connections;
182 * Handle for core transmissions.
184 struct GNUNET_MQ_Handle *core_mq;
187 * Hello message of the peer.
189 struct GNUNET_HELLO_Message *hello;
192 * Handle to us offering the HELLO to the transport.
194 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
197 * Handle to our ATS request asking ATS to suggest an address
198 * to TRANSPORT for this peer (to establish a direct link).
200 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
203 * How many messages are in the queue to this peer.
205 unsigned int queue_n;
208 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
210 unsigned int num_paths;
213 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
214 * Used to speed-up @GCP_get_desirability_of_path() calculation.
216 unsigned int off_sum;
219 * Number of message queue managers of this peer that have a message in waiting.
221 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
222 * TODO: could be replaced by another DLL that would then allow us to avoid
223 * the O(n)-scan of the DLL for ready entries!
225 unsigned int mqm_ready_counter;
228 * Current length of the @e path_heads and @path_tails arrays.
229 * The arrays should be grown as needed.
231 unsigned int path_dll_length;
237 * Get the static string for a peer ID.
240 * @return Static string for it's ID.
243 GCP_2s (const struct CadetPeer *cp)
247 GNUNET_snprintf (buf,
250 GNUNET_i2s (&cp->pid));
256 * Calculate how desirable a path is for @a cp if @a cp
257 * is at offset @a off.
259 * The 'desirability_table.c' program can be used to compute a list of
260 * sample outputs for different scenarios. Basically, we score paths
261 * lower if there are many alternatives, and higher if they are
262 * shorter than average, and very high if they are much shorter than
263 * average and without many alternatives.
265 * @param cp a peer reachable via a path
266 * @param off offset of @a cp in the path
267 * @return score how useful a path is to reach @a cp,
268 * positive scores mean path is more desirable
271 GCP_get_desirability_of_path (struct CadetPeer *cp,
274 unsigned int num_alts = cp->num_paths;
275 unsigned int off_sum;
280 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
281 GNUNET_assert (0 != cp->path_dll_length);
283 /* We maintain 'off_sum' in 'peer' and thereby
284 avoid the SLOW recalculation each time. Kept here
285 just to document what is going on. */
288 for (unsigned int j=0;j<cp->path_dll_length;j++)
289 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
293 GNUNET_assert (off_sum == cp->off_sum);
295 off_sum = cp->off_sum;
297 avg_sum = off_sum * 1.0 / cp->path_dll_length;
298 path_delta = off - avg_sum;
299 /* path_delta positiv: path off of peer above average (bad path for peer),
300 path_delta negativ: path off of peer below average (good path for peer) */
301 if (path_delta <= - 1.0)
302 weight_alts = - num_alts / path_delta; /* discount alternative paths */
303 else if (path_delta >= 1.0)
304 weight_alts = num_alts * path_delta; /* overcount alternative paths */
306 weight_alts = num_alts; /* count alternative paths normally */
309 /* off+1: long paths are generally harder to find and thus count
310 a bit more as they get longer. However, above-average paths
311 still need to count less, hence the squaring of that factor. */
312 return (off + 1.0) / (weight_alts * weight_alts);
317 * This peer is no longer be needed, clean it up now.
319 * @param cls peer to clean up
322 destroy_peer (void *cls)
324 struct CadetPeer *cp = cls;
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Destroying state about peer %s\n",
329 cp->destroy_task = NULL;
330 GNUNET_assert (NULL == cp->t);
331 GNUNET_assert (NULL == cp->core_mq);
332 GNUNET_assert (0 == cp->num_paths);
333 for (unsigned int i=0;i<cp->path_dll_length;i++)
334 GNUNET_assert (NULL == cp->path_heads[i]);
335 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
336 GNUNET_assert (GNUNET_YES ==
337 GNUNET_CONTAINER_multipeermap_remove (peers,
340 GNUNET_free_non_null (cp->path_heads);
341 GNUNET_free_non_null (cp->path_tails);
342 cp->path_dll_length = 0;
343 if (NULL != cp->search_h)
345 GCD_search_stop (cp->search_h);
348 /* FIXME: clean up search_delayedXXX! */
350 if (NULL != cp->hello_offer)
352 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
353 cp->hello_offer = NULL;
355 if (NULL != cp->connectivity_suggestion)
357 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
358 cp->connectivity_suggestion = NULL;
360 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
361 if (NULL != cp->path_heap)
363 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
364 cp->path_heap = NULL;
366 if (NULL != cp->heap_cleanup_task)
368 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
369 cp->heap_cleanup_task = NULL;
371 GNUNET_free_non_null (cp->hello);
372 /* Peer should not be freed if paths exist; if there are no paths,
373 there ought to be no connections, and without connections, no
374 notifications. Thus we can assert that mqm_head is empty at this
376 GNUNET_assert (NULL == cp->mqm_head);
377 GNUNET_assert (NULL == cp->mqm_ready_ptr);
383 * This peer is now on more "active" duty, activate processes related to it.
385 * @param cp the more-active peer
388 consider_peer_activate (struct CadetPeer *cp)
392 LOG (GNUNET_ERROR_TYPE_DEBUG,
393 "Updating peer %s activation state (%u connections)%s%s\n",
395 GNUNET_CONTAINER_multishortmap_size (cp->connections),
396 (NULL == cp->t) ? "" : " with tunnel",
397 (NULL == cp->core_mq) ? "" : " with CORE link");
398 if (NULL != cp->destroy_task)
400 /* It's active, do not destory! */
401 GNUNET_SCHEDULER_cancel (cp->destroy_task);
402 cp->destroy_task = NULL;
404 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
407 /* We're just on a path or directly connected; don't bother too much */
408 if (NULL != cp->connectivity_suggestion)
410 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
411 cp->connectivity_suggestion = NULL;
413 if (NULL != cp->search_h)
415 GCD_search_stop (cp->search_h);
420 if (NULL == cp->core_mq)
422 /* Lacks direct connection, try to create one by querying the DHT */
423 if ( (NULL == cp->search_h) &&
424 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
426 = GCD_search (&cp->pid);
430 /* Have direct connection, stop DHT search if active */
431 if (NULL != cp->search_h)
433 GCD_search_stop (cp->search_h);
438 /* If we have a tunnel, our urge for connections is much bigger */
439 strength = (NULL != cp->t) ? 32 : 1;
440 if (NULL != cp->connectivity_suggestion)
441 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
442 cp->connectivity_suggestion
443 = GNUNET_ATS_connectivity_suggest (ats_ch,
450 * This peer may no longer be needed, consider cleaning it up.
452 * @param cp peer to clean up
455 consider_peer_destroy (struct CadetPeer *cp);
459 * We really no longere care about a peer, stop hogging memory with paths to it.
460 * Afterwards, see if there is more to be cleaned up about this peer.
462 * @param cls a `struct CadetPeer`.
465 drop_paths (void *cls)
467 struct CadetPeer *cp = cls;
468 struct CadetPeerPath *path;
470 cp->destroy_task = NULL;
471 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
473 consider_peer_destroy (cp);
478 * This peer may no longer be needed, consider cleaning it up.
480 * @param cp peer to clean up
483 consider_peer_destroy (struct CadetPeer *cp)
485 struct GNUNET_TIME_Relative exp;
487 if (NULL != cp->destroy_task)
489 GNUNET_SCHEDULER_cancel (cp->destroy_task);
490 cp->destroy_task = NULL;
493 return; /* still relevant! */
494 if (NULL != cp->core_mq)
495 return; /* still relevant! */
496 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
497 return; /* still relevant! */
498 if ( (NULL != cp->path_heap) &&
499 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
501 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
506 if (0 != cp->num_paths)
507 return; /* still relevant! */
508 if (NULL != cp->hello)
510 /* relevant only until HELLO expires */
511 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
512 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
517 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
524 * Set the message queue to @a mq for peer @a cp and notify watchers.
526 * @param cp peer to modify
527 * @param mq message queue to set (can be NULL)
530 GCP_set_mq (struct CadetPeer *cp,
531 struct GNUNET_MQ_Handle *mq)
533 LOG (GNUNET_ERROR_TYPE_DEBUG,
534 "Message queue for peer %s is now %p\n",
538 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
542 /* Save next pointer in case mqm gets freed by the callback */
546 if (NULL != mqm->env)
548 GNUNET_MQ_discard (mqm->env);
550 mqm->cb (mqm->cb_cls,
555 mqm->cb (mqm->cb_cls,
561 GNUNET_assert (NULL == mqm->env);
562 mqm->cb (mqm->cb_cls,
568 consider_peer_activate (cp);
570 consider_peer_destroy (cp);
575 /* have a new, direct path to the target, notify tunnel */
576 struct CadetPeerPath *path;
578 path = GCPP_get_path_from_route (1,
580 GCT_consider_path (cp->t,
588 * Debug function should NEVER return true in production code, useful to
589 * simulate losses for testcases.
591 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
596 if (0 == drop_percent)
598 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
606 * Function called when CORE took one of the messages from
607 * a message queue manager and transmitted it.
609 * @param cls the `struct CadetPeeer` where we made progress
612 mqm_send_done (void *cls);
616 * Transmit current envelope from this @a mqm.
618 * @param mqm mqm to transmit message for now
621 mqm_execute (struct GCP_MessageQueueManager *mqm)
623 struct CadetPeer *cp = mqm->cp;
625 /* Move ready pointer to the next entry that might be ready. */
626 if ( (mqm == cp->mqm_ready_ptr) &&
627 (NULL != mqm->next) )
628 cp->mqm_ready_ptr = mqm->next;
629 /* Move entry to the end of the DLL, to be fair. */
630 if (mqm != cp->mqm_tail)
632 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
635 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
639 cp->mqm_ready_counter--;
640 if (GNUNET_YES == should_I_drop ())
642 LOG (GNUNET_ERROR_TYPE_DEBUG,
643 "DROPPING message to peer %s from MQM %p\n",
646 GNUNET_MQ_discard (mqm->env);
652 LOG (GNUNET_ERROR_TYPE_DEBUG,
653 "Sending to peer %s from MQM %p\n",
656 GNUNET_MQ_send (cp->core_mq,
660 mqm->cb (mqm->cb_cls,
666 * Find the next ready message in the queue (starting
667 * the search from the `cp->mqm_ready_ptr`) and if possible
668 * execute the transmission.
670 * @param cp peer to try to send the next ready message to
673 send_next_ready (struct CadetPeer *cp)
675 struct GCP_MessageQueueManager *mqm;
677 if (0 == cp->mqm_ready_counter)
679 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
681 cp->mqm_ready_ptr = mqm->next;
683 return; /* nothing to do */
689 * Function called when CORE took one of the messages from
690 * a message queue manager and transmitted it.
692 * @param cls the `struct CadetPeeer` where we made progress
695 mqm_send_done (void *cls)
697 struct CadetPeer *cp = cls;
699 LOG (GNUNET_ERROR_TYPE_DEBUG,
700 "Sending to peer %s completed\n",
702 send_next_ready (cp);
707 * Send the message in @a env to @a cp.
709 * @param mqm the message queue manager to use for transmission
710 * @param env envelope with the message to send; must NOT
711 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
714 GCP_send (struct GCP_MessageQueueManager *mqm,
715 struct GNUNET_MQ_Envelope *env)
717 struct CadetPeer *cp = mqm->cp;
719 GNUNET_assert (NULL != env);
720 LOG (GNUNET_ERROR_TYPE_DEBUG,
721 "Queueing message to peer %s in MQM %p\n",
724 GNUNET_assert (NULL != cp->core_mq);
725 GNUNET_assert (NULL == mqm->env);
726 GNUNET_MQ_notify_sent (env,
730 cp->mqm_ready_counter++;
731 if (mqm != cp->mqm_ready_ptr)
732 cp->mqm_ready_ptr = cp->mqm_head;
733 if (1 == cp->mqm_ready_counter)
734 cp->mqm_ready_ptr = mqm;
735 if (0 != GNUNET_MQ_get_length (cp->core_mq))
737 send_next_ready (cp);
742 * Function called to destroy a peer now.
745 * @param pid identity of the peer (unused)
746 * @param value the `struct CadetPeer` to clean up
747 * @return #GNUNET_OK (continue to iterate)
750 destroy_iterator_cb (void *cls,
751 const struct GNUNET_PeerIdentity *pid,
754 struct CadetPeer *cp = value;
756 if (NULL != cp->destroy_task)
758 GNUNET_SCHEDULER_cancel (cp->destroy_task);
759 cp->destroy_task = NULL;
767 * Clean up all entries about all peers.
768 * Must only be called after all tunnels, CORE-connections and
769 * connections are down.
772 GCP_destroy_all_peers ()
774 LOG (GNUNET_ERROR_TYPE_DEBUG,
775 "Destroying all peers now\n");
776 GNUNET_CONTAINER_multipeermap_iterate (peers,
777 &destroy_iterator_cb,
783 * Drop all paths owned by this peer, and do not
784 * allow new ones to be added: We are shutting down.
786 * @param cp peer to drop paths to
789 GCP_drop_owned_paths (struct CadetPeer *cp)
791 struct CadetPeerPath *path;
793 LOG (GNUNET_ERROR_TYPE_DEBUG,
794 "Destroying all paths to %s\n",
796 while (NULL != (path =
797 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
799 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
800 cp->path_heap = NULL;
805 * Add an entry to the DLL of all of the paths that this peer is on.
807 * @param cp peer to modify
808 * @param entry an entry on a path
809 * @param off offset of this peer on the path
812 GCP_path_entry_add (struct CadetPeer *cp,
813 struct CadetPeerPathEntry *entry,
816 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
818 LOG (GNUNET_ERROR_TYPE_DEBUG,
819 "Discovered that peer %s is on path %s at offset %u\n",
821 GCPP_2s (entry->path),
823 if (off >= cp->path_dll_length)
825 unsigned int len = cp->path_dll_length;
827 GNUNET_array_grow (cp->path_heads,
830 GNUNET_array_grow (cp->path_tails,
834 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
840 /* If we have a tunnel to this peer, tell the tunnel that there is a
841 new path available. */
843 GCT_consider_path (cp->t,
847 if ( (NULL != cp->search_h) &&
848 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
850 /* Now I have enough paths, stop search */
851 GCD_search_stop (cp->search_h);
854 if (NULL != cp->destroy_task)
856 /* paths changed, this resets the destroy timeout counter
857 and aborts a destroy task that may no longer be valid
858 to have (as we now have more paths via this peer). */
859 consider_peer_destroy (cp);
865 * Remove an entry from the DLL of all of the paths that this peer is on.
867 * @param cp peer to modify
868 * @param entry an entry on a path
869 * @param off offset of this peer on the path
872 GCP_path_entry_remove (struct CadetPeer *cp,
873 struct CadetPeerPathEntry *entry,
876 LOG (GNUNET_ERROR_TYPE_DEBUG,
877 "Removing knowledge about peer %s beging on path %s at offset %u\n",
879 GCPP_2s (entry->path),
881 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
884 GNUNET_assert (0 < cp->num_paths);
887 if ( (NULL == cp->core_mq) &&
889 (NULL == cp->search_h) &&
890 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
892 = GCD_search (&cp->pid);
893 if (NULL == cp->destroy_task)
895 /* paths changed, we might now be ready for destruction, check again */
896 consider_peer_destroy (cp);
902 * Prune down the number of paths to this peer, we seem to
905 * @param cls the `struct CadetPeer` to maintain the path heap for
908 path_heap_cleanup (void *cls)
910 struct CadetPeer *cp = cls;
911 struct CadetPeerPath *root;
913 cp->heap_cleanup_task = NULL;
914 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
915 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
917 /* Now we have way too many, drop least desirable UNLESS it is in use!
918 (Note that this intentionally keeps highly desireable, but currently
919 unused paths around in the hope that we might be able to switch, even
920 if the number of paths exceeds the threshold.) */
921 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
922 GNUNET_assert (NULL != root);
924 GCPP_get_connection (root,
926 GCPP_get_length (root) - 1))
927 break; /* can't fix */
928 /* Got plenty of paths to this destination, and this is a low-quality
929 one that we don't care about. Allow it to die. */
930 GNUNET_assert (root ==
931 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
938 * Try adding a @a path to this @a peer. If the peer already
939 * has plenty of paths, return NULL.
941 * @param cp peer to which the @a path leads to
942 * @param path a path looking for an owner; may not be fully initialized yet!
943 * @param off offset of @a cp in @a path
944 * @param force force attaching the path
945 * @return NULL if this peer does not care to become a new owner,
946 * otherwise the node in the peer's path heap for the @a path.
948 struct GNUNET_CONTAINER_HeapNode *
949 GCP_attach_path (struct CadetPeer *cp,
950 struct CadetPeerPath *path,
954 GNUNET_CONTAINER_HeapCostType desirability;
955 struct CadetPeerPath *root;
956 GNUNET_CONTAINER_HeapCostType root_desirability;
957 struct GNUNET_CONTAINER_HeapNode *hn;
959 GNUNET_assert (off == GCPP_get_length (path) - 1);
960 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
962 if (NULL == cp->path_heap)
964 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
965 GNUNET_assert (GNUNET_NO == force);
968 desirability = GCPP_get_desirability (path);
969 if (GNUNET_NO == force)
971 /* FIXME: desirability is not yet initialized; tricky! */
973 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
978 root_desirability = 0;
981 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
982 (desirability < root_desirability) )
984 LOG (GNUNET_ERROR_TYPE_DEBUG,
985 "Decided to not attach path %s to peer %s due to undesirability\n",
992 LOG (GNUNET_ERROR_TYPE_DEBUG,
993 "Attaching path %s to peer %s (%s)\n",
996 (GNUNET_NO == force) ? "desirable" : "forced");
998 /* Yes, we'd like to add this path, add to our heap */
999 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1003 /* Consider maybe dropping other paths because of the new one */
1004 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1005 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1006 (NULL != cp->heap_cleanup_task) )
1007 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1014 * This peer can no longer own @a path as the path
1015 * has been extended and a peer further down the line
1016 * is now the new owner.
1018 * @param cp old owner of the @a path
1019 * @param path path where the ownership is lost
1020 * @param hn note in @a cp's path heap that must be deleted
1023 GCP_detach_path (struct CadetPeer *cp,
1024 struct CadetPeerPath *path,
1025 struct GNUNET_CONTAINER_HeapNode *hn)
1027 LOG (GNUNET_ERROR_TYPE_DEBUG,
1028 "Detatching path %s from peer %s\n",
1031 GNUNET_assert (path ==
1032 GNUNET_CONTAINER_heap_remove_node (hn));
1037 * Add a @a connection to this @a cp.
1039 * @param cp peer via which the @a connection goes
1040 * @param cc the connection to add
1043 GCP_add_connection (struct CadetPeer *cp,
1044 struct CadetConnection *cc)
1046 LOG (GNUNET_ERROR_TYPE_DEBUG,
1047 "Adding connection %s to peer %s\n",
1050 GNUNET_assert (GNUNET_OK ==
1051 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1052 &GCC_get_id (cc)->connection_of_tunnel,
1054 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1055 if (NULL != cp->destroy_task)
1057 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1058 cp->destroy_task = NULL;
1064 * Remove a @a connection that went via this @a cp.
1066 * @param cp peer via which the @a connection went
1067 * @param cc the connection to remove
1070 GCP_remove_connection (struct CadetPeer *cp,
1071 struct CadetConnection *cc)
1073 LOG (GNUNET_ERROR_TYPE_DEBUG,
1074 "Removing connection %s from peer %s\n",
1077 GNUNET_assert (GNUNET_YES ==
1078 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1079 &GCC_get_id (cc)->connection_of_tunnel,
1081 consider_peer_destroy (cp);
1086 * Retrieve the CadetPeer stucture associated with the
1087 * peer. Optionally create one and insert it in the appropriate
1088 * structures if the peer is not known yet.
1090 * @param peer_id Full identity of the peer.
1091 * @param create #GNUNET_YES if a new peer should be created if unknown.
1092 * #GNUNET_NO to return NULL if peer is unknown.
1093 * @return Existing or newly created peer structure.
1094 * NULL if unknown and not requested @a create
1097 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1100 struct CadetPeer *cp;
1102 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1106 if (GNUNET_NO == create)
1108 cp = GNUNET_new (struct CadetPeer);
1110 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1112 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1113 GNUNET_assert (GNUNET_YES ==
1114 GNUNET_CONTAINER_multipeermap_put (peers,
1117 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1118 LOG (GNUNET_ERROR_TYPE_DEBUG,
1119 "Creating peer %s\n",
1126 * Obtain the peer identity for a `struct CadetPeer`.
1128 * @param cp our peer handle
1129 * @return the peer identity
1131 const struct GNUNET_PeerIdentity *
1132 GCP_get_id (struct CadetPeer *cp)
1139 * Iterate over all known peers.
1141 * @param iter Iterator.
1142 * @param cls Closure for @c iter.
1145 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1148 GNUNET_CONTAINER_multipeermap_iterate (peers,
1155 * Count the number of known paths toward the peer.
1157 * @param cp Peer to get path info.
1158 * @return Number of known paths.
1161 GCP_count_paths (const struct CadetPeer *cp)
1163 return cp->num_paths;
1168 * Iterate over the paths to a peer.
1170 * @param cp Peer to get path info.
1171 * @param callback Function to call for every path.
1172 * @param callback_cls Closure for @a callback.
1173 * @return Number of iterated paths.
1176 GCP_iterate_paths (struct CadetPeer *cp,
1177 GCP_PathIterator callback,
1180 unsigned int ret = 0;
1182 LOG (GNUNET_ERROR_TYPE_DEBUG,
1183 "Iterating over paths to peer %s%s\n",
1185 (NULL == cp->core_mq) ? "" : " including direct link");
1186 if (NULL != cp->core_mq)
1188 struct CadetPeerPath *path;
1190 path = GCPP_get_path_from_route (1,
1194 callback (callback_cls,
1199 for (unsigned int i=0;i<cp->path_dll_length;i++)
1201 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1207 callback (callback_cls,
1218 * Iterate over the paths to @a cp where
1219 * @a cp is at distance @a dist from us.
1221 * @param cp Peer to get path info.
1222 * @param dist desired distance of @a cp to us on the path
1223 * @param callback Function to call for every path.
1224 * @param callback_cls Closure for @a callback.
1225 * @return Number of iterated paths.
1228 GCP_iterate_paths_at (struct CadetPeer *cp,
1230 GCP_PathIterator callback,
1233 unsigned int ret = 0;
1235 if (dist >= cp->path_dll_length)
1237 LOG (GNUNET_ERROR_TYPE_DEBUG,
1238 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1240 cp->path_dll_length);
1243 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1248 callback (callback_cls,
1259 * Get the tunnel towards a peer.
1261 * @param cp Peer to get from.
1262 * @param create #GNUNET_YES to create a tunnel if we do not have one
1263 * @return Tunnel towards peer.
1265 struct CadetTunnel *
1266 GCP_get_tunnel (struct CadetPeer *cp,
1271 if ( (NULL != cp->t) ||
1272 (GNUNET_NO == create) )
1274 cp->t = GCT_create_tunnel (cp);
1275 consider_peer_activate (cp);
1281 * Hello offer was passed to the transport service. Mark it
1284 * @param cls the `struct CadetPeer` where the offer completed
1287 hello_offer_done (void *cls)
1289 struct CadetPeer *cp = cls;
1291 cp->hello_offer = NULL;
1296 * We got a HELLO for a @a peer, remember it, and possibly
1297 * trigger adequate actions (like trying to connect).
1299 * @param cp the peer we got a HELLO for
1300 * @param hello the HELLO to remember
1303 GCP_set_hello (struct CadetPeer *cp,
1304 const struct GNUNET_HELLO_Message *hello)
1306 struct GNUNET_HELLO_Message *mrg;
1308 LOG (GNUNET_ERROR_TYPE_DEBUG,
1309 "Got %u byte HELLO for peer %s\n",
1310 (unsigned int) GNUNET_HELLO_size (hello),
1312 if (NULL != cp->hello_offer)
1314 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1315 cp->hello_offer = NULL;
1317 if (NULL != cp->hello)
1319 mrg = GNUNET_HELLO_merge (hello,
1321 GNUNET_free (cp->hello);
1326 cp->hello = GNUNET_memdup (hello,
1327 GNUNET_HELLO_size (hello));
1330 = GNUNET_TRANSPORT_offer_hello (cfg,
1331 GNUNET_HELLO_get_header (cp->hello) ,
1334 /* New HELLO means cp's destruction time may change... */
1335 consider_peer_destroy (cp);
1340 * The tunnel to the given peer no longer exists, remove it from our
1341 * data structures, and possibly clean up the peer itself.
1343 * @param cp the peer affected
1344 * @param t the dead tunnel
1347 GCP_drop_tunnel (struct CadetPeer *cp,
1348 struct CadetTunnel *t)
1350 LOG (GNUNET_ERROR_TYPE_DEBUG,
1351 "Dropping tunnel %s to peer %s\n",
1354 GNUNET_assert (cp->t == t);
1356 consider_peer_destroy (cp);
1361 * Test if @a cp has a core-level connection
1363 * @param cp peer to test
1364 * @return #GNUNET_YES if @a cp has a core-level connection
1367 GCP_has_core_connection (struct CadetPeer *cp)
1369 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1374 * Start message queue change notifications.
1376 * @param cp peer to notify for
1377 * @param cb function to call if mq becomes available or unavailable
1378 * @param cb_cls closure for @a cb
1379 * @return handle to cancel request
1381 struct GCP_MessageQueueManager *
1382 GCP_request_mq (struct CadetPeer *cp,
1383 GCP_MessageQueueNotificationCallback cb,
1386 struct GCP_MessageQueueManager *mqm;
1388 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1390 mqm->cb_cls = cb_cls;
1392 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1395 LOG (GNUNET_ERROR_TYPE_DEBUG,
1396 "Creating MQM %p for peer %s\n",
1399 if (NULL != cp->core_mq)
1407 * Stops message queue change notifications.
1409 * @param mqm handle matching request to cancel
1410 * @param last_env final message to transmit, or NULL
1413 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1414 struct GNUNET_MQ_Envelope *last_env)
1416 struct CadetPeer *cp = mqm->cp;
1418 LOG (GNUNET_ERROR_TYPE_DEBUG,
1419 "Destroying MQM %p for peer %s%s\n",
1422 (NULL == last_env) ? "" : " with last ditch transmission");
1423 if (NULL != mqm->env)
1424 GNUNET_MQ_discard (mqm->env);
1425 if (NULL != last_env)
1427 if (NULL != cp->core_mq)
1429 GNUNET_MQ_notify_sent (last_env,
1432 GNUNET_MQ_send (cp->core_mq,
1437 GNUNET_MQ_discard (last_env);
1440 if (cp->mqm_ready_ptr == mqm)
1441 cp->mqm_ready_ptr = mqm->next;
1442 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1450 * Send the message in @a env to @a cp, overriding queueing logic.
1451 * This function should only be used to send error messages outside
1452 * of flow and congestion control, similar to ICMP. Note that
1453 * the envelope may be silently discarded as well.
1455 * @param cp peer to send the message to
1456 * @param env envelope with the message to send
1459 GCP_send_ooo (struct CadetPeer *cp,
1460 struct GNUNET_MQ_Envelope *env)
1462 LOG (GNUNET_ERROR_TYPE_DEBUG,
1463 "Sending message to %s out of management\n",
1465 if (NULL == cp->core_mq)
1467 GNUNET_MQ_discard (env);
1470 if (GNUNET_MQ_get_length (cp->core_mq) > MAX_OOO_QUEUE_SIZE)
1472 GNUNET_MQ_discard (env);
1475 GNUNET_MQ_notify_sent (env,
1478 GNUNET_MQ_send (cp->core_mq,
1485 /* end of gnunet-service-cadet-new_peer.c */