finish logic to maintain paths
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_peer.c
1
2 /*
3      This file is part of GNUnet.
4      Copyright (C) 2001-2017 GNUnet e.V.
5
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.
10
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.
15
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.
20 */
21
22 /**
23  * @file cadet/gnunet-service-cadet-new_peer.c
24  * @brief Information we track per peer.
25  * @author Bartlomiej Polot
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
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"
42
43 /**
44  * How long do we wait until tearing down an idle peer?
45  */
46 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
47
48 /**
49  * How long do we keep paths around if we no longer care about the peer?
50  */
51 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
52
53
54 /**
55  * Struct containing all information regarding a given peer
56  */
57 struct CadetPeer
58 {
59   /**
60    * ID of the peer
61    */
62   struct GNUNET_PeerIdentity pid;
63
64   /**
65    * Last time we heard from this peer
66    */
67   struct GNUNET_TIME_Absolute last_contact;
68
69   /**
70    * Array of DLLs of paths traversing the peer, organized by the
71    * offset of the peer on the larger path.
72    */
73   struct CadetPeerPathEntry **path_heads;
74
75   /**
76    * Array of DLL of paths traversing the peer, organized by the
77    * offset of the peer on the larger path.
78    */
79   struct CadetPeerPathEntry **path_tails;
80
81   /**
82    * MIN-heap of paths owned by this peer (they also end at this
83    * peer).  Ordered by desirability.
84    */
85   struct GNUNET_CONTAINER_Heap *path_heap;
86
87   /**
88    * Handle to stop the DHT search for paths to this peer
89    */
90   struct GCD_search_handle *search_h;
91
92   /**
93    * Task to stop the DHT search for paths to this peer
94    */
95   struct GNUNET_SCHEDULER_Task *search_delayedXXX;
96
97   /**
98    * Task to destroy this entry.
99    */
100   struct GNUNET_SCHEDULER_Task *destroy_task;
101
102   /**
103    * Tunnel to this peer, if any.
104    */
105   struct CadetTunnel *t;
106
107   /**
108    * Connections that go through this peer; indexed by tid.
109    */
110   struct GNUNET_CONTAINER_MultiHashMap *connections;
111
112   /**
113    * Handle for core transmissions.
114    */
115   struct GNUNET_MQ_Handle *core_mq;
116
117   /**
118    * Hello message of the peer.
119    */
120   struct GNUNET_HELLO_Message *hello;
121
122   /**
123    * Handle to us offering the HELLO to the transport.
124    */
125   struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
126
127   /**
128    * Handle to our ATS request asking ATS to suggest an address
129    * to TRANSPORT for this peer (to establish a direct link).
130    */
131   struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
132
133   /**
134    * How many messages are in the queue to this peer.
135    */
136   unsigned int queue_n;
137
138   /**
139    * How many paths do we have to this peer (in all @e path_heads DLLs combined).
140    */
141   unsigned int num_paths;
142
143   /**
144    * Current length of the @e path_heads and @path_tails arrays.
145    * The arrays should be grown as needed.
146    */
147   unsigned int path_dll_length;
148
149 };
150
151
152 /**
153  * Get the static string for a peer ID.
154  *
155  * @param peer Peer.
156  *
157  * @return Static string for it's ID.
158  */
159 const char *
160 GCP_2s (const struct CadetPeer *peer)
161 {
162   if (NULL == peer)
163     return "PEER(NULL)";
164   return GNUNET_i2s (&peer->pid);
165 }
166
167
168 /**
169  * This peer is no longer be needed, clean it up now.
170  *
171  * @param cls peer to clean up
172  */
173 static void
174 destroy_peer (void *cls)
175 {
176   struct CadetPeer *cp = cls;
177
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,
185                                                        &cp->pid,
186                                                        cp));
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)
191   {
192     GCD_search_stop (cp->search_h);
193     cp->search_h = NULL;
194   }
195   /* FIXME: clean up search_delayedXXX! */
196
197   if (NULL != cp->hello_offer)
198   {
199     GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
200     cp->hello_offer = NULL;
201   }
202   if (NULL != cp->connectivity_suggestion)
203   {
204     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
205     cp->connectivity_suggestion = NULL;
206   }
207   GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
208   GNUNET_CONTAINER_heap_destroy (cp->path_heap);
209   GNUNET_free_non_null (cp->hello);
210   GNUNET_free (cp);
211 }
212
213
214 /**
215  * Function called to destroy a peer now.
216  *
217  * @param cls NULL
218  * @param pid identity of the peer (unused)
219  * @param value the `struct CadetPeer` to clean up
220  * @return #GNUNET_OK (continue to iterate)
221  */
222 static int
223 destroy_iterator_cb (void *cls,
224                      const struct GNUNET_PeerIdentity *pid,
225                      void *value)
226 {
227   struct CadetPeer *cp = value;
228
229   if (NULL != cp->destroy_task)
230   {
231     GNUNET_SCHEDULER_cancel (cp->destroy_task);
232     cp->destroy_task = NULL;
233   }
234   destroy_peer (cp);
235   return GNUNET_OK;
236 }
237
238
239 /**
240  * Clean up all entries about all peers.
241  * Must only be called after all tunnels, CORE-connections and
242  * connections are down.
243  */
244 void
245 GCP_destroy_all_peers ()
246 {
247   GNUNET_CONTAINER_multipeermap_iterate (peers,
248                                          &destroy_iterator_cb,
249                                          NULL);
250 }
251
252
253 /**
254  * This peer may no longer be needed, consider cleaning it up.
255  *
256  * @param cp peer to clean up
257  */
258 static void
259 consider_peer_destroy (struct CadetPeer *cp);
260
261
262 /**
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.
265  *
266  * @param cls a `struct CadetPeer`.
267  */
268 static void
269 drop_paths (void *cls)
270 {
271   struct CadetPeer *cp = cls;
272   struct CadetPeerPath *path;
273
274   cp->destroy_task = NULL;
275   while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
276     GCPP_release (path);
277   consider_peer_destroy (cp);
278 }
279
280
281 /**
282  * This peer may no longer be needed, consider cleaning it up.
283  *
284  * @param cp peer to clean up
285  */
286 static void
287 consider_peer_destroy (struct CadetPeer *cp)
288 {
289   struct GNUNET_TIME_Relative exp;
290
291   if (NULL != cp->destroy_task)
292   {
293     GNUNET_SCHEDULER_cancel (cp->destroy_task);
294     cp->destroy_task = NULL;
295   }
296   if (NULL != cp->t)
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))
303   {
304     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
305                                                      &drop_paths,
306                                                      cp);
307     return;
308   }
309   if (0 < cp->path_dll_length)
310     return; /* still relevant! */
311   if (NULL != cp->hello)
312   {
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,
316                                                      &destroy_peer,
317                                                      cp);
318     return;
319   }
320   cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
321                                                    &destroy_peer,
322                                                    cp);
323 }
324
325
326 /**
327  * Add an entry to the DLL of all of the paths that this peer is on.
328  *
329  * @param cp peer to modify
330  * @param entry an entry on a path
331  * @param off offset of this peer on the path
332  */
333 void
334 GCP_path_entry_add (struct CadetPeer *cp,
335                     struct CadetPeerPathEntry *entry,
336                     unsigned int off)
337 {
338   if (off >= cp->path_dll_length)
339   {
340     unsigned int len = cp->path_dll_length;
341
342     GNUNET_array_grow (cp->path_heads,
343                        len,
344                        off + 4);
345     GNUNET_array_grow (cp->path_tails,
346                        cp->path_dll_length,
347                        off + 4);
348   }
349   GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
350                                cp->path_tails[off],
351                                entry);
352   cp->num_paths++;
353
354   /* If we have a tunnel to this peer, tell the tunnel that there is a
355      new path available. */
356   if (NULL != cp->t)
357     GCT_consider_path (cp->t,
358                        entry->path,
359                        off);
360 }
361
362
363 /**
364  * Remove an entry from the DLL of all of the paths that this peer is on.
365  *
366  * @param cp peer to modify
367  * @param entry an entry on a path
368  * @param off offset of this peer on the path
369  */
370 void
371 GCP_path_entry_remove (struct CadetPeer *cp,
372                        struct CadetPeerPathEntry *entry,
373                        unsigned int off)
374 {
375   GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
376                                cp->path_tails[off],
377                                entry);
378   GNUNET_assert (0 < cp->num_paths);
379   cp->num_paths--;
380 }
381
382
383 /**
384  * Try adding a @a path to this @a peer.  If the peer already
385  * has plenty of paths, return NULL.
386  *
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.
392  */
393 struct GNUNET_CONTAINER_HeapNode *
394 GCP_attach_path (struct CadetPeer *cp,
395                  struct CadetPeerPath *path,
396                  unsigned int off)
397 {
398   GNUNET_CONTAINER_HeapCostType desirability;
399   struct CadetPeerPath *root;
400   GNUNET_CONTAINER_HeapCostType root_desirability;
401   struct GNUNET_CONTAINER_HeapNode *hn;
402
403   /* FIXME: desirability is not yet initialized; tricky! */
404   desirability = GCPP_get_desirability (path);
405   if (GNUNET_NO ==
406       GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
407                                    (void **) &root,
408                                    &root_desirability))
409   {
410     root = NULL;
411     root_desirability = 0;
412   }
413
414   if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
415        (desirability < root_desirability) )
416     return NULL;
417
418   /* Yes, we'd like to add this path, add to our heap */
419   hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
420                                      (void *) cp,
421                                      desirability);
422
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)
426   {
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);
432     if (NULL ==
433         GCPP_get_connection (root,
434                              cp,
435                              GCPP_get_length (root) - 1))
436     {
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));
441       GCPP_release (root);
442     }
443   }
444   return hn;
445 }
446
447
448 /**
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.
452  *
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
456  */
457 void
458 GCP_detach_path (struct CadetPeer *cp,
459                  struct CadetPeerPath *path,
460                  struct GNUNET_CONTAINER_HeapNode *hn)
461 {
462   GNUNET_assert (path ==
463                  GNUNET_CONTAINER_heap_remove_node (hn));
464 }
465
466
467 /**
468  * This peer is now on more "active" duty, activate processes related to it.
469  *
470  * @param cp the more-active peer
471  */
472 static void
473 consider_peer_activate (struct CadetPeer *cp)
474 {
475   uint32_t strength;
476
477   if (NULL != cp->destroy_task)
478   {
479     /* It's active, do not destory! */
480     GNUNET_SCHEDULER_cancel (cp->destroy_task);
481     cp->destroy_task = NULL;
482   }
483   if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
484        (NULL == cp->t) )
485   {
486     /* We're just on a path or directly connected; don't bother too much */
487     if (NULL != cp->connectivity_suggestion)
488     {
489       GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
490       cp->connectivity_suggestion = NULL;
491     }
492     if (NULL != cp->search_h)
493     {
494       GCD_search_stop (cp->search_h);
495       cp->search_h = NULL;
496     }
497     return;
498   }
499   if (NULL == cp->core_mq)
500   {
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) )
504       cp->search_h
505         = GCD_search (&cp->pid);
506   }
507   else
508   {
509     /* Have direct connection, stop DHT search if active */
510     if (NULL != cp->search_h)
511     {
512       GCD_search_stop (cp->search_h);
513       cp->search_h = NULL;
514     }
515   }
516
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,
523                                        &cp->pid,
524                                        strength);
525 }
526
527
528 /**
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.
532  *
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
538  */
539 struct CadetPeer *
540 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
541          int create)
542 {
543   struct CadetPeer *cp;
544
545   cp = GNUNET_CONTAINER_multipeermap_get (peers,
546                                           peer_id);
547   if (NULL != cp)
548     return cp;
549   if (GNUNET_NO == create)
550     return NULL;
551   cp = GNUNET_new (struct CadetPeer);
552   cp->pid = *peer_id;
553   cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
554                                                           GNUNET_YES);
555   cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
556   GNUNET_assert (GNUNET_YES ==
557                  GNUNET_CONTAINER_multipeermap_put (peers,
558                                                     &cp->pid,
559                                                     cp,
560                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
561   return cp;
562 }
563
564
565 /**
566  * Obtain the peer identity for a `struct CadetPeer`.
567  *
568  * @param cp our peer handle
569  * @return the peer identity
570  */
571 const struct GNUNET_PeerIdentity *
572 GCP_get_id (struct CadetPeer *cp)
573 {
574   return &cp->pid;
575 }
576
577
578 /**
579  * Iterate over all known peers.
580  *
581  * @param iter Iterator.
582  * @param cls Closure for @c iter.
583  */
584 void
585 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
586                  void *cls)
587 {
588   GNUNET_CONTAINER_multipeermap_iterate (peers,
589                                          iter,
590                                          cls);
591 }
592
593
594 /**
595  * Count the number of known paths toward the peer.
596  *
597  * @param peer Peer to get path info.
598  * @return Number of known paths.
599  */
600 unsigned int
601 GCP_count_paths (const struct CadetPeer *peer)
602 {
603   return peer->num_paths;
604 }
605
606
607 /**
608  * Iterate over the paths to a peer.
609  *
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.
614  */
615 unsigned int
616 GCP_iterate_paths (struct CadetPeer *peer,
617                    GCP_PathIterator callback,
618                    void *callback_cls)
619 {
620   unsigned int ret = 0;
621
622   for (unsigned int i=0;i<peer->path_dll_length;i++)
623   {
624     for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
625          NULL != pe;
626          pe = pe->next)
627     {
628       if (GNUNET_NO ==
629           callback (callback_cls,
630                     pe->path,
631                     i))
632         return ret;
633       ret++;
634     }
635   }
636   return ret;
637 }
638
639
640 /**
641  * Iterate over the paths to @a peer where
642  * @a peer is at distance @a dist from us.
643  *
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.
649  */
650 unsigned int
651 GCP_iterate_paths_at (struct CadetPeer *peer,
652                       unsigned int dist,
653                       GCP_PathIterator callback,
654                       void *callback_cls)
655 {
656   unsigned int ret = 0;
657
658   if (dist<peer->path_dll_length)
659     return 0;
660   for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
661        NULL != pe;
662        pe = pe->next)
663   {
664     if (GNUNET_NO ==
665         callback (callback_cls,
666                   pe->path,
667                   dist))
668       return ret;
669     ret++;
670   }
671   return ret;
672 }
673
674
675 /**
676  * Get the tunnel towards a peer.
677  *
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.
681  */
682 struct CadetTunnel *
683 GCP_get_tunnel (struct CadetPeer *peer,
684                 int create)
685 {
686   if (NULL == peer)
687     return NULL;
688   if ( (NULL != peer->t) ||
689        (GNUNET_NO == create) )
690     return peer->t;
691   peer->t = GCT_create_tunnel (peer);
692   consider_peer_activate (peer);
693   return peer->t;
694 }
695
696
697 /**
698  * We got a HELLO for a @a peer, remember it, and possibly
699  * trigger adequate actions (like trying to connect).
700  *
701  * @param peer the peer we got a HELLO for
702  * @param hello the HELLO to remember
703  */
704 void
705 GCP_set_hello (struct CadetPeer *peer,
706                const struct GNUNET_HELLO_Message *hello)
707 {
708   /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
709
710   consider_peer_destroy (peer);
711 }
712
713
714 /**
715  * The tunnel to the given peer no longer exists, remove it from our
716  * data structures, and possibly clean up the peer itself.
717  *
718  * @param peer the peer affected
719  * @param t the dead tunnel
720  */
721 void
722 GCP_drop_tunnel (struct CadetPeer *peer,
723                  struct CadetTunnel *t)
724 {
725   GNUNET_assert (peer->t == t);
726   peer->t = NULL;
727   consider_peer_destroy (peer);
728 }
729
730
731 /* end of gnunet-service-cadet-new_peer.c */