more work on peer and paths structures
[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
355
356 /**
357  * Remove an entry from the DLL of all of the paths that this peer is on.
358  *
359  * @param cp peer to modify
360  * @param entry an entry on a path
361  * @param off offset of this peer on the path
362  */
363 void
364 GCP_path_entry_remove (struct CadetPeer *cp,
365                        struct CadetPeerPathEntry *entry,
366                        unsigned int off)
367 {
368   GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
369                                cp->path_tails[off],
370                                entry);
371   GNUNET_assert (0 < cp->num_paths);
372   cp->num_paths--;
373 }
374
375
376 /**
377  * Function called when the DHT finds a @a path to the peer (@a cls).
378  *
379  * @param cls the `struct CadetPeer`
380  * @param path the path that was found
381  */
382 static void
383 dht_result_cb (void *cls,
384                struct CadetPeerPath *path)
385 {
386   struct CadetPeer *cp = cls;
387   GNUNET_CONTAINER_HeapCostType desirability;
388   struct CadetPeerPath *root;
389   GNUNET_CONTAINER_HeapCostType root_desirability;
390
391   desirability = GCPP_get_desirability (path);
392   if (GNUNET_NO ==
393       GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
394                                    (void **) &root,
395                                    &root_desirability))
396   {
397     root = NULL;
398     root_desirability = 0;
399   }
400   if ( (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ||
401        (desirability >= root_desirability) )
402   {
403     /* Yes, we'd like to add this path, add to our heap */
404     GCPP_acquire (path,
405                   cp,
406                   GNUNET_CONTAINER_heap_insert (cp->path_heap,
407                                                 (void *) path,
408                                                 desirability));
409   }
410   if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
411       2 * DESIRED_CONNECTIONS_PER_TUNNEL)
412   {
413     /* Now we have way too many, drop least desirable */
414     root = GNUNET_CONTAINER_heap_remove_root (cp->path_heap);
415     GCPP_release (path);
416   }
417 }
418
419
420 /**
421  * This peer is now on more "active" duty, activate processes related to it.
422  *
423  * @param cp the more-active peer
424  */
425 static void
426 consider_peer_activate (struct CadetPeer *cp)
427 {
428   uint32_t strength;
429
430   if (NULL != cp->destroy_task)
431   {
432     /* It's active, do not destory! */
433     GNUNET_SCHEDULER_cancel (cp->destroy_task);
434     cp->destroy_task = NULL;
435   }
436   if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
437        (NULL == cp->t) )
438   {
439     /* We're just on a path or directly connected; don't bother too much */
440     if (NULL != cp->connectivity_suggestion)
441     {
442       GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
443       cp->connectivity_suggestion = NULL;
444     }
445     if (NULL != cp->search_h)
446     {
447       GCD_search_stop (cp->search_h);
448       cp->search_h = NULL;
449     }
450     return;
451   }
452   if (NULL == cp->core_mq)
453   {
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) )
457       cp->search_h
458         = GCD_search (&cp->pid,
459                       &dht_result_cb,
460                       cp);
461   }
462   else
463   {
464     /* Have direct connection, stop DHT search if active */
465     if (NULL != cp->search_h)
466     {
467       GCD_search_stop (cp->search_h);
468       cp->search_h = NULL;
469     }
470   }
471
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,
478                                        &cp->pid,
479                                        strength);
480 }
481
482
483 /**
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.
487  *
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
493  */
494 struct CadetPeer *
495 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
496          int create)
497 {
498   struct CadetPeer *cp;
499
500   cp = GNUNET_CONTAINER_multipeermap_get (peers,
501                                           peer_id);
502   if (NULL != cp)
503     return cp;
504   if (GNUNET_NO == create)
505     return NULL;
506   cp = GNUNET_new (struct CadetPeer);
507   cp->pid = *peer_id;
508   cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
509                                                           GNUNET_YES);
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!?
513
514   GNUNET_assert (GNUNET_YES ==
515                  GNUNET_CONTAINER_multipeermap_put (peers,
516                                                     &cp->pid,
517                                                     cp,
518                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
519   return cp;
520 }
521
522
523 /**
524  * Obtain the peer identity for a `struct CadetPeer`.
525  *
526  * @param cp our peer handle
527  * @param[out] peer_id where to write the peer identity
528  */
529 void
530 GCP_id (struct CadetPeer *cp,
531         struct GNUNET_PeerIdentity *peer_id)
532 {
533   *peer_id = cp->pid;
534 }
535
536
537 /**
538  * Iterate over all known peers.
539  *
540  * @param iter Iterator.
541  * @param cls Closure for @c iter.
542  */
543 void
544 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
545                  void *cls)
546 {
547   GNUNET_CONTAINER_multipeermap_iterate (peers,
548                                          iter,
549                                          cls);
550 }
551
552
553 /**
554  * Count the number of known paths toward the peer.
555  *
556  * @param peer Peer to get path info.
557  * @return Number of known paths.
558  */
559 unsigned int
560 GCP_count_paths (const struct CadetPeer *peer)
561 {
562   return peer->num_paths;
563 }
564
565
566 /**
567  * Iterate over the paths to a peer.
568  *
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.
573  */
574 unsigned int
575 GCP_iterate_paths (struct CadetPeer *peer,
576                    GCP_PathIterator callback,
577                    void *callback_cls)
578 {
579   unsigned int ret = 0;
580
581   for (unsigned int i=0;i<peer->path_dll_length;i++)
582   {
583     for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
584          NULL != pe;
585          pe = pe->next)
586     {
587       if (GNUNET_NO ==
588           callback (callback_cls,
589                     peer,
590                     pe->path))
591         return ret;
592       ret++;
593     }
594   }
595   return ret;
596 }
597
598
599 /**
600  * Get the tunnel towards a peer.
601  *
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.
605  */
606 struct CadetTunnel *
607 GCP_get_tunnel (struct CadetPeer *peer,
608                 int create)
609 {
610   if (NULL == peer)
611     return NULL;
612   if ( (NULL != peer->t) ||
613        (GNUNET_NO == create) )
614     return peer->t;
615   peer->t = GCT_create_tunnel (peer);
616   consider_peer_activate (peer);
617   return peer->t;
618 }
619
620
621 /**
622  * We got a HELLO for a @a peer, remember it, and possibly
623  * trigger adequate actions (like trying to connect).
624  *
625  * @param peer the peer we got a HELLO for
626  * @param hello the HELLO to remember
627  */
628 void
629 GCP_set_hello (struct CadetPeer *peer,
630                const struct GNUNET_HELLO_Message *hello)
631 {
632   /* FIXME! */
633
634   consider_peer_destroy (peer);
635 }
636
637
638 /**
639  * The tunnel to the given peer no longer exists, remove it from our
640  * data structures, and possibly clean up the peer itself.
641  *
642  * @param peer the peer affected
643  * @param t the dead tunnel
644  */
645 void
646 GCP_drop_tunnel (struct CadetPeer *peer,
647                  struct CadetTunnel *t)
648 {
649   GNUNET_assert (peer->t == t);
650   peer->t = NULL;
651   consider_peer_destroy (peer);
652 }
653
654
655 /* end of gnunet-service-cadet-new_peer.c */