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-new_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-new.h"
43 #include "gnunet-service-cadet-new_connection.h"
44 #include "gnunet-service-cadet-new_dht.h"
45 #include "gnunet-service-cadet-new_peer.h"
46 #include "gnunet-service-cadet-new_paths.h"
47 #include "gnunet-service-cadet-new_tunnels.h"
50 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
54 * How long do we wait until tearing down an idle peer?
56 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
59 * How long do we keep paths around if we no longer care about the peer?
61 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
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 stop the DHT search for paths to this peer
162 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
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)
245 GNUNET_snprintf (buf,
248 GNUNET_i2s (&cp->pid));
254 * Calculate how desirable a path is for @a cp if @a cp
255 * is at offset @a off.
257 * The 'desirability_table.c' program can be used to compute a list of
258 * sample outputs for different scenarios. Basically, we score paths
259 * lower if there are many alternatives, and higher if they are
260 * shorter than average, and very high if they are much shorter than
261 * average and without many alternatives.
263 * @param cp a peer reachable via a path
264 * @param off offset of @a cp in the path
265 * @return score how useful a path is to reach @a cp,
266 * positive scores mean path is more desirable
269 GCP_get_desirability_of_path (struct CadetPeer *cp,
272 unsigned int num_alts = cp->num_paths;
273 unsigned int off_sum;
278 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
279 GNUNET_assert (0 != cp->path_dll_length);
281 /* We maintain 'off_sum' in 'peer' and thereby
282 avoid the SLOW recalculation each time. Kept here
283 just to document what is going on. */
286 for (unsigned int j=0;j<cp->path_dll_length;j++)
287 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
291 GNUNET_assert (off_sum == cp->off_sum);
293 off_sum = cp->off_sum;
295 avg_sum = off_sum * 1.0 / cp->path_dll_length;
296 path_delta = off - avg_sum;
297 /* path_delta positiv: path off of peer above average (bad path for peer),
298 path_delta negativ: path off of peer below average (good path for peer) */
299 if (path_delta <= - 1.0)
300 weight_alts = - num_alts / path_delta; /* discount alternative paths */
301 else if (path_delta >= 1.0)
302 weight_alts = num_alts * path_delta; /* overcount alternative paths */
304 weight_alts = num_alts; /* count alternative paths normally */
307 /* off+1: long paths are generally harder to find and thus count
308 a bit more as they get longer. However, above-average paths
309 still need to count less, hence the squaring of that factor. */
310 return (off + 1.0) / (weight_alts * weight_alts);
315 * This peer is no longer be needed, clean it up now.
317 * @param cls peer to clean up
320 destroy_peer (void *cls)
322 struct CadetPeer *cp = cls;
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Destroying state about peer %s\n",
327 cp->destroy_task = NULL;
328 GNUNET_assert (NULL == cp->t);
329 GNUNET_assert (NULL == cp->core_mq);
330 GNUNET_assert (0 == cp->num_paths);
331 for (unsigned int i=0;i<cp->path_dll_length;i++)
332 GNUNET_assert (NULL == cp->path_heads[i]);
333 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
334 GNUNET_assert (GNUNET_YES ==
335 GNUNET_CONTAINER_multipeermap_remove (peers,
338 GNUNET_free_non_null (cp->path_heads);
339 GNUNET_free_non_null (cp->path_tails);
340 cp->path_dll_length = 0;
341 if (NULL != cp->search_h)
343 GCD_search_stop (cp->search_h);
346 /* FIXME: clean up search_delayedXXX! */
348 if (NULL != cp->hello_offer)
350 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
351 cp->hello_offer = NULL;
353 if (NULL != cp->connectivity_suggestion)
355 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
356 cp->connectivity_suggestion = NULL;
358 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
359 if (NULL != cp->path_heap)
361 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
362 cp->path_heap = NULL;
364 GNUNET_free_non_null (cp->hello);
365 /* Peer should not be freed if paths exist; if there are no paths,
366 there ought to be no connections, and without connections, no
367 notifications. Thus we can assert that mqm_head is empty at this
369 GNUNET_assert (NULL == cp->mqm_head);
370 GNUNET_assert (NULL == cp->mqm_ready_ptr);
376 * This peer is now on more "active" duty, activate processes related to it.
378 * @param cp the more-active peer
381 consider_peer_activate (struct CadetPeer *cp)
385 LOG (GNUNET_ERROR_TYPE_DEBUG,
386 "Updating peer %s activation state (%u connections)%s%s\n",
388 GNUNET_CONTAINER_multishortmap_size (cp->connections),
389 (NULL == cp->t) ? "" : " with tunnel",
390 (NULL == cp->core_mq) ? "" : " with CORE link");
391 if (NULL != cp->destroy_task)
393 /* It's active, do not destory! */
394 GNUNET_SCHEDULER_cancel (cp->destroy_task);
395 cp->destroy_task = NULL;
397 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
400 /* We're just on a path or directly connected; don't bother too much */
401 if (NULL != cp->connectivity_suggestion)
403 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
404 cp->connectivity_suggestion = NULL;
406 if (NULL != cp->search_h)
408 GCD_search_stop (cp->search_h);
413 if (NULL == cp->core_mq)
415 /* Lacks direct connection, try to create one by querying the DHT */
416 if ( (NULL == cp->search_h) &&
417 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
419 = GCD_search (&cp->pid);
423 /* Have direct connection, stop DHT search if active */
424 if (NULL != cp->search_h)
426 GCD_search_stop (cp->search_h);
431 /* If we have a tunnel, our urge for connections is much bigger */
432 strength = (NULL != cp->t) ? 32 : 1;
433 if (NULL != cp->connectivity_suggestion)
434 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
435 cp->connectivity_suggestion
436 = GNUNET_ATS_connectivity_suggest (ats_ch,
443 * This peer may no longer be needed, consider cleaning it up.
445 * @param cp peer to clean up
448 consider_peer_destroy (struct CadetPeer *cp);
452 * We really no longere care about a peer, stop hogging memory with paths to it.
453 * Afterwards, see if there is more to be cleaned up about this peer.
455 * @param cls a `struct CadetPeer`.
458 drop_paths (void *cls)
460 struct CadetPeer *cp = cls;
461 struct CadetPeerPath *path;
463 cp->destroy_task = NULL;
464 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
466 consider_peer_destroy (cp);
471 * This peer may no longer be needed, consider cleaning it up.
473 * @param cp peer to clean up
476 consider_peer_destroy (struct CadetPeer *cp)
478 struct GNUNET_TIME_Relative exp;
480 if (NULL != cp->destroy_task)
482 GNUNET_SCHEDULER_cancel (cp->destroy_task);
483 cp->destroy_task = NULL;
486 return; /* still relevant! */
487 if (NULL != cp->core_mq)
488 return; /* still relevant! */
489 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
490 return; /* still relevant! */
491 if ( (NULL != cp->path_heap) &&
492 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
494 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
499 if (0 != cp->num_paths)
500 return; /* still relevant! */
501 if (NULL != cp->hello)
503 /* relevant only until HELLO expires */
504 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
505 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
510 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
517 * Set the message queue to @a mq for peer @a cp and notify watchers.
519 * @param cp peer to modify
520 * @param mq message queue to set (can be NULL)
523 GCP_set_mq (struct CadetPeer *cp,
524 struct GNUNET_MQ_Handle *mq)
526 LOG (GNUNET_ERROR_TYPE_DEBUG,
527 "Message queue for peer %s is now %p\n",
531 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
535 /* Save next pointer in case mqm gets freed by the callback */
539 if (NULL != mqm->env)
541 GNUNET_MQ_discard (mqm->env);
543 mqm->cb (mqm->cb_cls,
548 mqm->cb (mqm->cb_cls,
554 GNUNET_assert (NULL == mqm->env);
555 mqm->cb (mqm->cb_cls,
561 consider_peer_activate (cp);
563 consider_peer_destroy (cp);
568 /* have a new, direct path to the target, notify tunnel */
569 struct CadetPeerPath *path;
571 path = GCPP_get_path_from_route (1,
573 GCT_consider_path (cp->t,
581 * Debug function should NEVER return true in production code, useful to
582 * simulate losses for testcases.
584 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
589 if (0 == drop_percent)
591 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
599 * Function called when CORE took one of the messages from
600 * a message queue manager and transmitted it.
602 * @param cls the `struct CadetPeeer` where we made progress
605 mqm_send_done (void *cls);
609 * Transmit current envelope from this @a mqm.
611 * @param mqm mqm to transmit message for now
614 mqm_execute (struct GCP_MessageQueueManager *mqm)
616 struct CadetPeer *cp = mqm->cp;
618 /* Move ready pointer to the next entry that might be ready. */
619 if ( (mqm == cp->mqm_ready_ptr) &&
620 (NULL != mqm->next) )
621 cp->mqm_ready_ptr = mqm->next;
622 /* Move entry to the end of the DLL, to be fair. */
623 if (mqm != cp->mqm_tail)
625 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
628 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
632 cp->mqm_ready_counter--;
633 if (GNUNET_YES == should_I_drop ())
635 LOG (GNUNET_ERROR_TYPE_DEBUG,
636 "DROPPING message to peer %s from MQM %p\n",
639 GNUNET_MQ_discard (mqm->env);
645 LOG (GNUNET_ERROR_TYPE_DEBUG,
646 "Sending to peer %s from MQM %p\n",
649 GNUNET_MQ_send (cp->core_mq,
653 mqm->cb (mqm->cb_cls,
659 * Find the next ready message in the queue (starting
660 * the search from the `cp->mqm_ready_ptr`) and if possible
661 * execute the transmission.
663 * @param cp peer to try to send the next ready message to
666 send_next_ready (struct CadetPeer *cp)
668 struct GCP_MessageQueueManager *mqm;
670 if (0 == cp->mqm_ready_counter)
672 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
674 cp->mqm_ready_ptr = mqm->next;
676 return; /* nothing to do */
682 * Function called when CORE took one of the messages from
683 * a message queue manager and transmitted it.
685 * @param cls the `struct CadetPeeer` where we made progress
688 mqm_send_done (void *cls)
690 struct CadetPeer *cp = cls;
692 LOG (GNUNET_ERROR_TYPE_DEBUG,
693 "Sending to peer %s completed\n",
695 send_next_ready (cp);
700 * Send the message in @a env to @a cp.
702 * @param mqm the message queue manager to use for transmission
703 * @param env envelope with the message to send; must NOT
704 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
707 GCP_send (struct GCP_MessageQueueManager *mqm,
708 struct GNUNET_MQ_Envelope *env)
710 struct CadetPeer *cp = mqm->cp;
712 GNUNET_assert (NULL != env);
713 LOG (GNUNET_ERROR_TYPE_DEBUG,
714 "Queueing message to peer %s in MQM %p\n",
717 GNUNET_assert (NULL != cp->core_mq);
718 GNUNET_assert (NULL == mqm->env);
719 GNUNET_MQ_notify_sent (env,
723 cp->mqm_ready_counter++;
724 if (mqm != cp->mqm_ready_ptr)
725 cp->mqm_ready_ptr = cp->mqm_head;
726 if (1 == cp->mqm_ready_counter)
727 cp->mqm_ready_ptr = mqm;
728 if (0 != GNUNET_MQ_get_length (cp->core_mq))
730 send_next_ready (cp);
735 * Function called to destroy a peer now.
738 * @param pid identity of the peer (unused)
739 * @param value the `struct CadetPeer` to clean up
740 * @return #GNUNET_OK (continue to iterate)
743 destroy_iterator_cb (void *cls,
744 const struct GNUNET_PeerIdentity *pid,
747 struct CadetPeer *cp = value;
749 if (NULL != cp->destroy_task)
751 GNUNET_SCHEDULER_cancel (cp->destroy_task);
752 cp->destroy_task = NULL;
760 * Clean up all entries about all peers.
761 * Must only be called after all tunnels, CORE-connections and
762 * connections are down.
765 GCP_destroy_all_peers ()
767 LOG (GNUNET_ERROR_TYPE_DEBUG,
768 "Destroying all peers now\n");
769 GNUNET_CONTAINER_multipeermap_iterate (peers,
770 &destroy_iterator_cb,
776 * Drop all paths owned by this peer, and do not
777 * allow new ones to be added: We are shutting down.
779 * @param cp peer to drop paths to
782 GCP_drop_owned_paths (struct CadetPeer *cp)
784 struct CadetPeerPath *path;
786 LOG (GNUNET_ERROR_TYPE_DEBUG,
787 "Destroying all paths to %s\n",
789 while (NULL != (path =
790 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
792 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
793 cp->path_heap = NULL;
798 * Add an entry to the DLL of all of the paths that this peer is on.
800 * @param cp peer to modify
801 * @param entry an entry on a path
802 * @param off offset of this peer on the path
805 GCP_path_entry_add (struct CadetPeer *cp,
806 struct CadetPeerPathEntry *entry,
809 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
811 LOG (GNUNET_ERROR_TYPE_DEBUG,
812 "Discovered that peer %s is on path %s at offset %u\n",
814 GCPP_2s (entry->path),
816 if (off >= cp->path_dll_length)
818 unsigned int len = cp->path_dll_length;
820 GNUNET_array_grow (cp->path_heads,
823 GNUNET_array_grow (cp->path_tails,
827 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
833 /* If we have a tunnel to this peer, tell the tunnel that there is a
834 new path available. */
836 GCT_consider_path (cp->t,
840 if ( (NULL != cp->search_h) &&
841 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
843 /* Now I have enough paths, stop search */
844 GCD_search_stop (cp->search_h);
847 if (NULL != cp->destroy_task)
849 /* paths changed, this resets the destroy timeout counter
850 and aborts a destroy task that may no longer be valid
851 to have (as we now have more paths via this peer). */
852 consider_peer_destroy (cp);
858 * Remove an entry from the DLL of all of the paths that this peer is on.
860 * @param cp peer to modify
861 * @param entry an entry on a path
862 * @param off offset of this peer on the path
865 GCP_path_entry_remove (struct CadetPeer *cp,
866 struct CadetPeerPathEntry *entry,
869 LOG (GNUNET_ERROR_TYPE_DEBUG,
870 "Removing knowledge about peer %s beging on path %s at offset %u\n",
872 GCPP_2s (entry->path),
874 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
877 GNUNET_assert (0 < cp->num_paths);
880 if ( (NULL == cp->core_mq) &&
882 (NULL == cp->search_h) &&
883 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
885 = GCD_search (&cp->pid);
886 if (NULL == cp->destroy_task)
888 /* paths changed, we might now be ready for destruction, check again */
889 consider_peer_destroy (cp);
895 * Try adding a @a path to this @a peer. If the peer already
896 * has plenty of paths, return NULL.
898 * @param cp peer to which the @a path leads to
899 * @param path a path looking for an owner; may not be fully initialized yet!
900 * @param off offset of @a cp in @a path
901 * @param force force attaching the path
902 * @return NULL if this peer does not care to become a new owner,
903 * otherwise the node in the peer's path heap for the @a path.
905 struct GNUNET_CONTAINER_HeapNode *
906 GCP_attach_path (struct CadetPeer *cp,
907 struct CadetPeerPath *path,
911 GNUNET_CONTAINER_HeapCostType desirability;
912 struct CadetPeerPath *root;
913 GNUNET_CONTAINER_HeapCostType root_desirability;
914 struct GNUNET_CONTAINER_HeapNode *hn;
916 GNUNET_assert (off == GCPP_get_length (path) - 1);
917 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
919 if (NULL == cp->path_heap)
921 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
922 GNUNET_assert (GNUNET_NO == force);
925 desirability = GCPP_get_desirability (path);
926 if (GNUNET_NO == force)
928 /* FIXME: desirability is not yet initialized; tricky! */
930 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
935 root_desirability = 0;
938 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
939 (desirability < root_desirability) )
941 LOG (GNUNET_ERROR_TYPE_DEBUG,
942 "Decided to not attach path %p to peer %s due to undesirability\n",
949 LOG (GNUNET_ERROR_TYPE_DEBUG,
950 "Attaching path %s to peer %s (%s)\n",
953 (GNUNET_NO == force) ? "desirable" : "forced");
955 /* Yes, we'd like to add this path, add to our heap */
956 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
960 /* Consider maybe dropping other paths because of the new one */
961 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
962 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
964 /* Now we have way too many, drop least desirable UNLESS it is in use!
965 (Note that this intentionally keeps highly desireable, but currently
966 unused paths around in the hope that we might be able to switch, even
967 if the number of paths exceeds the threshold.) */
968 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
969 if ( (path != root) &&
971 GCPP_get_connection (root,
973 GCPP_get_length (root) - 1)) )
975 /* Got plenty of paths to this destination, and this is a low-quality
976 one that we don't care about. Allow it to die. */
977 GNUNET_assert (root ==
978 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
987 * This peer can no longer own @a path as the path
988 * has been extended and a peer further down the line
989 * is now the new owner.
991 * @param cp old owner of the @a path
992 * @param path path where the ownership is lost
993 * @param hn note in @a cp's path heap that must be deleted
996 GCP_detach_path (struct CadetPeer *cp,
997 struct CadetPeerPath *path,
998 struct GNUNET_CONTAINER_HeapNode *hn)
1000 LOG (GNUNET_ERROR_TYPE_DEBUG,
1001 "Detatching path %s from peer %s\n",
1004 GNUNET_assert (path ==
1005 GNUNET_CONTAINER_heap_remove_node (hn));
1010 * Add a @a connection to this @a cp.
1012 * @param cp peer via which the @a connection goes
1013 * @param cc the connection to add
1016 GCP_add_connection (struct CadetPeer *cp,
1017 struct CadetConnection *cc)
1019 LOG (GNUNET_ERROR_TYPE_DEBUG,
1020 "Adding connection %s to peer %s\n",
1023 GNUNET_assert (GNUNET_OK ==
1024 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1025 &GCC_get_id (cc)->connection_of_tunnel,
1027 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1028 if (NULL != cp->destroy_task)
1030 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1031 cp->destroy_task = NULL;
1037 * Remove a @a connection that went via this @a cp.
1039 * @param cp peer via which the @a connection went
1040 * @param cc the connection to remove
1043 GCP_remove_connection (struct CadetPeer *cp,
1044 struct CadetConnection *cc)
1046 LOG (GNUNET_ERROR_TYPE_DEBUG,
1047 "Removing connection %s from peer %s\n",
1050 GNUNET_assert (GNUNET_YES ==
1051 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1052 &GCC_get_id (cc)->connection_of_tunnel,
1054 consider_peer_destroy (cp);
1059 * Retrieve the CadetPeer stucture associated with the
1060 * peer. Optionally create one and insert it in the appropriate
1061 * structures if the peer is not known yet.
1063 * @param peer_id Full identity of the peer.
1064 * @param create #GNUNET_YES if a new peer should be created if unknown.
1065 * #GNUNET_NO to return NULL if peer is unknown.
1066 * @return Existing or newly created peer structure.
1067 * NULL if unknown and not requested @a create
1070 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1073 struct CadetPeer *cp;
1075 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1079 if (GNUNET_NO == create)
1081 cp = GNUNET_new (struct CadetPeer);
1083 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1085 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1086 GNUNET_assert (GNUNET_YES ==
1087 GNUNET_CONTAINER_multipeermap_put (peers,
1090 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1091 LOG (GNUNET_ERROR_TYPE_DEBUG,
1092 "Creating peer %s\n",
1099 * Obtain the peer identity for a `struct CadetPeer`.
1101 * @param cp our peer handle
1102 * @return the peer identity
1104 const struct GNUNET_PeerIdentity *
1105 GCP_get_id (struct CadetPeer *cp)
1112 * Iterate over all known peers.
1114 * @param iter Iterator.
1115 * @param cls Closure for @c iter.
1118 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1121 GNUNET_CONTAINER_multipeermap_iterate (peers,
1128 * Count the number of known paths toward the peer.
1130 * @param cp Peer to get path info.
1131 * @return Number of known paths.
1134 GCP_count_paths (const struct CadetPeer *cp)
1136 return cp->num_paths;
1141 * Iterate over the paths to a peer.
1143 * @param cp Peer to get path info.
1144 * @param callback Function to call for every path.
1145 * @param callback_cls Closure for @a callback.
1146 * @return Number of iterated paths.
1149 GCP_iterate_paths (struct CadetPeer *cp,
1150 GCP_PathIterator callback,
1153 unsigned int ret = 0;
1155 LOG (GNUNET_ERROR_TYPE_DEBUG,
1156 "Iterating over paths to peer %s%s\n",
1158 (NULL == cp->core_mq) ? "" : " including direct link");
1159 if (NULL != cp->core_mq)
1161 struct CadetPeerPath *path;
1163 path = GCPP_get_path_from_route (1,
1167 callback (callback_cls,
1172 for (unsigned int i=0;i<cp->path_dll_length;i++)
1174 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1180 callback (callback_cls,
1191 * Iterate over the paths to @a cp where
1192 * @a cp is at distance @a dist from us.
1194 * @param cp Peer to get path info.
1195 * @param dist desired distance of @a cp to us on the path
1196 * @param callback Function to call for every path.
1197 * @param callback_cls Closure for @a callback.
1198 * @return Number of iterated paths.
1201 GCP_iterate_paths_at (struct CadetPeer *cp,
1203 GCP_PathIterator callback,
1206 unsigned int ret = 0;
1208 if (dist >= cp->path_dll_length)
1210 LOG (GNUNET_ERROR_TYPE_DEBUG,
1211 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1213 cp->path_dll_length);
1216 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1221 callback (callback_cls,
1232 * Get the tunnel towards a peer.
1234 * @param cp Peer to get from.
1235 * @param create #GNUNET_YES to create a tunnel if we do not have one
1236 * @return Tunnel towards peer.
1238 struct CadetTunnel *
1239 GCP_get_tunnel (struct CadetPeer *cp,
1244 if ( (NULL != cp->t) ||
1245 (GNUNET_NO == create) )
1247 cp->t = GCT_create_tunnel (cp);
1248 consider_peer_activate (cp);
1254 * Hello offer was passed to the transport service. Mark it
1257 * @param cls the `struct CadetPeer` where the offer completed
1260 hello_offer_done (void *cls)
1262 struct CadetPeer *cp = cls;
1264 cp->hello_offer = NULL;
1269 * We got a HELLO for a @a peer, remember it, and possibly
1270 * trigger adequate actions (like trying to connect).
1272 * @param cp the peer we got a HELLO for
1273 * @param hello the HELLO to remember
1276 GCP_set_hello (struct CadetPeer *cp,
1277 const struct GNUNET_HELLO_Message *hello)
1279 struct GNUNET_HELLO_Message *mrg;
1281 LOG (GNUNET_ERROR_TYPE_DEBUG,
1282 "Got %u byte HELLO for peer %s\n",
1283 (unsigned int) GNUNET_HELLO_size (hello),
1285 if (NULL != cp->hello_offer)
1287 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1288 cp->hello_offer = NULL;
1290 if (NULL != cp->hello)
1292 mrg = GNUNET_HELLO_merge (hello,
1294 GNUNET_free (cp->hello);
1299 cp->hello = GNUNET_memdup (hello,
1300 GNUNET_HELLO_size (hello));
1303 = GNUNET_TRANSPORT_offer_hello (cfg,
1304 GNUNET_HELLO_get_header (cp->hello) ,
1307 /* New HELLO means cp's destruction time may change... */
1308 consider_peer_destroy (cp);
1313 * The tunnel to the given peer no longer exists, remove it from our
1314 * data structures, and possibly clean up the peer itself.
1316 * @param cp the peer affected
1317 * @param t the dead tunnel
1320 GCP_drop_tunnel (struct CadetPeer *cp,
1321 struct CadetTunnel *t)
1323 LOG (GNUNET_ERROR_TYPE_DEBUG,
1324 "Dropping tunnel %s to peer %s\n",
1327 GNUNET_assert (cp->t == t);
1329 consider_peer_destroy (cp);
1334 * Test if @a cp has a core-level connection
1336 * @param cp peer to test
1337 * @return #GNUNET_YES if @a cp has a core-level connection
1340 GCP_has_core_connection (struct CadetPeer *cp)
1342 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1347 * Start message queue change notifications.
1349 * @param cp peer to notify for
1350 * @param cb function to call if mq becomes available or unavailable
1351 * @param cb_cls closure for @a cb
1352 * @return handle to cancel request
1354 struct GCP_MessageQueueManager *
1355 GCP_request_mq (struct CadetPeer *cp,
1356 GCP_MessageQueueNotificationCallback cb,
1359 struct GCP_MessageQueueManager *mqm;
1361 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1363 mqm->cb_cls = cb_cls;
1365 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1368 LOG (GNUNET_ERROR_TYPE_DEBUG,
1369 "Creating MQM %p for peer %s\n",
1372 if (NULL != cp->core_mq)
1380 * Stops message queue change notifications.
1382 * @param mqm handle matching request to cancel
1383 * @param last_env final message to transmit, or NULL
1386 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1387 struct GNUNET_MQ_Envelope *last_env)
1389 struct CadetPeer *cp = mqm->cp;
1391 LOG (GNUNET_ERROR_TYPE_DEBUG,
1392 "Destroying MQM %p for peer %s%s\n",
1395 (NULL == last_env) ? "" : " with last ditch transmission");
1396 if (NULL != mqm->env)
1397 GNUNET_MQ_discard (mqm->env);
1398 if (NULL != last_env)
1400 if (NULL != cp->core_mq)
1402 GNUNET_MQ_notify_sent (last_env,
1405 GNUNET_MQ_send (cp->core_mq,
1410 GNUNET_MQ_discard (last_env);
1413 if (cp->mqm_ready_ptr == mqm)
1414 cp->mqm_ready_ptr = mqm->next;
1415 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1423 * Send the message in @a env to @a cp, overriding queueing logic.
1424 * This function should only be used to send error messages outside
1425 * of flow and congestion control, similar to ICMP. Note that
1426 * the envelope may be silently discarded as well.
1428 * @param cp peer to send the message to
1429 * @param env envelope with the message to send
1432 GCP_send_ooo (struct CadetPeer *cp,
1433 struct GNUNET_MQ_Envelope *env)
1435 LOG (GNUNET_ERROR_TYPE_DEBUG,
1436 "Sending message to %s out of management\n",
1438 if (NULL == cp->core_mq)
1440 GNUNET_MQ_discard (env);
1443 GNUNET_MQ_notify_sent (env,
1446 GNUNET_MQ_send (cp->core_mq,
1453 /* end of gnunet-service-cadet-new_peer.c */