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 * Number of message queue managers of this peer that have a message in waiting.
213 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
214 * TODO: could be replaced by another DLL that would then allow us to avoid
215 * the O(n)-scan of the DLL for ready entries!
217 unsigned int mqm_ready_counter;
220 * Current length of the @e path_heads and @path_tails arrays.
221 * The arrays should be grown as needed.
223 unsigned int path_dll_length;
229 * Get the static string for a peer ID.
232 * @return Static string for it's ID.
235 GCP_2s (const struct CadetPeer *cp)
239 GNUNET_snprintf (buf,
242 GNUNET_i2s (&cp->pid));
248 * This peer is no longer be needed, clean it up now.
250 * @param cls peer to clean up
253 destroy_peer (void *cls)
255 struct CadetPeer *cp = cls;
257 LOG (GNUNET_ERROR_TYPE_DEBUG,
258 "Destroying state about peer %s\n",
260 cp->destroy_task = NULL;
261 GNUNET_assert (NULL == cp->t);
262 GNUNET_assert (NULL == cp->core_mq);
263 for (unsigned int i=0;i<cp->path_dll_length;i++)
264 GNUNET_assert (NULL == cp->path_heads[i]);
265 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
266 GNUNET_assert (GNUNET_YES ==
267 GNUNET_CONTAINER_multipeermap_remove (peers,
270 GNUNET_free_non_null (cp->path_heads);
271 GNUNET_free_non_null (cp->path_tails);
272 cp->path_dll_length = 0;
273 if (NULL != cp->search_h)
275 GCD_search_stop (cp->search_h);
278 /* FIXME: clean up search_delayedXXX! */
280 if (NULL != cp->hello_offer)
282 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
283 cp->hello_offer = NULL;
285 if (NULL != cp->connectivity_suggestion)
287 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
288 cp->connectivity_suggestion = NULL;
290 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
291 if (NULL != cp->path_heap)
293 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
294 cp->path_heap = NULL;
296 GNUNET_free_non_null (cp->hello);
297 /* Peer should not be freed if paths exist; if there are no paths,
298 there ought to be no connections, and without connections, no
299 notifications. Thus we can assert that mqm_head is empty at this
301 GNUNET_assert (NULL == cp->mqm_head);
302 GNUNET_assert (NULL == cp->mqm_ready_ptr);
308 * This peer is now on more "active" duty, activate processes related to it.
310 * @param cp the more-active peer
313 consider_peer_activate (struct CadetPeer *cp)
317 LOG (GNUNET_ERROR_TYPE_DEBUG,
318 "Updating peer %s activation state (%u connections)%s%s\n",
320 GNUNET_CONTAINER_multishortmap_size (cp->connections),
321 (NULL == cp->t) ? "" : " with tunnel",
322 (NULL == cp->core_mq) ? "" : " with CORE link");
323 if (NULL != cp->destroy_task)
325 /* It's active, do not destory! */
326 GNUNET_SCHEDULER_cancel (cp->destroy_task);
327 cp->destroy_task = NULL;
329 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
332 /* We're just on a path or directly connected; don't bother too much */
333 if (NULL != cp->connectivity_suggestion)
335 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
336 cp->connectivity_suggestion = NULL;
338 if (NULL != cp->search_h)
340 GCD_search_stop (cp->search_h);
345 if (NULL == cp->core_mq)
347 /* Lacks direct connection, try to create one by querying the DHT */
348 if ( (NULL == cp->search_h) &&
349 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
351 = GCD_search (&cp->pid);
355 /* Have direct connection, stop DHT search if active */
356 if (NULL != cp->search_h)
358 GCD_search_stop (cp->search_h);
363 /* If we have a tunnel, our urge for connections is much bigger */
364 strength = (NULL != cp->t) ? 32 : 1;
365 if (NULL != cp->connectivity_suggestion)
366 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
367 cp->connectivity_suggestion
368 = GNUNET_ATS_connectivity_suggest (ats_ch,
375 * This peer may no longer be needed, consider cleaning it up.
377 * @param cp peer to clean up
380 consider_peer_destroy (struct CadetPeer *cp);
384 * We really no longere care about a peer, stop hogging memory with paths to it.
385 * Afterwards, see if there is more to be cleaned up about this peer.
387 * @param cls a `struct CadetPeer`.
390 drop_paths (void *cls)
392 struct CadetPeer *cp = cls;
393 struct CadetPeerPath *path;
395 cp->destroy_task = NULL;
396 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
398 consider_peer_destroy (cp);
403 * This peer may no longer be needed, consider cleaning it up.
405 * @param cp peer to clean up
408 consider_peer_destroy (struct CadetPeer *cp)
410 struct GNUNET_TIME_Relative exp;
412 if (NULL != cp->destroy_task)
414 GNUNET_SCHEDULER_cancel (cp->destroy_task);
415 cp->destroy_task = NULL;
418 return; /* still relevant! */
419 if (NULL != cp->core_mq)
420 return; /* still relevant! */
421 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
422 return; /* still relevant! */
423 if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
425 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
430 for (unsigned int i=0;i<cp->path_dll_length;i++)
431 if (NULL != cp->path_heads[i])
432 return; /* still relevant! */
433 if (NULL != cp->hello)
435 /* relevant only until HELLO expires */
436 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
437 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
442 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
449 * Set the message queue to @a mq for peer @a cp and notify watchers.
451 * @param cp peer to modify
452 * @param mq message queue to set (can be NULL)
455 GCP_set_mq (struct CadetPeer *cp,
456 struct GNUNET_MQ_Handle *mq)
458 LOG (GNUNET_ERROR_TYPE_DEBUG,
459 "Message queue for peer %s is now %p\n",
463 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
469 if (NULL != mqm->env)
471 GNUNET_MQ_discard (mqm->env);
473 mqm->cb (mqm->cb_cls,
478 mqm->cb (mqm->cb_cls,
484 GNUNET_assert (NULL == mqm->env);
485 mqm->cb (mqm->cb_cls,
491 consider_peer_activate (cp);
493 consider_peer_destroy (cp);
498 /* have a new, direct path to the target, notify tunnel */
499 struct CadetPeerPath *path;
501 path = GCPP_get_path_from_route (1,
503 GCT_consider_path (cp->t,
511 * Debug function should NEVER return true in production code, useful to
512 * simulate losses for testcases.
514 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
519 if (0 == drop_percent)
521 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
529 * Function called when CORE took one of the messages from
530 * a message queue manager and transmitted it.
532 * @param cls the `struct CadetPeeer` where we made progress
535 mqm_send_done (void *cls);
539 * Transmit current envelope from this @a mqm.
541 * @param mqm mqm to transmit message for now
544 mqm_execute (struct GCP_MessageQueueManager *mqm)
546 struct CadetPeer *cp = mqm->cp;
548 /* Move ready pointer to the next entry that might be ready. */
549 if ( (mqm == cp->mqm_ready_ptr) &&
550 (NULL != mqm->next) )
551 cp->mqm_ready_ptr = mqm->next;
552 /* Move entry to the end of the DLL, to be fair. */
553 if (mqm != cp->mqm_tail)
555 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
558 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
562 cp->mqm_ready_counter--;
563 if (GNUNET_YES == should_I_drop ())
565 LOG (GNUNET_ERROR_TYPE_DEBUG,
566 "DROPPING message to peer %s from MQM %p\n",
569 GNUNET_MQ_discard (mqm->env);
575 LOG (GNUNET_ERROR_TYPE_DEBUG,
576 "Sending to peer %s from MQM %p\n",
579 GNUNET_MQ_send (cp->core_mq,
583 mqm->cb (mqm->cb_cls,
589 * Find the next ready message in the queue (starting
590 * the search from the `cp->mqm_ready_ptr`) and if possible
591 * execute the transmission.
593 * @param cp peer to try to send the next ready message to
596 send_next_ready (struct CadetPeer *cp)
598 struct GCP_MessageQueueManager *mqm;
600 if (0 == cp->mqm_ready_counter)
602 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
604 cp->mqm_ready_ptr = mqm->next;
606 return; /* nothing to do */
612 * Function called when CORE took one of the messages from
613 * a message queue manager and transmitted it.
615 * @param cls the `struct CadetPeeer` where we made progress
618 mqm_send_done (void *cls)
620 struct CadetPeer *cp = cls;
622 LOG (GNUNET_ERROR_TYPE_DEBUG,
623 "Sending to peer %s completed\n",
625 send_next_ready (cp);
630 * Send the message in @a env to @a cp.
632 * @param mqm the message queue manager to use for transmission
633 * @param env envelope with the message to send; must NOT
634 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
637 GCP_send (struct GCP_MessageQueueManager *mqm,
638 struct GNUNET_MQ_Envelope *env)
640 struct CadetPeer *cp = mqm->cp;
642 GNUNET_assert (NULL != env);
643 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 "Queueing message to peer %s in MQM %p\n",
647 GNUNET_assert (NULL != cp->core_mq);
648 GNUNET_assert (NULL == mqm->env);
649 GNUNET_MQ_notify_sent (env,
653 cp->mqm_ready_counter++;
654 if (mqm != cp->mqm_ready_ptr)
655 cp->mqm_ready_ptr = cp->mqm_head;
656 if (1 == cp->mqm_ready_counter)
657 cp->mqm_ready_ptr = mqm;
658 if (0 != GNUNET_MQ_get_length (cp->core_mq))
660 send_next_ready (cp);
665 * Function called to destroy a peer now.
668 * @param pid identity of the peer (unused)
669 * @param value the `struct CadetPeer` to clean up
670 * @return #GNUNET_OK (continue to iterate)
673 destroy_iterator_cb (void *cls,
674 const struct GNUNET_PeerIdentity *pid,
677 struct CadetPeer *cp = value;
679 if (NULL != cp->destroy_task)
681 GNUNET_SCHEDULER_cancel (cp->destroy_task);
682 cp->destroy_task = NULL;
690 * Clean up all entries about all peers.
691 * Must only be called after all tunnels, CORE-connections and
692 * connections are down.
695 GCP_destroy_all_peers ()
697 LOG (GNUNET_ERROR_TYPE_DEBUG,
698 "Destroying all peers now\n");
699 GNUNET_CONTAINER_multipeermap_iterate (peers,
700 &destroy_iterator_cb,
706 * Drop all paths owned by this peer, and do not
707 * allow new ones to be added: We are shutting down.
709 * @param cp peer to drop paths to
712 GCP_drop_owned_paths (struct CadetPeer *cp)
714 struct CadetPeerPath *path;
716 LOG (GNUNET_ERROR_TYPE_DEBUG,
717 "Destroying all paths to %s\n",
719 while (NULL != (path =
720 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
722 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
723 cp->path_heap = NULL;
728 * Add an entry to the DLL of all of the paths that this peer is on.
730 * @param cp peer to modify
731 * @param entry an entry on a path
732 * @param off offset of this peer on the path
735 GCP_path_entry_add (struct CadetPeer *cp,
736 struct CadetPeerPathEntry *entry,
739 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
741 LOG (GNUNET_ERROR_TYPE_DEBUG,
742 "Discovered that peer %s is on path %s at offset %u\n",
744 GCPP_2s (entry->path),
746 if (off >= cp->path_dll_length)
748 unsigned int len = cp->path_dll_length;
750 GNUNET_array_grow (cp->path_heads,
753 GNUNET_array_grow (cp->path_tails,
757 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
762 /* If we have a tunnel to this peer, tell the tunnel that there is a
763 new path available. */
765 GCT_consider_path (cp->t,
769 if ( (NULL != cp->search_h) &&
770 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
772 /* Now I have enough paths, stop search */
773 GCD_search_stop (cp->search_h);
780 * Remove an entry from the DLL of all of the paths that this peer is on.
782 * @param cp peer to modify
783 * @param entry an entry on a path
784 * @param off offset of this peer on the path
787 GCP_path_entry_remove (struct CadetPeer *cp,
788 struct CadetPeerPathEntry *entry,
791 LOG (GNUNET_ERROR_TYPE_DEBUG,
792 "Removing knowledge about peer %s beging on path %s at offset %u\n",
794 GCPP_2s (entry->path),
796 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
799 GNUNET_assert (0 < cp->num_paths);
801 if ( (NULL == cp->core_mq) &&
803 (NULL == cp->search_h) &&
804 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
806 = GCD_search (&cp->pid);
811 * Try adding a @a path to this @a peer. If the peer already
812 * has plenty of paths, return NULL.
814 * @param cp peer to which the @a path leads to
815 * @param path a path looking for an owner; may not be fully initialized yet!
816 * @param off offset of @a cp in @a path
817 * @param force force attaching the path
818 * @return NULL if this peer does not care to become a new owner,
819 * otherwise the node in the peer's path heap for the @a path.
821 struct GNUNET_CONTAINER_HeapNode *
822 GCP_attach_path (struct CadetPeer *cp,
823 struct CadetPeerPath *path,
827 GNUNET_CONTAINER_HeapCostType desirability;
828 struct CadetPeerPath *root;
829 GNUNET_CONTAINER_HeapCostType root_desirability;
830 struct GNUNET_CONTAINER_HeapNode *hn;
832 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
834 if (NULL == cp->path_heap)
836 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
837 GNUNET_assert (GNUNET_NO == force);
840 desirability = GCPP_get_desirability (path);
841 if (GNUNET_NO == force)
843 /* FIXME: desirability is not yet initialized; tricky! */
845 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
850 root_desirability = 0;
853 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
854 (desirability < root_desirability) )
856 LOG (GNUNET_ERROR_TYPE_DEBUG,
857 "Decided to not attach path %p to peer %s due to undesirability\n",
864 LOG (GNUNET_ERROR_TYPE_DEBUG,
865 "Attaching path %s to peer %s (%s)\n",
868 (GNUNET_NO == force) ? "desirable" : "forced");
870 /* Yes, we'd like to add this path, add to our heap */
871 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
875 /* Consider maybe dropping other paths because of the new one */
876 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
877 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
879 /* Now we have way too many, drop least desirable UNLESS it is in use!
880 (Note that this intentionally keeps highly desireable, but currently
881 unused paths around in the hope that we might be able to switch, even
882 if the number of paths exceeds the threshold.) */
883 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
884 if ( (path != root) &&
886 GCPP_get_connection (root,
888 GCPP_get_length (root) - 1)) )
890 /* Got plenty of paths to this destination, and this is a low-quality
891 one that we don't care, allow it to die. */
892 GNUNET_assert (root ==
893 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
902 * This peer can no longer own @a path as the path
903 * has been extended and a peer further down the line
904 * is now the new owner.
906 * @param cp old owner of the @a path
907 * @param path path where the ownership is lost
908 * @param hn note in @a cp's path heap that must be deleted
911 GCP_detach_path (struct CadetPeer *cp,
912 struct CadetPeerPath *path,
913 struct GNUNET_CONTAINER_HeapNode *hn)
915 LOG (GNUNET_ERROR_TYPE_DEBUG,
916 "Detatching path %s from peer %s\n",
919 GNUNET_assert (path ==
920 GNUNET_CONTAINER_heap_remove_node (hn));
925 * Add a @a connection to this @a cp.
927 * @param cp peer via which the @a connection goes
928 * @param cc the connection to add
931 GCP_add_connection (struct CadetPeer *cp,
932 struct CadetConnection *cc)
934 LOG (GNUNET_ERROR_TYPE_DEBUG,
935 "Adding connection %s to peer %s\n",
938 GNUNET_assert (GNUNET_OK ==
939 GNUNET_CONTAINER_multishortmap_put (cp->connections,
940 &GCC_get_id (cc)->connection_of_tunnel,
942 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
947 * Remove a @a connection that went via this @a cp.
949 * @param cp peer via which the @a connection went
950 * @param cc the connection to remove
953 GCP_remove_connection (struct CadetPeer *cp,
954 struct CadetConnection *cc)
956 LOG (GNUNET_ERROR_TYPE_DEBUG,
957 "Removing connection %s from peer %s\n",
960 GNUNET_assert (GNUNET_YES ==
961 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
962 &GCC_get_id (cc)->connection_of_tunnel,
968 * Retrieve the CadetPeer stucture associated with the
969 * peer. Optionally create one and insert it in the appropriate
970 * structures if the peer is not known yet.
972 * @param peer_id Full identity of the peer.
973 * @param create #GNUNET_YES if a new peer should be created if unknown.
974 * #GNUNET_NO to return NULL if peer is unknown.
975 * @return Existing or newly created peer structure.
976 * NULL if unknown and not requested @a create
979 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
982 struct CadetPeer *cp;
984 cp = GNUNET_CONTAINER_multipeermap_get (peers,
988 if (GNUNET_NO == create)
990 cp = GNUNET_new (struct CadetPeer);
992 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
994 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
995 GNUNET_assert (GNUNET_YES ==
996 GNUNET_CONTAINER_multipeermap_put (peers,
999 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1000 LOG (GNUNET_ERROR_TYPE_DEBUG,
1001 "Creating peer %s\n",
1008 * Obtain the peer identity for a `struct CadetPeer`.
1010 * @param cp our peer handle
1011 * @return the peer identity
1013 const struct GNUNET_PeerIdentity *
1014 GCP_get_id (struct CadetPeer *cp)
1021 * Iterate over all known peers.
1023 * @param iter Iterator.
1024 * @param cls Closure for @c iter.
1027 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1030 GNUNET_CONTAINER_multipeermap_iterate (peers,
1037 * Count the number of known paths toward the peer.
1039 * @param cp Peer to get path info.
1040 * @return Number of known paths.
1043 GCP_count_paths (const struct CadetPeer *cp)
1045 return cp->num_paths;
1050 * Iterate over the paths to a peer.
1052 * @param cp Peer to get path info.
1053 * @param callback Function to call for every path.
1054 * @param callback_cls Closure for @a callback.
1055 * @return Number of iterated paths.
1058 GCP_iterate_paths (struct CadetPeer *cp,
1059 GCP_PathIterator callback,
1062 unsigned int ret = 0;
1064 LOG (GNUNET_ERROR_TYPE_DEBUG,
1065 "Iterating over paths to peer %s%s\n",
1067 (NULL == cp->core_mq) ? "" : " including direct link");
1068 if (NULL != cp->core_mq)
1070 struct CadetPeerPath *path;
1072 path = GCPP_get_path_from_route (1,
1076 callback (callback_cls,
1081 for (unsigned int i=0;i<cp->path_dll_length;i++)
1083 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1089 callback (callback_cls,
1100 * Iterate over the paths to @a cp where
1101 * @a cp is at distance @a dist from us.
1103 * @param cp Peer to get path info.
1104 * @param dist desired distance of @a cp to us on the path
1105 * @param callback Function to call for every path.
1106 * @param callback_cls Closure for @a callback.
1107 * @return Number of iterated paths.
1110 GCP_iterate_paths_at (struct CadetPeer *cp,
1112 GCP_PathIterator callback,
1115 unsigned int ret = 0;
1117 if (dist >= cp->path_dll_length)
1119 LOG (GNUNET_ERROR_TYPE_DEBUG,
1120 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1122 cp->path_dll_length);
1125 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1130 callback (callback_cls,
1141 * Get the tunnel towards a peer.
1143 * @param cp Peer to get from.
1144 * @param create #GNUNET_YES to create a tunnel if we do not have one
1145 * @return Tunnel towards peer.
1147 struct CadetTunnel *
1148 GCP_get_tunnel (struct CadetPeer *cp,
1153 if ( (NULL != cp->t) ||
1154 (GNUNET_NO == create) )
1156 cp->t = GCT_create_tunnel (cp);
1157 consider_peer_activate (cp);
1163 * Hello offer was passed to the transport service. Mark it
1166 * @param cls the `struct CadetPeer` where the offer completed
1169 hello_offer_done (void *cls)
1171 struct CadetPeer *cp = cls;
1173 cp->hello_offer = NULL;
1178 * We got a HELLO for a @a peer, remember it, and possibly
1179 * trigger adequate actions (like trying to connect).
1181 * @param cp the peer we got a HELLO for
1182 * @param hello the HELLO to remember
1185 GCP_set_hello (struct CadetPeer *cp,
1186 const struct GNUNET_HELLO_Message *hello)
1188 struct GNUNET_HELLO_Message *mrg;
1190 LOG (GNUNET_ERROR_TYPE_DEBUG,
1191 "Got %u byte HELLO for peer %s\n",
1192 (unsigned int) GNUNET_HELLO_size (hello),
1194 if (NULL != cp->hello_offer)
1196 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1197 cp->hello_offer = NULL;
1199 if (NULL != cp->hello)
1201 mrg = GNUNET_HELLO_merge (hello,
1203 GNUNET_free (cp->hello);
1208 cp->hello = GNUNET_memdup (hello,
1209 GNUNET_HELLO_size (hello));
1212 = GNUNET_TRANSPORT_offer_hello (cfg,
1213 GNUNET_HELLO_get_header (cp->hello) ,
1216 /* New HELLO means cp's destruction time may change... */
1217 consider_peer_destroy (cp);
1222 * The tunnel to the given peer no longer exists, remove it from our
1223 * data structures, and possibly clean up the peer itself.
1225 * @param cp the peer affected
1226 * @param t the dead tunnel
1229 GCP_drop_tunnel (struct CadetPeer *cp,
1230 struct CadetTunnel *t)
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Dropping tunnel %s to peer %s\n",
1236 GNUNET_assert (cp->t == t);
1238 consider_peer_destroy (cp);
1243 * Test if @a cp has a core-level connection
1245 * @param cp peer to test
1246 * @return #GNUNET_YES if @a cp has a core-level connection
1249 GCP_has_core_connection (struct CadetPeer *cp)
1251 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1256 * Start message queue change notifications.
1258 * @param cp peer to notify for
1259 * @param cb function to call if mq becomes available or unavailable
1260 * @param cb_cls closure for @a cb
1261 * @return handle to cancel request
1263 struct GCP_MessageQueueManager *
1264 GCP_request_mq (struct CadetPeer *cp,
1265 GCP_MessageQueueNotificationCallback cb,
1268 struct GCP_MessageQueueManager *mqm;
1270 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1272 mqm->cb_cls = cb_cls;
1274 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1277 LOG (GNUNET_ERROR_TYPE_DEBUG,
1278 "Creating MQM %p for peer %s\n",
1281 if (NULL != cp->core_mq)
1289 * Stops message queue change notifications.
1291 * @param mqm handle matching request to cancel
1292 * @param last_env final message to transmit, or NULL
1295 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1296 struct GNUNET_MQ_Envelope *last_env)
1298 struct CadetPeer *cp = mqm->cp;
1300 LOG (GNUNET_ERROR_TYPE_DEBUG,
1301 "Destroying MQM %p for peer %s%s\n",
1304 (NULL == last_env) ? "" : " with last ditch transmission");
1305 if (NULL != mqm->env)
1306 GNUNET_MQ_discard (mqm->env);
1307 if (NULL != last_env)
1309 if (NULL != cp->core_mq)
1310 GNUNET_MQ_send (cp->core_mq,
1313 GNUNET_MQ_discard (last_env);
1315 if (cp->mqm_ready_ptr == mqm)
1316 cp->mqm_ready_ptr = mqm->next;
1317 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1325 * Send the message in @a env to @a cp, overriding queueing logic.
1326 * This function should only be used to send error messages outside
1327 * of flow and congestion control, similar to ICMP. Note that
1328 * the envelope may be silently discarded as well.
1330 * @param cp peer to send the message to
1331 * @param env envelope with the message to send
1334 GCP_send_ooo (struct CadetPeer *cp,
1335 struct GNUNET_MQ_Envelope *env)
1337 LOG (GNUNET_ERROR_TYPE_DEBUG,
1338 "Sending message to %s out of management\n",
1340 if (NULL == cp->core_mq)
1342 GNUNET_MQ_discard (env);
1345 GNUNET_MQ_send (cp->core_mq,
1352 /* end of gnunet-service-cadet-new_peer.c */