3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
23 * @file cadet/gnunet-service-cadet-new_peer.c
24 * @brief Information we track per peer.
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
29 #include "gnunet_util_lib.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_ats_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "cadet_protocol.h"
36 #include "cadet_path.h"
37 #include "gnunet-service-cadet-new.h"
38 #include "gnunet-service-cadet-new_connection.h"
39 #include "gnunet-service-cadet-new_dht.h"
40 #include "gnunet-service-cadet-new_peer.h"
41 #include "gnunet-service-cadet-new_paths.h"
42 #include "gnunet-service-cadet-new_tunnels.h"
45 * How long do we wait until tearing down an idle peer?
47 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
50 * How long do we keep paths around if we no longer care about the peer?
52 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
58 * Data structure used to track whom we have to notify about changes
59 * to our message queue.
61 struct GCP_MessageQueueManager
67 struct GCP_MessageQueueManager *next;
72 struct GCP_MessageQueueManager *prev;
75 * Function to call with updated message queue object.
77 GCP_MessageQueueNotificationCallback cb;
85 * The peer this is for.
93 * Struct containing all information regarding a given peer
100 struct GNUNET_PeerIdentity pid;
103 * Last time we heard from this peer
105 struct GNUNET_TIME_Absolute last_contact;
108 * Array of DLLs of paths traversing the peer, organized by the
109 * offset of the peer on the larger path.
111 struct CadetPeerPathEntry **path_heads;
114 * Array of DLL of paths traversing the peer, organized by the
115 * offset of the peer on the larger path.
117 struct CadetPeerPathEntry **path_tails;
120 * Notifications to call when @e core_mq changes.
122 struct GCP_MessageQueueManager *mqm_head;
125 * Notifications to call when @e core_mq changes.
127 struct GCP_MessageQueueManager *mqm_tail;
130 * MIN-heap of paths owned by this peer (they also end at this
131 * peer). Ordered by desirability.
133 struct GNUNET_CONTAINER_Heap *path_heap;
136 * Handle to stop the DHT search for paths to this peer
138 struct GCD_search_handle *search_h;
141 * Task to stop the DHT search for paths to this peer
143 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
146 * Task to destroy this entry.
148 struct GNUNET_SCHEDULER_Task *destroy_task;
151 * Tunnel to this peer, if any.
153 struct CadetTunnel *t;
156 * Connections that go through this peer; indexed by tid.
158 struct GNUNET_CONTAINER_MultiHashMap *connections;
161 * Handle for core transmissions.
163 struct GNUNET_MQ_Handle *core_mq;
166 * Hello message of the peer.
168 struct GNUNET_HELLO_Message *hello;
171 * Handle to us offering the HELLO to the transport.
173 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
176 * Handle to our ATS request asking ATS to suggest an address
177 * to TRANSPORT for this peer (to establish a direct link).
179 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
182 * How many messages are in the queue to this peer.
184 unsigned int queue_n;
187 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
189 unsigned int num_paths;
192 * Current length of the @e path_heads and @path_tails arrays.
193 * The arrays should be grown as needed.
195 unsigned int path_dll_length;
201 * Get the static string for a peer ID.
205 * @return Static string for it's ID.
208 GCP_2s (const struct CadetPeer *peer)
212 return GNUNET_i2s (&peer->pid);
217 * This peer is no longer be needed, clean it up now.
219 * @param cls peer to clean up
222 destroy_peer (void *cls)
224 struct CadetPeer *cp = cls;
226 cp->destroy_task = NULL;
227 GNUNET_assert (NULL == cp->t);
228 GNUNET_assert (NULL == cp->core_mq);
229 GNUNET_assert (0 == cp->path_dll_length);
230 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
231 GNUNET_assert (GNUNET_YES ==
232 GNUNET_CONTAINER_multipeermap_remove (peers,
235 GNUNET_free_non_null (cp->path_heads);
236 GNUNET_free_non_null (cp->path_tails);
237 cp->path_dll_length = 0;
238 if (NULL != cp->search_h)
240 GCD_search_stop (cp->search_h);
243 /* FIXME: clean up search_delayedXXX! */
245 if (NULL != cp->hello_offer)
247 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
248 cp->hello_offer = NULL;
250 if (NULL != cp->connectivity_suggestion)
252 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
253 cp->connectivity_suggestion = NULL;
255 GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
256 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
257 GNUNET_free_non_null (cp->hello);
258 /* Peer should not be freed if paths exist; if there are no paths,
259 there ought to be no connections, and without connections, no
260 notifications. Thus we can assert that mqm_head is empty at this
262 GNUNET_assert (NULL == cp->mqm_head);
268 * Set the message queue to @a mq for peer @a cp and notify watchers.
270 * @param cp peer to modify
271 * @param mq message queue to set (can be NULL)
274 GCP_set_mq (struct CadetPeer *cp,
275 struct GNUNET_MQ_Handle *mq)
278 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
281 mqm->cb (mqm->cb_cls,
287 * Function called to destroy a peer now.
290 * @param pid identity of the peer (unused)
291 * @param value the `struct CadetPeer` to clean up
292 * @return #GNUNET_OK (continue to iterate)
295 destroy_iterator_cb (void *cls,
296 const struct GNUNET_PeerIdentity *pid,
299 struct CadetPeer *cp = value;
301 if (NULL != cp->destroy_task)
303 GNUNET_SCHEDULER_cancel (cp->destroy_task);
304 cp->destroy_task = NULL;
312 * Clean up all entries about all peers.
313 * Must only be called after all tunnels, CORE-connections and
314 * connections are down.
317 GCP_destroy_all_peers ()
319 GNUNET_CONTAINER_multipeermap_iterate (peers,
320 &destroy_iterator_cb,
326 * This peer may no longer be needed, consider cleaning it up.
328 * @param cp peer to clean up
331 consider_peer_destroy (struct CadetPeer *cp);
335 * We really no longere care about a peer, stop hogging memory with paths to it.
336 * Afterwards, see if there is more to be cleaned up about this peer.
338 * @param cls a `struct CadetPeer`.
341 drop_paths (void *cls)
343 struct CadetPeer *cp = cls;
344 struct CadetPeerPath *path;
346 cp->destroy_task = NULL;
347 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
349 consider_peer_destroy (cp);
354 * This peer may no longer be needed, consider cleaning it up.
356 * @param cp peer to clean up
359 consider_peer_destroy (struct CadetPeer *cp)
361 struct GNUNET_TIME_Relative exp;
363 if (NULL != cp->destroy_task)
365 GNUNET_SCHEDULER_cancel (cp->destroy_task);
366 cp->destroy_task = NULL;
369 return; /* still relevant! */
370 if (NULL != cp->core_mq)
371 return; /* still relevant! */
372 if (0 != GNUNET_CONTAINER_multihashmap_size (cp->connections))
373 return; /* still relevant! */
374 if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
376 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
381 if (0 < cp->path_dll_length)
382 return; /* still relevant! */
383 if (NULL != cp->hello)
385 /* relevant only until HELLO expires */
386 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
387 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
392 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
399 * Add an entry to the DLL of all of the paths that this peer is on.
401 * @param cp peer to modify
402 * @param entry an entry on a path
403 * @param off offset of this peer on the path
406 GCP_path_entry_add (struct CadetPeer *cp,
407 struct CadetPeerPathEntry *entry,
410 if (off >= cp->path_dll_length)
412 unsigned int len = cp->path_dll_length;
414 GNUNET_array_grow (cp->path_heads,
417 GNUNET_array_grow (cp->path_tails,
421 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
426 /* If we have a tunnel to this peer, tell the tunnel that there is a
427 new path available. */
429 GCT_consider_path (cp->t,
436 * Remove an entry from the DLL of all of the paths that this peer is on.
438 * @param cp peer to modify
439 * @param entry an entry on a path
440 * @param off offset of this peer on the path
443 GCP_path_entry_remove (struct CadetPeer *cp,
444 struct CadetPeerPathEntry *entry,
447 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
450 GNUNET_assert (0 < cp->num_paths);
456 * Try adding a @a path to this @a peer. If the peer already
457 * has plenty of paths, return NULL.
459 * @param cp peer to which the @a path leads to
460 * @param path a path looking for an owner; may not be fully initialized yet!
461 * @param off offset of @a cp in @a path
462 * @return NULL if this peer does not care to become a new owner,
463 * otherwise the node in the peer's path heap for the @a path.
465 struct GNUNET_CONTAINER_HeapNode *
466 GCP_attach_path (struct CadetPeer *cp,
467 struct CadetPeerPath *path,
470 GNUNET_CONTAINER_HeapCostType desirability;
471 struct CadetPeerPath *root;
472 GNUNET_CONTAINER_HeapCostType root_desirability;
473 struct GNUNET_CONTAINER_HeapNode *hn;
475 /* FIXME: desirability is not yet initialized; tricky! */
476 desirability = GCPP_get_desirability (path);
478 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
483 root_desirability = 0;
486 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
487 (desirability < root_desirability) )
490 /* Yes, we'd like to add this path, add to our heap */
491 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
495 /* Consider maybe dropping other paths because of the new one */
496 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
497 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
499 /* Now we have way too many, drop least desirable UNLESS it is in use!
500 (Note that this intentionally keeps highly desireable, but currently
501 unused paths around in the hope that we might be able to switch, even
502 if the number of paths exceeds the threshold.) */
503 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
505 GCPP_get_connection (root,
507 GCPP_get_length (root) - 1))
509 /* Got plenty of paths to this destination, and this is a low-quality
510 one that we don't care, allow it to die. */
511 GNUNET_assert (root ==
512 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
521 * This peer can no longer own @a path as the path
522 * has been extended and a peer further down the line
523 * is now the new owner.
525 * @param cp old owner of the @a path
526 * @param path path where the ownership is lost
527 * @param hn note in @a cp's path heap that must be deleted
530 GCP_detach_path (struct CadetPeer *cp,
531 struct CadetPeerPath *path,
532 struct GNUNET_CONTAINER_HeapNode *hn)
534 GNUNET_assert (path ==
535 GNUNET_CONTAINER_heap_remove_node (hn));
540 * Add a @a connection to this @a cp.
542 * @param cp peer via which the @a connection goes
543 * @param cc the connection to add
546 GCP_add_connection (struct CadetPeer *cp,
547 struct CadetConnection *cc)
549 GNUNET_assert (GNUNET_OK ==
550 GNUNET_CONTAINER_multihashmap_put (cp->connections,
553 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
558 * Remove a @a connection that went via this @a cp.
560 * @param cp peer via which the @a connection went
561 * @param cc the connection to remove
564 GCP_remove_connection (struct CadetPeer *cp,
565 struct CadetConnection *cc)
567 GNUNET_assert (GNUNET_YES ==
568 GNUNET_CONTAINER_multihashmap_remove (cp->connections,
575 * This peer is now on more "active" duty, activate processes related to it.
577 * @param cp the more-active peer
580 consider_peer_activate (struct CadetPeer *cp)
584 if (NULL != cp->destroy_task)
586 /* It's active, do not destory! */
587 GNUNET_SCHEDULER_cancel (cp->destroy_task);
588 cp->destroy_task = NULL;
590 if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
593 /* We're just on a path or directly connected; don't bother too much */
594 if (NULL != cp->connectivity_suggestion)
596 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
597 cp->connectivity_suggestion = NULL;
599 if (NULL != cp->search_h)
601 GCD_search_stop (cp->search_h);
606 if (NULL == cp->core_mq)
608 /* Lacks direct connection, try to create one by querying the DHT */
609 if ( (NULL == cp->search_h) &&
610 (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
612 = GCD_search (&cp->pid);
616 /* Have direct connection, stop DHT search if active */
617 if (NULL != cp->search_h)
619 GCD_search_stop (cp->search_h);
624 /* If we have a tunnel, our urge for connections is much bigger */
625 strength = (NULL != cp->t) ? 32 : 1;
626 if (NULL != cp->connectivity_suggestion)
627 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
628 cp->connectivity_suggestion
629 = GNUNET_ATS_connectivity_suggest (ats_ch,
636 * Retrieve the CadetPeer stucture associated with the
637 * peer. Optionally create one and insert it in the appropriate
638 * structures if the peer is not known yet.
640 * @param peer_id Full identity of the peer.
641 * @param create #GNUNET_YES if a new peer should be created if unknown.
642 * #GNUNET_NO to return NULL if peer is unknown.
643 * @return Existing or newly created peer structure.
644 * NULL if unknown and not requested @a create
647 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
650 struct CadetPeer *cp;
652 cp = GNUNET_CONTAINER_multipeermap_get (peers,
656 if (GNUNET_NO == create)
658 cp = GNUNET_new (struct CadetPeer);
660 cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
662 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
663 GNUNET_assert (GNUNET_YES ==
664 GNUNET_CONTAINER_multipeermap_put (peers,
667 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
673 * Obtain the peer identity for a `struct CadetPeer`.
675 * @param cp our peer handle
676 * @return the peer identity
678 const struct GNUNET_PeerIdentity *
679 GCP_get_id (struct CadetPeer *cp)
686 * Iterate over all known peers.
688 * @param iter Iterator.
689 * @param cls Closure for @c iter.
692 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
695 GNUNET_CONTAINER_multipeermap_iterate (peers,
702 * Count the number of known paths toward the peer.
704 * @param peer Peer to get path info.
705 * @return Number of known paths.
708 GCP_count_paths (const struct CadetPeer *peer)
710 return peer->num_paths;
715 * Iterate over the paths to a peer.
717 * @param peer Peer to get path info.
718 * @param callback Function to call for every path.
719 * @param callback_cls Closure for @a callback.
720 * @return Number of iterated paths.
723 GCP_iterate_paths (struct CadetPeer *peer,
724 GCP_PathIterator callback,
727 unsigned int ret = 0;
729 for (unsigned int i=0;i<peer->path_dll_length;i++)
731 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
736 callback (callback_cls,
748 * Iterate over the paths to @a peer where
749 * @a peer is at distance @a dist from us.
751 * @param peer Peer to get path info.
752 * @param dist desired distance of @a peer to us on the path
753 * @param callback Function to call for every path.
754 * @param callback_cls Closure for @a callback.
755 * @return Number of iterated paths.
758 GCP_iterate_paths_at (struct CadetPeer *peer,
760 GCP_PathIterator callback,
763 unsigned int ret = 0;
765 if (dist<peer->path_dll_length)
767 for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
772 callback (callback_cls,
783 * Get the tunnel towards a peer.
785 * @param peer Peer to get from.
786 * @param create #GNUNET_YES to create a tunnel if we do not have one
787 * @return Tunnel towards peer.
790 GCP_get_tunnel (struct CadetPeer *peer,
795 if ( (NULL != peer->t) ||
796 (GNUNET_NO == create) )
798 peer->t = GCT_create_tunnel (peer);
799 consider_peer_activate (peer);
805 * We got a HELLO for a @a peer, remember it, and possibly
806 * trigger adequate actions (like trying to connect).
808 * @param peer the peer we got a HELLO for
809 * @param hello the HELLO to remember
812 GCP_set_hello (struct CadetPeer *peer,
813 const struct GNUNET_HELLO_Message *hello)
815 /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
817 consider_peer_destroy (peer);
822 * The tunnel to the given peer no longer exists, remove it from our
823 * data structures, and possibly clean up the peer itself.
825 * @param peer the peer affected
826 * @param t the dead tunnel
829 GCP_drop_tunnel (struct CadetPeer *peer,
830 struct CadetTunnel *t)
832 GNUNET_assert (peer->t == t);
834 consider_peer_destroy (peer);
839 * Start message queue change notifications.
841 * @param cp peer to notify for
842 * @param cb function to call if mq becomes available or unavailable
843 * @param cb_cls closure for @a cb
844 * @return handle to cancel request
846 struct GCP_MessageQueueManager *
847 GCP_request_mq (struct CadetPeer *cp,
848 GCP_MessageQueueNotificationCallback cb,
851 struct GCP_MessageQueueManager *mqm;
853 mqm = GNUNET_new (struct GCP_MessageQueueManager);
855 mqm->cb_cls = cb_cls;
857 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
860 if (NULL != cp->core_mq)
868 * Stops message queue change notifications.
870 * @param mqm handle matching request to cancel
873 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm)
875 struct CadetPeer *cp = mqm->cp;
877 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
885 /* end of gnunet-service-cadet-new_peer.c */