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_dht.h"
39 #include "gnunet-service-cadet-new_peer.h"
40 #include "gnunet-service-cadet-new_paths.h"
41 #include "gnunet-service-cadet-new_tunnels.h"
44 * How long do we wait until tearing down an idle peer?
46 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
49 * How long do we keep paths around if we no longer care about the peer?
51 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
55 * Struct containing all information regarding a given peer
62 struct GNUNET_PeerIdentity pid;
65 * Last time we heard from this peer
67 struct GNUNET_TIME_Absolute last_contact;
70 * Array of DLLs of paths traversing the peer, organized by the
71 * offset of the peer on the larger path.
73 struct CadetPeerPathEntry **path_heads;
76 * Array of DLL of paths traversing the peer, organized by the
77 * offset of the peer on the larger path.
79 struct CadetPeerPathEntry **path_tails;
82 * MIN-heap of paths owned by this peer (they also end at this
83 * peer). Ordered by desirability.
85 struct GNUNET_CONTAINER_Heap *path_heap;
88 * Handle to stop the DHT search for paths to this peer
90 struct GCD_search_handle *search_h;
93 * Task to stop the DHT search for paths to this peer
95 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
98 * Task to destroy this entry.
100 struct GNUNET_SCHEDULER_Task *destroy_task;
103 * Tunnel to this peer, if any.
105 struct CadetTunnel *t;
108 * Connections that go through this peer; indexed by tid.
110 struct GNUNET_CONTAINER_MultiHashMap *connections;
113 * Handle for core transmissions.
115 struct GNUNET_MQ_Handle *core_mq;
118 * Hello message of the peer.
120 struct GNUNET_HELLO_Message *hello;
123 * Handle to us offering the HELLO to the transport.
125 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
128 * Handle to our ATS request asking ATS to suggest an address
129 * to TRANSPORT for this peer (to establish a direct link).
131 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
134 * How many messages are in the queue to this peer.
136 unsigned int queue_n;
139 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
141 unsigned int num_paths;
144 * Current length of the @e path_heads and @path_tails arrays.
145 * The arrays should be grown as needed.
147 unsigned int path_dll_length;
153 * Get the static string for a peer ID.
157 * @return Static string for it's ID.
160 GCP_2s (const struct CadetPeer *peer)
164 return GNUNET_i2s (&peer->pid);
169 * This peer is no longer be needed, clean it up now.
171 * @param cls peer to clean up
174 destroy_peer (void *cls)
176 struct CadetPeer *cp = cls;
178 cp->destroy_task = NULL;
179 GNUNET_assert (NULL == cp->t);
180 GNUNET_assert (NULL == cp->core_mq);
181 GNUNET_assert (0 == cp->path_dll_length);
182 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
183 GNUNET_assert (GNUNET_YES ==
184 GNUNET_CONTAINER_multipeermap_remove (peers,
187 GNUNET_free_non_null (cp->path_heads);
188 GNUNET_free_non_null (cp->path_tails);
189 cp->path_dll_length = 0;
190 if (NULL != cp->search_h)
192 GCD_search_stop (cp->search_h);
195 /* FIXME: clean up search_delayedXXX! */
197 if (NULL != cp->hello_offer)
199 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
200 cp->hello_offer = NULL;
202 if (NULL != cp->connectivity_suggestion)
204 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
205 cp->connectivity_suggestion = NULL;
207 GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
208 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
209 GNUNET_free_non_null (cp->hello);
215 * Function called to destroy a peer now.
218 * @param pid identity of the peer (unused)
219 * @param value the `struct CadetPeer` to clean up
220 * @return #GNUNET_OK (continue to iterate)
223 destroy_iterator_cb (void *cls,
224 const struct GNUNET_PeerIdentity *pid,
227 struct CadetPeer *cp = value;
229 if (NULL != cp->destroy_task)
231 GNUNET_SCHEDULER_cancel (cp->destroy_task);
232 cp->destroy_task = NULL;
240 * Clean up all entries about all peers.
241 * Must only be called after all tunnels, CORE-connections and
242 * connections are down.
245 GCP_destroy_all_peers ()
247 GNUNET_CONTAINER_multipeermap_iterate (peers,
248 &destroy_iterator_cb,
254 * This peer may no longer be needed, consider cleaning it up.
256 * @param cp peer to clean up
259 consider_peer_destroy (struct CadetPeer *cp);
263 * We really no longere care about a peer, stop hogging memory with paths to it.
264 * Afterwards, see if there is more to be cleaned up about this peer.
266 * @param cls a `struct CadetPeer`.
269 drop_paths (void *cls)
271 struct CadetPeer *cp = cls;
272 struct CadetPeerPath *path;
274 cp->destroy_task = NULL;
275 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
277 consider_peer_destroy (cp);
282 * This peer may no longer be needed, consider cleaning it up.
284 * @param cp peer to clean up
287 consider_peer_destroy (struct CadetPeer *cp)
289 struct GNUNET_TIME_Relative exp;
291 if (NULL != cp->destroy_task)
293 GNUNET_SCHEDULER_cancel (cp->destroy_task);
294 cp->destroy_task = NULL;
297 return; /* still relevant! */
298 if (NULL != cp->core_mq)
299 return; /* still relevant! */
300 if (0 != GNUNET_CONTAINER_multihashmap_size (cp->connections))
301 return; /* still relevant! */
302 if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
304 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
309 if (0 < cp->path_dll_length)
310 return; /* still relevant! */
311 if (NULL != cp->hello)
313 /* relevant only until HELLO expires */
314 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
315 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
320 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
327 * Add an entry to the DLL of all of the paths that this peer is on.
329 * @param cp peer to modify
330 * @param entry an entry on a path
331 * @param off offset of this peer on the path
334 GCP_path_entry_add (struct CadetPeer *cp,
335 struct CadetPeerPathEntry *entry,
338 if (off >= cp->path_dll_length)
340 unsigned int len = cp->path_dll_length;
342 GNUNET_array_grow (cp->path_heads,
345 GNUNET_array_grow (cp->path_tails,
349 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
354 /* If we have a tunnel to this peer, tell the tunnel that there is a
355 new path available. */
357 GCT_consider_path (cp->t,
364 * Remove an entry from the DLL of all of the paths that this peer is on.
366 * @param cp peer to modify
367 * @param entry an entry on a path
368 * @param off offset of this peer on the path
371 GCP_path_entry_remove (struct CadetPeer *cp,
372 struct CadetPeerPathEntry *entry,
375 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
378 GNUNET_assert (0 < cp->num_paths);
384 * Try adding a @a path to this @a peer. If the peer already
385 * has plenty of paths, return NULL.
387 * @param cp peer to which the @a path leads to
388 * @param path a path looking for an owner; may not be fully initialized yet!
389 * @param off offset of @a cp in @a path
390 * @return NULL if this peer does not care to become a new owner,
391 * otherwise the node in the peer's path heap for the @a path.
393 struct GNUNET_CONTAINER_HeapNode *
394 GCP_attach_path (struct CadetPeer *cp,
395 struct CadetPeerPath *path,
398 GNUNET_CONTAINER_HeapCostType desirability;
399 struct CadetPeerPath *root;
400 GNUNET_CONTAINER_HeapCostType root_desirability;
401 struct GNUNET_CONTAINER_HeapNode *hn;
403 /* FIXME: desirability is not yet initialized; tricky! */
404 desirability = GCPP_get_desirability (path);
406 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
411 root_desirability = 0;
414 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
415 (desirability < root_desirability) )
418 /* Yes, we'd like to add this path, add to our heap */
419 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
423 /* Consider maybe dropping other paths because of the new one */
424 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
425 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
427 /* Now we have way too many, drop least desirable UNLESS it is in use!
428 (Note that this intentionally keeps highly desireable, but currently
429 unused paths around in the hope that we might be able to switch, even
430 if the number of paths exceeds the threshold.) */
431 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
433 GCPP_get_connection (root,
435 GCPP_get_length (root) - 1))
437 /* Got plenty of paths to this destination, and this is a low-quality
438 one that we don't care, allow it to die. */
439 GNUNET_assert (root ==
440 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
449 * This peer can no longer own @a path as the path
450 * has been extended and a peer further down the line
451 * is now the new owner.
453 * @param cp old owner of the @a path
454 * @param path path where the ownership is lost
455 * @param hn note in @a cp's path heap that must be deleted
458 GCP_detach_path (struct CadetPeer *cp,
459 struct CadetPeerPath *path,
460 struct GNUNET_CONTAINER_HeapNode *hn)
462 GNUNET_assert (path ==
463 GNUNET_CONTAINER_heap_remove_node (hn));
468 * This peer is now on more "active" duty, activate processes related to it.
470 * @param cp the more-active peer
473 consider_peer_activate (struct CadetPeer *cp)
477 if (NULL != cp->destroy_task)
479 /* It's active, do not destory! */
480 GNUNET_SCHEDULER_cancel (cp->destroy_task);
481 cp->destroy_task = NULL;
483 if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
486 /* We're just on a path or directly connected; don't bother too much */
487 if (NULL != cp->connectivity_suggestion)
489 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
490 cp->connectivity_suggestion = NULL;
492 if (NULL != cp->search_h)
494 GCD_search_stop (cp->search_h);
499 if (NULL == cp->core_mq)
501 /* Lacks direct connection, try to create one by querying the DHT */
502 if ( (NULL == cp->search_h) &&
503 (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
505 = GCD_search (&cp->pid);
509 /* Have direct connection, stop DHT search if active */
510 if (NULL != cp->search_h)
512 GCD_search_stop (cp->search_h);
517 /* If we have a tunnel, our urge for connections is much bigger */
518 strength = (NULL != cp->t) ? 32 : 1;
519 if (NULL != cp->connectivity_suggestion)
520 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
521 cp->connectivity_suggestion
522 = GNUNET_ATS_connectivity_suggest (ats_ch,
529 * Retrieve the CadetPeer stucture associated with the
530 * peer. Optionally create one and insert it in the appropriate
531 * structures if the peer is not known yet.
533 * @param peer_id Full identity of the peer.
534 * @param create #GNUNET_YES if a new peer should be created if unknown.
535 * #GNUNET_NO to return NULL if peer is unknown.
536 * @return Existing or newly created peer structure.
537 * NULL if unknown and not requested @a create
540 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
543 struct CadetPeer *cp;
545 cp = GNUNET_CONTAINER_multipeermap_get (peers,
549 if (GNUNET_NO == create)
551 cp = GNUNET_new (struct CadetPeer);
553 cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
555 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
556 GNUNET_assert (GNUNET_YES ==
557 GNUNET_CONTAINER_multipeermap_put (peers,
560 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
566 * Obtain the peer identity for a `struct CadetPeer`.
568 * @param cp our peer handle
569 * @return the peer identity
571 const struct GNUNET_PeerIdentity *
572 GCP_get_id (struct CadetPeer *cp)
579 * Iterate over all known peers.
581 * @param iter Iterator.
582 * @param cls Closure for @c iter.
585 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
588 GNUNET_CONTAINER_multipeermap_iterate (peers,
595 * Count the number of known paths toward the peer.
597 * @param peer Peer to get path info.
598 * @return Number of known paths.
601 GCP_count_paths (const struct CadetPeer *peer)
603 return peer->num_paths;
608 * Iterate over the paths to a peer.
610 * @param peer Peer to get path info.
611 * @param callback Function to call for every path.
612 * @param callback_cls Closure for @a callback.
613 * @return Number of iterated paths.
616 GCP_iterate_paths (struct CadetPeer *peer,
617 GCP_PathIterator callback,
620 unsigned int ret = 0;
622 for (unsigned int i=0;i<peer->path_dll_length;i++)
624 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
629 callback (callback_cls,
641 * Iterate over the paths to @a peer where
642 * @a peer is at distance @a dist from us.
644 * @param peer Peer to get path info.
645 * @param dist desired distance of @a peer to us on the path
646 * @param callback Function to call for every path.
647 * @param callback_cls Closure for @a callback.
648 * @return Number of iterated paths.
651 GCP_iterate_paths_at (struct CadetPeer *peer,
653 GCP_PathIterator callback,
656 unsigned int ret = 0;
658 if (dist<peer->path_dll_length)
660 for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
665 callback (callback_cls,
676 * Get the tunnel towards a peer.
678 * @param peer Peer to get from.
679 * @param create #GNUNET_YES to create a tunnel if we do not have one
680 * @return Tunnel towards peer.
683 GCP_get_tunnel (struct CadetPeer *peer,
688 if ( (NULL != peer->t) ||
689 (GNUNET_NO == create) )
691 peer->t = GCT_create_tunnel (peer);
692 consider_peer_activate (peer);
698 * We got a HELLO for a @a peer, remember it, and possibly
699 * trigger adequate actions (like trying to connect).
701 * @param peer the peer we got a HELLO for
702 * @param hello the HELLO to remember
705 GCP_set_hello (struct CadetPeer *peer,
706 const struct GNUNET_HELLO_Message *hello)
708 /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
710 consider_peer_destroy (peer);
715 * The tunnel to the given peer no longer exists, remove it from our
716 * data structures, and possibly clean up the peer itself.
718 * @param peer the peer affected
719 * @param t the dead tunnel
722 GCP_drop_tunnel (struct CadetPeer *peer,
723 struct CadetTunnel *t)
725 GNUNET_assert (peer->t == t);
727 consider_peer_destroy (peer);
731 /* end of gnunet-service-cadet-new_peer.c */