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
389 * @return NULL if this peer does not care to become a new owner,
390 * otherwise the node in the peer's path heap for the @a path.
392 struct GNUNET_CONTAINER_HeapNode *
393 GCP_attach_path (struct CadetPeer *cp,
394 struct CadetPeerPath *path)
396 GNUNET_CONTAINER_HeapCostType desirability;
397 struct CadetPeerPath *root;
398 GNUNET_CONTAINER_HeapCostType root_desirability;
399 struct GNUNET_CONTAINER_HeapNode *hn;
401 desirability = GCPP_get_desirability (path);
403 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
408 root_desirability = 0;
411 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
412 (desirability < root_desirability) )
415 /* Yes, we'd like to add this path, add to our heap */
416 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
420 /* Consider maybe dropping other paths because of the new one */
421 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
422 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
424 /* Now we have way too many, drop least desirable UNLESS it is in use!
425 (Note that this intentionally keeps highly desireable, but currently
426 unused paths around in the hope that we might be able to switch, even
427 if the number of paths exceeds the threshold.) */
428 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
430 GCPP_get_connection (root,
432 GCPP_get_length (root) - 1))
434 /* Got plenty of paths to this destination, and this is a low-quality
435 one that we don't care, allow it to die. */
436 GNUNET_assert (root ==
437 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
446 * Function called when the DHT finds a @a path to the peer (@a cls).
448 * @param cls the `struct CadetPeer`
449 * @param path the path that was found
452 dht_result_cb (void *cls,
453 struct CadetPeerPath *path)
455 struct CadetPeer *cp = cls;
456 struct GNUNET_CONTAINER_HeapNode *hn;
458 hn = GCP_attach_path (cp,
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,
511 /* Have direct connection, stop DHT search if active */
512 if (NULL != cp->search_h)
514 GCD_search_stop (cp->search_h);
519 /* If we have a tunnel, our urge for connections is much bigger */
520 strength = (NULL != cp->t) ? 32 : 1;
521 if (NULL != cp->connectivity_suggestion)
522 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
523 cp->connectivity_suggestion
524 = GNUNET_ATS_connectivity_suggest (ats_ch,
531 * Retrieve the CadetPeer stucture associated with the
532 * peer. Optionally create one and insert it in the appropriate
533 * structures if the peer is not known yet.
535 * @param peer_id Full identity of the peer.
536 * @param create #GNUNET_YES if a new peer should be created if unknown.
537 * #GNUNET_NO to return NULL if peer is unknown.
538 * @return Existing or newly created peer structure.
539 * NULL if unknown and not requested @a create
542 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
545 struct CadetPeer *cp;
547 cp = GNUNET_CONTAINER_multipeermap_get (peers,
551 if (GNUNET_NO == create)
553 cp = GNUNET_new (struct CadetPeer);
555 cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
557 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
558 GNUNET_assert (GNUNET_YES ==
559 GNUNET_CONTAINER_multipeermap_put (peers,
562 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
568 * Obtain the peer identity for a `struct CadetPeer`.
570 * @param cp our peer handle
571 * @return the peer identity
573 const struct GNUNET_PeerIdentity *
574 GCP_get_id (struct CadetPeer *cp)
581 * Iterate over all known peers.
583 * @param iter Iterator.
584 * @param cls Closure for @c iter.
587 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
590 GNUNET_CONTAINER_multipeermap_iterate (peers,
597 * Count the number of known paths toward the peer.
599 * @param peer Peer to get path info.
600 * @return Number of known paths.
603 GCP_count_paths (const struct CadetPeer *peer)
605 return peer->num_paths;
610 * Iterate over the paths to a peer.
612 * @param peer Peer to get path info.
613 * @param callback Function to call for every path.
614 * @param callback_cls Closure for @a callback.
615 * @return Number of iterated paths.
618 GCP_iterate_paths (struct CadetPeer *peer,
619 GCP_PathIterator callback,
622 unsigned int ret = 0;
624 for (unsigned int i=0;i<peer->path_dll_length;i++)
626 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
631 callback (callback_cls,
643 * Get the tunnel towards a peer.
645 * @param peer Peer to get from.
646 * @param create #GNUNET_YES to create a tunnel if we do not have one
647 * @return Tunnel towards peer.
650 GCP_get_tunnel (struct CadetPeer *peer,
655 if ( (NULL != peer->t) ||
656 (GNUNET_NO == create) )
658 peer->t = GCT_create_tunnel (peer);
659 consider_peer_activate (peer);
665 * We got a HELLO for a @a peer, remember it, and possibly
666 * trigger adequate actions (like trying to connect).
668 * @param peer the peer we got a HELLO for
669 * @param hello the HELLO to remember
672 GCP_set_hello (struct CadetPeer *peer,
673 const struct GNUNET_HELLO_Message *hello)
675 /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
677 consider_peer_destroy (peer);
682 * The tunnel to the given peer no longer exists, remove it from our
683 * data structures, and possibly clean up the peer itself.
685 * @param peer the peer affected
686 * @param t the dead tunnel
689 GCP_drop_tunnel (struct CadetPeer *peer,
690 struct CadetTunnel *t)
692 GNUNET_assert (peer->t == t);
694 consider_peer_destroy (peer);
698 /* end of gnunet-service-cadet-new_peer.c */