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],
357 * Remove an entry from the DLL of all of the paths that this peer is on.
359 * @param cp peer to modify
360 * @param entry an entry on a path
361 * @param off offset of this peer on the path
364 GCP_path_entry_remove (struct CadetPeer *cp,
365 struct CadetPeerPathEntry *entry,
368 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
371 GNUNET_assert (0 < cp->num_paths);
377 * Function called when the DHT finds a @a path to the peer (@a cls).
379 * @param cls the `struct CadetPeer`
380 * @param path the path that was found
383 dht_result_cb (void *cls,
384 struct CadetPeerPath *path)
386 struct CadetPeer *cp = cls;
387 GNUNET_CONTAINER_HeapCostType desirability;
388 struct CadetPeerPath *root;
389 GNUNET_CONTAINER_HeapCostType root_desirability;
391 desirability = GCPP_get_desirability (path);
393 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
398 root_desirability = 0;
400 if ( (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ||
401 (desirability >= root_desirability) )
403 /* Yes, we'd like to add this path, add to our heap */
406 GNUNET_CONTAINER_heap_insert (cp->path_heap,
410 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
411 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
413 /* Now we have way too many, drop least desirable */
414 root = GNUNET_CONTAINER_heap_remove_root (cp->path_heap);
421 * This peer is now on more "active" duty, activate processes related to it.
423 * @param cp the more-active peer
426 consider_peer_activate (struct CadetPeer *cp)
430 if (NULL != cp->destroy_task)
432 /* It's active, do not destory! */
433 GNUNET_SCHEDULER_cancel (cp->destroy_task);
434 cp->destroy_task = NULL;
436 if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
439 /* We're just on a path or directly connected; don't bother too much */
440 if (NULL != cp->connectivity_suggestion)
442 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
443 cp->connectivity_suggestion = NULL;
445 if (NULL != cp->search_h)
447 GCD_search_stop (cp->search_h);
452 if (NULL == cp->core_mq)
454 /* Lacks direct connection, try to create one by querying the DHT */
455 if ( (NULL == cp->search_h) &&
456 (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
458 = GCD_search (&cp->pid,
464 /* Have direct connection, stop DHT search if active */
465 if (NULL != cp->search_h)
467 GCD_search_stop (cp->search_h);
472 /* If we have a tunnel, our urge for connections is much bigger */
473 strength = (NULL != cp->t) ? 32 : 1;
474 if (NULL != cp->connectivity_suggestion)
475 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
476 cp->connectivity_suggestion
477 = GNUNET_ATS_connectivity_suggest (ats_ch,
484 * Retrieve the CadetPeer stucture associated with the
485 * peer. Optionally create one and insert it in the appropriate
486 * structures if the peer is not known yet.
488 * @param peer_id Full identity of the peer.
489 * @param create #GNUNET_YES if a new peer should be created if unknown.
490 * #GNUNET_NO to return NULL if peer is unknown.
491 * @return Existing or newly created peer structure.
492 * NULL if unknown and not requested @a create
495 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
498 struct CadetPeer *cp;
500 cp = GNUNET_CONTAINER_multipeermap_get (peers,
504 if (GNUNET_NO == create)
506 cp = GNUNET_new (struct CadetPeer);
508 cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
510 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
511 cp->search_h = NULL; // FIXME: start search immediately!?
512 cp->connectivity_suggestion = NULL; // FIXME: request with ATS!?
514 GNUNET_assert (GNUNET_YES ==
515 GNUNET_CONTAINER_multipeermap_put (peers,
518 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
524 * Obtain the peer identity for a `struct CadetPeer`.
526 * @param cp our peer handle
527 * @param[out] peer_id where to write the peer identity
530 GCP_id (struct CadetPeer *cp,
531 struct GNUNET_PeerIdentity *peer_id)
538 * Iterate over all known peers.
540 * @param iter Iterator.
541 * @param cls Closure for @c iter.
544 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
547 GNUNET_CONTAINER_multipeermap_iterate (peers,
554 * Count the number of known paths toward the peer.
556 * @param peer Peer to get path info.
557 * @return Number of known paths.
560 GCP_count_paths (const struct CadetPeer *peer)
562 return peer->num_paths;
567 * Iterate over the paths to a peer.
569 * @param peer Peer to get path info.
570 * @param callback Function to call for every path.
571 * @param callback_cls Closure for @a callback.
572 * @return Number of iterated paths.
575 GCP_iterate_paths (struct CadetPeer *peer,
576 GCP_PathIterator callback,
579 unsigned int ret = 0;
581 for (unsigned int i=0;i<peer->path_dll_length;i++)
583 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
588 callback (callback_cls,
600 * Get the tunnel towards a peer.
602 * @param peer Peer to get from.
603 * @param create #GNUNET_YES to create a tunnel if we do not have one
604 * @return Tunnel towards peer.
607 GCP_get_tunnel (struct CadetPeer *peer,
612 if ( (NULL != peer->t) ||
613 (GNUNET_NO == create) )
615 peer->t = GCT_create_tunnel (peer);
616 consider_peer_activate (peer);
622 * We got a HELLO for a @a peer, remember it, and possibly
623 * trigger adequate actions (like trying to connect).
625 * @param peer the peer we got a HELLO for
626 * @param hello the HELLO to remember
629 GCP_set_hello (struct CadetPeer *peer,
630 const struct GNUNET_HELLO_Message *hello)
634 consider_peer_destroy (peer);
639 * The tunnel to the given peer no longer exists, remove it from our
640 * data structures, and possibly clean up the peer itself.
642 * @param peer the peer affected
643 * @param t the dead tunnel
646 GCP_drop_tunnel (struct CadetPeer *peer,
647 struct CadetTunnel *t)
649 GNUNET_assert (peer->t == t);
651 consider_peer_destroy (peer);
655 /* end of gnunet-service-cadet-new_peer.c */