design CadetPeerPathEntry data structure
[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_tunnels.h"
41
42 /**
43  * How long do we wait until tearing down an idle peer?
44  */
45 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
46
47 /**
48  * Struct containing all information regarding a given peer
49  */
50 struct CadetPeer
51 {
52   /**
53    * ID of the peer
54    */
55   struct GNUNET_PeerIdentity pid;
56
57   /**
58    * Last time we heard from this peer
59    */
60   struct GNUNET_TIME_Absolute last_contact;
61
62   /**
63    * Array of DLLs of paths traversing the peer, organized by the
64    * offset of the peer on the larger path.
65    */
66   struct CadetPeerPathEntry **path_heads;
67
68   /**
69    * Array of DLL of paths traversing the peer, organized by the
70    * offset of the peer on the larger path.
71    */
72   struct CadetPeerPathEntry **path_tails;
73
74   /**
75    * MIN-heap of paths ending at this peer.  Ordered by desirability.
76    */
77   struct GNUNET_CONTAINER_Heap *path_heap;
78
79   /**
80    * Handle to stop the DHT search for paths to this peer
81    */
82   struct GCD_search_handle *search_h;
83
84   /**
85    * Task to stop the DHT search for paths to this peer
86    */
87   struct GNUNET_SCHEDULER_Task *search_delayedXXX;
88
89   /**
90    * Task to destroy this entry.
91    */
92   struct GNUNET_SCHEDULER_Task *destroy_task;
93
94   /**
95    * Tunnel to this peer, if any.
96    */
97   struct CadetTunnel *t;
98
99   /**
100    * Connections that go through this peer; indexed by tid.
101    */
102   struct GNUNET_CONTAINER_MultiHashMap *connections;
103
104   /**
105    * Handle for core transmissions.
106    */
107   struct GNUNET_MQ_Handle *core_mq;
108
109   /**
110    * Hello message of the peer.
111    */
112   struct GNUNET_HELLO_Message *hello;
113
114   /**
115    * Handle to us offering the HELLO to the transport.
116    */
117   struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
118
119   /**
120    * Handle to our ATS request asking ATS to suggest an address
121    * to TRANSPORT for this peer (to establish a direct link).
122    */
123   struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
124
125   /**
126    * How many messages are in the queue to this peer.
127    */
128   unsigned int queue_n;
129
130   /**
131    * How many paths do we have to this peer (in all @e path_heads DLLs combined).
132    */
133   unsigned int num_paths;
134
135   /**
136    * Current length of the @e path_heads and @path_tails arrays.
137    * The arrays should be grown as needed.
138    */
139   unsigned int path_dll_length;
140
141 };
142
143
144 /**
145  * Get the static string for a peer ID.
146  *
147  * @param peer Peer.
148  *
149  * @return Static string for it's ID.
150  */
151 const char *
152 GCP_2s (const struct CadetPeer *peer)
153 {
154   if (NULL == peer)
155     return "PEER(NULL)";
156   return GNUNET_i2s (&peer->pid);
157 }
158
159
160 /**
161  * This peer is no longer be needed, clean it up now.
162  *
163  * @param cls peer to clean up
164  */
165 static void
166 destroy_peer (void *cls)
167 {
168   struct CadetPeer *cp = cls;
169
170   cp->destroy_task = NULL;
171   GNUNET_assert (NULL == cp->t);
172   GNUNET_assert (NULL == cp->core_mq);
173   GNUNET_assert (0 == cp->path_dll_length);
174   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
175   GNUNET_assert (GNUNET_YES ==
176                  GNUNET_CONTAINER_multipeermap_remove (peers,
177                                                        &cp->pid,
178                                                        cp));
179   GNUNET_free_non_null (cp->path_heads);
180   GNUNET_free_non_null (cp->path_tails);
181   cp->path_dll_length = 0;
182   if (NULL != cp->search_h)
183   {
184     GCD_search_stop (cp->search_h);
185     cp->search_h = NULL;
186   }
187   /* FIXME: clean up search_delayedXXX! */
188
189   GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
190   GNUNET_free_non_null (cp->hello);
191   if (NULL != cp->hello_offer)
192   {
193     GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
194     cp->hello_offer = NULL;
195   }
196   if (NULL != cp->connectivity_suggestion)
197   {
198     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
199     cp->connectivity_suggestion = NULL;
200   }
201   GNUNET_free (cp);
202 }
203
204
205 /**
206  * Function called to destroy a peer now.
207  *
208  * @param cls NULL
209  * @param pid identity of the peer (unused)
210  * @param value the `struct CadetPeer` to clean up
211  * @return #GNUNET_OK (continue to iterate)
212  */
213 static int
214 destroy_iterator_cb (void *cls,
215                      const struct GNUNET_PeerIdentity *pid,
216                      void *value)
217 {
218   struct CadetPeer *cp = value;
219
220   if (NULL != cp->destroy_task)
221   {
222     GNUNET_SCHEDULER_cancel (cp->destroy_task);
223     cp->destroy_task = NULL;
224   }
225   destroy_peer (cp);
226   return GNUNET_OK;
227 }
228
229
230 /**
231  * Clean up all entries about all peers.
232  * Must only be called after all tunnels, CORE-connections and
233  * connections are down.
234  */
235 void
236 GCP_destroy_all_peers ()
237 {
238   GNUNET_CONTAINER_multipeermap_iterate (peers,
239                                          &destroy_iterator_cb,
240                                          NULL);
241 }
242
243
244 /**
245  * This peer may no longer be needed, consider cleaning it up.
246  *
247  * @param cp peer to clean up
248  */
249 static void
250 consider_peer_destroy (struct CadetPeer *cp)
251 {
252   struct GNUNET_TIME_Relative exp;
253
254   if (NULL != cp->destroy_task)
255   {
256     GNUNET_SCHEDULER_cancel (cp->destroy_task);
257     cp->destroy_task = NULL;
258   }
259   if (NULL != cp->t)
260     return; /* still relevant! */
261   if (NULL != cp->core_mq)
262     return; /* still relevant! */
263   if (0 != cp->path_dll_length)
264     return; /* still relevant! */
265   if (0 != GNUNET_CONTAINER_multihashmap_size (cp->connections))
266     return; /* still relevant! */
267   if (NULL != cp->hello)
268   {
269     /* relevant only until HELLO expires */
270     exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
271     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
272                                                        &destroy_peer,
273                                                        cp);
274     return;
275   }
276   cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
277                                                    &destroy_peer,
278                                                    cp);
279 }
280
281
282 /**
283  * Add an entry to the DLL of all of the paths that this peer is on.
284  *
285  * @param cp peer to modify
286  * @param entry an entry on a path
287  * @param off offset of this peer on the path
288  */
289 void
290 GCP_path_entry_add (struct CadetPeer *cp,
291                     struct CadetPeerPathEntry *entry,
292                     unsigned int off)
293 {
294   if (off >= cp->path_dll_length)
295   {
296     unsigned int len = cp->path_dll_length;
297
298     GNUNET_array_grow (cp->path_heads,
299                        len,
300                        off + 4);
301     GNUNET_array_grow (cp->path_tails,
302                        cp->path_dll_length,
303                        off + 4);
304   }
305   GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
306                                cp->path_tails[off],
307                                entry);
308   cp->num_paths++;
309 }
310
311
312 /**
313  * Remove an entry from the DLL of all of the paths that this peer is on.
314  *
315  * @param cp peer to modify
316  * @param entry an entry on a path
317  * @param off offset of this peer on the path
318  */
319 void
320 GCP_path_entry_remove (struct CadetPeer *cp,
321                        struct CadetPeerPathEntry *entry,
322                        unsigned int off)
323 {
324   GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
325                                cp->path_tails[off],
326                                entry);
327   GNUNET_assert (0 < cp->num_paths);
328   cp->num_paths--;
329 }
330
331
332 /**
333  * Function called when the DHT finds a @a path to the peer (@a cls).
334  *
335  * @param cls the `struct CadetPeer`
336  * @param path the path that was found
337  */
338 static void
339 dht_result_cb (void *cls,
340                const struct CadetPeerPath *path)
341 {
342   struct CadetPeer *cp = cls;
343   GNUNET_CONTAINER_HeapCostType desirability;
344   struct CadetPeerPath *root;
345   GNUNET_CONTAINER_HeapCostType root_desirability;
346
347   desirability = GCPP_get_desirability (path);
348   if (GNUNET_NO ==
349       GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
350                                    (void **) &root,
351                                    &root_desirability))
352   {
353     root = NULL;
354     root_desirability = 0;
355   }
356   if ( (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ||
357        (desirability >= root_desirability) )
358   {
359     /* Yes, we'd like to add this path, add to our heap */
360     GCPP_acquire (path,
361                   cp,
362                   GNUNET_CONTAINER_heap_insert (cp->path_heap,
363                                                 (void *) path,
364                                                 desirability));
365   }
366   if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
367       2 * DESIRED_CONNECTIONS_PER_TUNNEL)
368   {
369     /* Now we have way too many, drop least desirable */
370     root = GNUNET_CONTAINER_heap_remove_root (cp->path_heap);
371     GCPP_release (path,
372                   cp);
373   }
374 }
375
376
377 /**
378  * This peer is now on more "active" duty, activate processes related to it.
379  *
380  * @param cp the more-active peer
381  */
382 static void
383 consider_peer_activate (struct CadetPeer *cp)
384 {
385   uint32_t strength;
386
387   if (NULL != cp->destroy_task)
388   {
389     /* It's active, do not destory! */
390     GNUNET_SCHEDULER_cancel (cp->destroy_task);
391     cp->destroy_task = NULL;
392   }
393   if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
394        (NULL == cp->t) )
395   {
396     /* We're just on a path or directly connected; don't bother too much */
397     if (NULL != cp->connectivity_suggestion)
398     {
399       GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
400       cp->connectivity_suggestion = NULL;
401     }
402     if (NULL != cp->search_h)
403     {
404       GCD_search_stop (cp->search_h);
405       cp->search_h = NULL;
406     }
407     return;
408   }
409   if (NULL == cp->core_mq)
410   {
411     /* Lacks direct connection, try to create one by querying the DHT */
412     if ( (NULL == cp->search_h) &&
413          (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
414       cp->search_h
415         = GCD_search (&cp->pid,
416                       &dht_result_cb,
417                       cp);
418   }
419   else
420   {
421     /* Have direct connection, stop DHT search if active */
422     if (NULL != cp->search_h)
423     {
424       GCD_search_stop (cp->search_h);
425       cp->search_h = NULL;
426     }
427   }
428
429   /* If we have a tunnel, our urge for connections is much bigger */
430   strength = (NULL != cp->t) ? 32 : 1;
431   if (NULL != cp->connectivity_suggestion)
432     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
433   cp->connectivity_suggestion
434     = GNUNET_ATS_connectivity_suggest (ats_ch,
435                                        &cp->pid,
436                                        strength);
437 }
438
439
440 /**
441  * Retrieve the CadetPeer stucture associated with the
442  * peer. Optionally create one and insert it in the appropriate
443  * structures if the peer is not known yet.
444  *
445  * @param peer_id Full identity of the peer.
446  * @param create #GNUNET_YES if a new peer should be created if unknown.
447  *               #GNUNET_NO to return NULL if peer is unknown.
448  * @return Existing or newly created peer structure.
449  *         NULL if unknown and not requested @a create
450  */
451 struct CadetPeer *
452 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
453          int create)
454 {
455   struct CadetPeer *cp;
456
457   cp = GNUNET_CONTAINER_multipeermap_get (peers,
458                                           peer_id);
459   if (NULL != cp)
460     return cp;
461   if (GNUNET_NO == create)
462     return NULL;
463   cp = GNUNET_new (struct CadetPeer);
464   cp->pid = *peer_id;
465   cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
466                                                           GNUNET_YES);
467   cp->search_h = NULL; // FIXME: start search immediately!?
468   cp->connectivity_suggestion = NULL; // FIXME: request with ATS!?
469
470   GNUNET_assert (GNUNET_YES ==
471                  GNUNET_CONTAINER_multipeermap_put (peers,
472                                                     &cp->pid,
473                                                     cp,
474                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
475   return cp;
476 }
477
478
479 /**
480  * Obtain the peer identity for a `struct CadetPeer`.
481  *
482  * @param cp our peer handle
483  * @param[out] peer_id where to write the peer identity
484  */
485 void
486 GCP_id (struct CadetPeer *cp,
487         struct GNUNET_PeerIdentity *peer_id)
488 {
489   *peer_id = cp->pid;
490 }
491
492
493 /**
494  * Iterate over all known peers.
495  *
496  * @param iter Iterator.
497  * @param cls Closure for @c iter.
498  */
499 void
500 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
501                  void *cls)
502 {
503   GNUNET_CONTAINER_multipeermap_iterate (peers,
504                                          iter,
505                                          cls);
506 }
507
508
509 /**
510  * Count the number of known paths toward the peer.
511  *
512  * @param peer Peer to get path info.
513  * @return Number of known paths.
514  */
515 unsigned int
516 GCP_count_paths (const struct CadetPeer *peer)
517 {
518   return peer->num_paths;
519 }
520
521
522 /**
523  * Iterate over the paths to a peer.
524  *
525  * @param peer Peer to get path info.
526  * @param callback Function to call for every path.
527  * @param callback_cls Closure for @a callback.
528  * @return Number of iterated paths.
529  */
530 unsigned int
531 GCP_iterate_paths (struct CadetPeer *peer,
532                    GCP_PathIterator callback,
533                    void *callback_cls)
534 {
535   unsigned int ret = 0;
536
537   for (unsigned int i=0;i<peer->path_dll_length;i++)
538   {
539     for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
540          NULL != pe;
541          pe = pe->next)
542     {
543       if (GNUNET_NO ==
544           callback (callback_cls,
545                     peer,
546                     pe->path))
547         return ret;
548       ret++;
549     }
550   }
551   return ret;
552 }
553
554
555 /**
556  * Get the tunnel towards a peer.
557  *
558  * @param peer Peer to get from.
559  * @param create #GNUNET_YES to create a tunnel if we do not have one
560  * @return Tunnel towards peer.
561  */
562 struct CadetTunnel *
563 GCP_get_tunnel (struct CadetPeer *peer,
564                 int create)
565 {
566   if (NULL == peer)
567     return NULL;
568   if ( (NULL != peer->t) ||
569        (GNUNET_NO == create) )
570     return peer->t;
571   peer->t = GCT_create_tunnel (peer);
572   consider_peer_activate (peer);
573   return peer->t;
574 }
575
576
577 /**
578  * We got a HELLO for a @a peer, remember it, and possibly
579  * trigger adequate actions (like trying to connect).
580  *
581  * @param peer the peer we got a HELLO for
582  * @param hello the HELLO to remember
583  */
584 void
585 GCP_set_hello (struct CadetPeer *peer,
586                const struct GNUNET_HELLO_Message *hello)
587 {
588   /* FIXME! */
589
590   consider_peer_destroy (peer);
591 }
592
593
594 /**
595  * The tunnel to the given peer no longer exists, remove it from our
596  * data structures, and possibly clean up the peer itself.
597  *
598  * @param peer the peer affected
599  * @param t the dead tunnel
600  */
601 void
602 GCP_drop_tunnel (struct CadetPeer *peer,
603                  struct CadetTunnel *t)
604 {
605   GNUNET_assert (peer->t == t);
606   peer->t = NULL;
607   consider_peer_destroy (peer);
608 }
609
610
611 /* end of gnunet-service-cadet-new_peer.c */