fix shutdown sequence
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_paths.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001-2017 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file cadet/gnunet-service-cadet-new_paths.c
22  * @brief Information we track per path.
23  * @author Bartlomiej Polot
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - path desirability score calculations are not done
28  */
29 #include "platform.h"
30 #include "gnunet-service-cadet-new_connection.h"
31 #include "gnunet-service-cadet-new_tunnels.h"
32 #include "gnunet-service-cadet-new_peer.h"
33 #include "gnunet-service-cadet-new_paths.h"
34
35
36 #define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
37
38
39 /**
40  * Information regarding a possible path to reach a peer.
41  */
42 struct CadetPeerPath
43 {
44
45   /**
46    * Array of all the peers on the path.  If @e hn is non-NULL, the
47    * last one is our owner.
48    */
49   struct CadetPeerPathEntry **entries;
50
51   /**
52    * Node of this path in the owner's heap.  Used to update our position
53    * in the heap whenever our @e desirability changes.
54    */
55   struct GNUNET_CONTAINER_HeapNode *hn;
56
57   /**
58    * Desirability of the path. How unique is it for the various peers
59    * on it?
60    */
61   GNUNET_CONTAINER_HeapCostType desirability;
62
63   /**
64    * Length of the @e entries array.
65    */
66   unsigned int entries_length;
67
68 };
69
70
71 /**
72  * Calculate the path's desirability score.
73  *
74  * @param path path to calculate the score for
75  */
76 static void
77 recalculate_path_desirability (struct CadetPeerPath *path)
78 {
79   /* FIXME: update path desirability! */
80   GNUNET_break (0); // not implemented
81 }
82
83
84 /**
85  * Return how much we like keeping the path.  This is an aggregate
86  * score based on various factors, including the age of the path
87  * (older == better), and the value of this path to all of its ajacent
88  * peers.  For example, long paths that end at a peer that we have no
89  * shorter way to reach are very desirable, while long paths that end
90  * at a peer for which we have a shorter way as well are much less
91  * desirable.  Higher values indicate more valuable paths.  The
92  * returned value should be used to decide which paths to remember.
93  *
94  * @param path path to return the length for
95  * @return desirability of the path, larger is more desirable
96  */
97 GNUNET_CONTAINER_HeapCostType
98 GCPP_get_desirability (const struct CadetPeerPath *path)
99 {
100   return path->desirability;
101 }
102
103
104 /**
105  * Return connection to @a destination using @a path, or return
106  * NULL if no such connection exists.
107  *
108  * @param path path to traverse
109  * @param destination destination node to get to, must be on path
110  * @param off offset of @a destination on @a path
111  * @return NULL if we have no existing connection
112  *         otherwise connection from us to @a destination via @a path
113  */
114 struct CadetConnection *
115 GCPP_get_connection (struct CadetPeerPath *path,
116                      struct CadetPeer *destination,
117                      unsigned int off)
118 {
119   struct CadetPeerPathEntry *entry;
120
121   GNUNET_assert (off < path->entries_length);
122   entry = path->entries[off];
123   GNUNET_assert (entry->peer == destination);
124   return entry->cc;
125 }
126
127
128 /**
129  * Notify @a path that it is used for connection @a cc
130  * which ends at the path's offset @a off.
131  *
132  * @param path the path to remember the @a cc
133  * @param off the offset where the @a cc ends
134  * @param cc the connection to remember
135  */
136 void
137 GCPP_add_connection (struct CadetPeerPath *path,
138                      unsigned int off,
139                      struct CadetConnection *cc)
140 {
141   struct CadetPeerPathEntry *entry;
142
143   LOG (GNUNET_ERROR_TYPE_DEBUG,
144        "Adding connection %s to path %s at offset %u\n",
145        GCC_2s (cc),
146        GCPP_2s (path),
147        off);
148   GNUNET_assert (off < path->entries_length);
149   entry = path->entries[off];
150   GNUNET_assert (NULL == entry->cc);
151   entry->cc = cc;
152 }
153
154
155
156 /**
157  * Notify @a path that it is no longer used for connection @a cc which
158  * ended at the path's offset @a off.
159  *
160  * @param path the path to forget the @a cc
161  * @param off the offset where the @a cc ended
162  * @param cc the connection to forget
163  */
164 void
165 GCPP_del_connection (struct CadetPeerPath *path,
166                      unsigned int off,
167                      struct CadetConnection *cc)
168 {
169   struct CadetPeerPathEntry *entry;
170
171   LOG (GNUNET_ERROR_TYPE_DEBUG,
172        "Removing connection %s to path %s at offset %u\n",
173        GCC_2s (cc),
174        GCPP_2s (path),
175        off);
176   GNUNET_assert (off < path->entries_length);
177   entry = path->entries[off];
178   GNUNET_assert (cc == entry->cc);
179   entry->cc = NULL;
180 }
181
182
183 /**
184  * This path is no longer needed, free resources.
185  *
186  * @param path path resources to free
187  */
188 static void
189 path_destroy (struct CadetPeerPath *path)
190 {
191   LOG (GNUNET_ERROR_TYPE_DEBUG,
192        "Destroying path %s\n",
193        GCPP_2s (path));
194   for (unsigned int i=0;i<path->entries_length;i++)
195   {
196     struct CadetPeerPathEntry *entry = path->entries[i];
197
198     if (NULL != entry->cc)
199     {
200       struct CadetTConnection *ct;
201
202       ct = GCC_get_ct (entry->cc);
203       if (NULL != ct)
204         GCT_connection_lost (ct);
205       GCC_destroy_without_tunnel (entry->cc);
206     }
207     GNUNET_free (entry);
208   }
209   GNUNET_free (path->entries);
210   GNUNET_free (path);
211 }
212
213
214 /**
215  * The owning peer of this path is no longer interested in maintaining
216  * it, so the path should be discarded or shortened (in case a
217  * previous peer on the path finds the path desirable).
218  *
219  * @param path the path that is being released
220  */
221 void
222 GCPP_release (struct CadetPeerPath *path)
223 {
224   struct CadetPeerPathEntry *entry;
225
226   LOG (GNUNET_ERROR_TYPE_DEBUG,
227        "Owner releases path %s\n",
228        GCPP_2s (path));
229   path->hn = NULL;
230   entry = path->entries[path->entries_length - 1];
231   while (1)
232   {
233     /* cut 'off' end of path */
234     GCP_path_entry_remove (entry->peer,
235                            entry,
236                            path->entries_length - 1);
237     path->entries_length--; /* We don't bother shrinking the 'entries' array,
238                                as it's probably not worth it. */
239     GNUNET_free (entry);
240     if (0 == path->entries_length)
241       break; /* the end */
242
243     /* see if new peer at the end likes this path any better */
244     entry = path->entries[path->entries_length - 1];
245     path->hn = GCP_attach_path (entry->peer,
246                                 path,
247                                 path->entries_length - 1,
248                                 GNUNET_NO);
249     if (NULL != path->hn)
250       return; /* yep, got attached, we are done. */
251   }
252
253   /* nobody wants us, discard the path */
254   path_destroy (path);
255 }
256
257
258 /**
259  * Updates the score for an entry on the path based
260  * on our experiences with using @a path.
261  *
262  * @param path the path to update
263  * @param off offset of the entry to update
264  * @param delta change in the score to apply
265  */
266 void
267 GCPP_update_score (struct CadetPeerPath *path,
268                    unsigned int off,
269                    int delta)
270 {
271   struct CadetPeerPathEntry *entry;
272
273   GNUNET_assert (off < path->entries_length);
274   entry = path->entries[off];
275
276   /* Add delta, with checks for overflows */
277   if (delta >= 0)
278   {
279     if (delta + entry->score < entry->score)
280       entry->score = INT_MAX;
281     else
282       entry->score += delta;
283   }
284   else
285   {
286     if (delta + entry->score > entry->score)
287       entry->score = INT_MIN;
288     else
289       entry->score += delta;
290   }
291   recalculate_path_desirability (path);
292 }
293
294
295 /**
296  * Closure for #find_peer_at() and #check_match().
297  */
298 struct CheckMatchContext
299 {
300
301   /**
302    * Set to a matching path, if any.
303    */
304   struct CadetPeerPath *match;
305
306   /**
307    * Array the combined paths.
308    */
309   struct CadetPeer **cpath;
310
311   /**
312    * How long is the @e cpath array?
313    */
314   unsigned int cpath_length;
315
316 };
317
318
319 /**
320  * Check if the given path is identical on all of the
321  * hops until @a off, and not longer than @a off.  If the
322  * @a path matches, store it in `match`.
323  *
324  * @param cls the `struct CheckMatchContext` to check against
325  * @param path the path to check
326  * @param off offset to check at
327  * @return #GNUNET_YES (continue to iterate), or if found #GNUNET_NO
328  */
329 static int
330 check_match (void *cls,
331              struct CadetPeerPath *path,
332              unsigned int off)
333 {
334   struct CheckMatchContext *cm_ctx = cls;
335
336   GNUNET_assert (path->entries_length > off);
337   if ( (path->entries_length != off + 1) &&
338        (off + 1 != cm_ctx->cpath_length) )
339   {
340     LOG (GNUNET_ERROR_TYPE_DEBUG,
341          "check_match missmatch because path %s is too long (%u vs. %u vs. %u)\n",
342          GCPP_2s (path),
343          path->entries_length,
344          off + 1,
345          cm_ctx->cpath_length);
346     return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
347   }
348   for (unsigned int i=0;i<off;i++)
349     if (cm_ctx->cpath[i] !=
350         GCPP_get_peer_at_offset (path,
351                                  i))
352     {
353       LOG (GNUNET_ERROR_TYPE_DEBUG,
354            "check_match path %s missmatches at offset %u\n",
355            GCPP_2s (path),
356            i);
357       return GNUNET_YES; /* missmatch, ignore */
358     }
359   LOG (GNUNET_ERROR_TYPE_DEBUG,
360        "check_match found match with path %s\n",
361        GCPP_2s (path));
362   cm_ctx->match = path;
363   return GNUNET_NO; /* match, we are done! */
364 }
365
366
367 /**
368  * Extend path @a path by the @a num_peers from the @a peers
369  * array, assuming the owners past the current owner want it.
370  *
371  * @param path path to extend
372  * @param peers list of peers beyond the end of @a path
373  * @param num_peers length of the @a peers array
374  * @param force force attachment, even if we have other
375  *        paths already
376  */
377 static void
378 extend_path (struct CadetPeerPath *path,
379              struct CadetPeer **peers,
380              unsigned int num_peers,
381              int force)
382 {
383   unsigned int old_len = path->entries_length;
384   struct GNUNET_CONTAINER_HeapNode *hn;
385   int i;
386
387   /* Expand path */
388   GNUNET_array_grow (path->entries,
389                      path->entries_length,
390                      old_len + num_peers);
391   for (i=num_peers-1;i >= 0;i--)
392   {
393     struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
394
395     path->entries[old_len + i] = entry;
396     entry->peer = peers[i];
397     entry->path = path;
398   }
399   for (i=num_peers-1;i >= 0;i--)
400   {
401     struct CadetPeerPathEntry *entry = path->entries[old_len + i];
402
403     GCP_path_entry_add (entry->peer,
404                         entry,
405                         old_len + i);
406   }
407
408   /* If we extend an existing path, detach it from the
409      old owner and re-attach to the new one */
410   hn = NULL;
411   for (i=num_peers-1;i>=0;i--)
412   {
413     struct CadetPeerPathEntry *entry = path->entries[old_len + i];
414
415     path->entries_length = old_len + i + 1;
416     recalculate_path_desirability (path);
417     hn = GCP_attach_path (peers[i],
418                           path,
419                           old_len + (unsigned int) i,
420                           GNUNET_YES);
421     if (NULL != hn)
422       break;
423     GCP_path_entry_remove (entry->peer,
424                            entry,
425                            old_len + i);
426     GNUNET_free (entry);
427     path->entries[old_len + i] = NULL;
428   }
429   if (NULL == hn)
430   {
431     /* none of the peers is interested in this path;
432        shrink path back */
433     GNUNET_array_grow (path->entries,
434                        path->entries_length,
435                        old_len);
436     return;
437   }
438   GCP_detach_path (path->entries[old_len-1]->peer,
439                    path,
440                    path->hn);
441   path->hn = hn;
442   LOG (GNUNET_ERROR_TYPE_DEBUG,
443        "Extended path %s\n",
444        GCPP_2s (path));
445 }
446
447
448 /**
449  * Create a peer path based on the result of a DHT lookup.  If we
450  * already know this path, or one that is longer, simply return NULL.
451  * Otherwise, we try to extend an existing path, or create a new one
452  * if applicable.
453  *
454  * @param get_path path of the get request
455  * @param get_path_length lenght of @a get_path
456  * @param put_path path of the put request
457  * @param put_path_length length of the @a put_path
458  * @return a path through the network
459  */
460 void
461 GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
462                         unsigned int get_path_length,
463                         const struct GNUNET_PeerIdentity *put_path,
464                         unsigned int put_path_length)
465 {
466   struct CadetPeer *cpath[get_path_length + put_path_length];
467   struct CheckMatchContext cm_ctx;
468   struct CadetPeerPath *path;
469   struct GNUNET_CONTAINER_HeapNode *hn;
470   int i;
471   unsigned int skip;
472   unsigned int total_len;
473
474   /* precompute 'cpath' so we can avoid doing the lookups lots of times */
475   skip = 0;
476   total_len = get_path_length + put_path_length;
477   for (unsigned int off=0;off<total_len;off++)
478   {
479     const struct GNUNET_PeerIdentity *pid;
480
481     pid = (off < get_path_length)
482       ? &get_path[get_path_length - off]
483       : &put_path[get_path_length + put_path_length - off];
484     cpath[off - skip] = GCP_get (pid,
485                                  GNUNET_YES);
486     /* Check that no peer is twice on the path */
487     for (unsigned int i=0;i<off;i++)
488     {
489       if (cpath[i] == cpath[off])
490       {
491         skip = off - i;
492         break;
493       }
494     }
495   }
496   total_len -= skip;
497
498   /* First figure out if this path is a subset of an existing path, an
499      extension of an existing path, or a new path. */
500   cm_ctx.cpath_length = total_len;
501   cm_ctx.cpath = cpath;
502   cm_ctx.match = NULL;
503   for (i=total_len-1;i>=0;i--)
504   {
505     GCP_iterate_paths_at (cpath[i],
506                           (unsigned int) i,
507                           &check_match,
508                           &cm_ctx);
509     if (NULL != cm_ctx.match)
510     {
511       if (i == total_len - 1)
512       {
513         /* Existing path includes this one, nothing to do! */
514         LOG (GNUNET_ERROR_TYPE_DEBUG,
515              "Path discovered from DHT is already known\n");
516         return;
517       }
518       if (cm_ctx.match->entries_length == i + 1)
519       {
520         /* Existing path ends in the middle of new path, extend it! */
521         LOG (GNUNET_ERROR_TYPE_DEBUG,
522              "Trying to extend existing path %s by additional links discovered from DHT\n",
523              GCPP_2s (cm_ctx.match));
524         extend_path (cm_ctx.match,
525                      &cpath[i + 1],
526                      total_len - i - 1,
527                      GNUNET_NO);
528         return;
529       }
530     }
531   }
532
533   /* No match at all, create completely new path */
534   path = GNUNET_new (struct CadetPeerPath);
535   path->entries_length = total_len;
536   path->entries = GNUNET_new_array (path->entries_length,
537                                     struct CadetPeerPathEntry *);
538   for (i=path->entries_length-1;i>=0;i--)
539   {
540     struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
541
542     path->entries[i] = entry;
543     entry->peer = cpath[i];
544     entry->path = path;
545   }
546   for (i=path->entries_length-1;i>=0;i--)
547   {
548     struct CadetPeerPathEntry *entry = path->entries[i];
549
550     GCP_path_entry_add (entry->peer,
551                         entry,
552                         i);
553   }
554
555   /* Finally, try to attach it */
556   hn = NULL;
557   for (i=total_len-1;i>=0;i--)
558   {
559     struct CadetPeerPathEntry *entry = path->entries[i];
560
561     path->entries_length = i + 1;
562     recalculate_path_desirability (path);
563     hn = GCP_attach_path (cpath[i],
564                           path,
565                           (unsigned int) i,
566                           GNUNET_NO);
567     if (NULL != hn)
568       break;
569     GCP_path_entry_remove (entry->peer,
570                            entry,
571                            i);
572     GNUNET_free (entry);
573     path->entries[i] = NULL;
574   }
575   if (NULL == hn)
576   {
577     /* None of the peers on the path care about it. */
578     LOG (GNUNET_ERROR_TYPE_DEBUG,
579          "Path discovered from DHT is not interesting to us\n");
580     GNUNET_free (path->entries);
581     GNUNET_free (path);
582     return;
583   }
584   path->hn = hn;
585   /* Shrink path to actual useful length */
586   GNUNET_array_grow (path->entries,
587                      path->entries_length,
588                      i + 1);
589   LOG (GNUNET_ERROR_TYPE_DEBUG,
590        "Created new path %s based on information from DHT\n",
591        GCPP_2s (path));
592 }
593
594
595 /**
596  * We got an incoming connection, obtain the corresponding path.
597  *
598  * @param path_length number of segments on the @a path
599  * @param pids path through the network, in reverse order (we are at the end at index @a path_length)
600  * @return corresponding path object
601  */
602 struct CadetPeerPath *
603 GCPP_get_path_from_route (unsigned int path_length,
604                           const struct GNUNET_PeerIdentity *pids)
605 {
606   struct CheckMatchContext cm_ctx;
607   struct CadetPeer *cpath[path_length];
608   struct CadetPeerPath *path;
609
610   /* precompute inverted 'cpath' so we can avoid doing the lookups and
611      have the correct order */
612   for (unsigned int off=0;off<path_length;off++)
613     cpath[off] = GCP_get (&pids[path_length - 1 - off],
614                           GNUNET_YES);
615
616   /* First figure out if this path is a subset of an existing path, an
617      extension of an existing path, or a new path. */
618   cm_ctx.cpath = cpath;
619   cm_ctx.cpath_length = path_length;
620   cm_ctx.match = NULL;
621   for (int i=path_length-1;i>=0;i--)
622   {
623     GCP_iterate_paths_at (cpath[i],
624                           (unsigned int) i,
625                           &check_match,
626                           &cm_ctx);
627     if (NULL != cm_ctx.match)
628     {
629       if (i == path_length - 1)
630       {
631         /* Existing path includes this one, return the match! */
632         LOG (GNUNET_ERROR_TYPE_DEBUG,
633              "Returning existing path %s as inverse for incoming connection\n",
634              GCPP_2s (cm_ctx.match));
635         return cm_ctx.match;
636       }
637       if (cm_ctx.match->entries_length == i + 1)
638       {
639         /* Existing path ends in the middle of new path, extend it! */
640         LOG (GNUNET_ERROR_TYPE_DEBUG,
641              "Extending existing path %s to create inverse for incoming connection\n",
642              GCPP_2s (cm_ctx.match));
643         extend_path (cm_ctx.match,
644                      &cpath[i + 1],
645                      path_length - i - 1,
646                      GNUNET_YES);
647         /* Check that extension was successful */
648         GNUNET_assert (cm_ctx.match->entries_length == path_length);
649         return cm_ctx.match;
650       }
651       /* Eh, we found a match but couldn't use it? Something is wrong. */
652       GNUNET_break (0);
653     }
654   }
655
656   /* No match at all, create completely new path */
657   path = GNUNET_new (struct CadetPeerPath);
658   path->entries_length = path_length;
659   path->entries = GNUNET_new_array (path->entries_length,
660                                     struct CadetPeerPathEntry *);
661   for (int i=path_length-1;i>=0;i--)
662   {
663     struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
664
665     path->entries[i] = entry;
666     entry->peer = cpath[i];
667     entry->path = path;
668   }
669   for (int i=path_length-1;i>=0;i--)
670   {
671     struct CadetPeerPathEntry *entry = path->entries[i];
672
673     GCP_path_entry_add (entry->peer,
674                         entry,
675                         i);
676   }
677   recalculate_path_desirability (path);
678   LOG (GNUNET_ERROR_TYPE_DEBUG,
679        "Created new path %s to create inverse for incoming connection\n",
680        GCPP_2s (path));
681   path->hn = GCP_attach_path (cpath[path_length - 1],
682                               path,
683                               path_length - 1,
684                               GNUNET_YES);
685   return path;
686 }
687
688
689 /**
690  * Return the length of the path.  Excludes one end of the
691  * path, so the loopback path has length 0.
692  *
693  * @param path path to return the length for
694  * @return number of peers on the path
695  */
696 unsigned int
697 GCPP_get_length (struct CadetPeerPath *path)
698 {
699   return path->entries_length;
700 }
701
702
703 /**
704  * Find peer's offset on path.
705  *
706  * @param path path to search
707  * @param cp peer to look for
708  * @return offset of @a cp on @a path, or UINT_MAX if not found
709  */
710 unsigned int
711 GCPP_find_peer (struct CadetPeerPath *path,
712                 struct CadetPeer *cp)
713 {
714   for (unsigned int off = 0;
715        off < path->entries_length;
716        off++)
717     if (cp == GCPP_get_peer_at_offset (path,
718                                        off))
719       return off;
720   return UINT_MAX;
721 }
722
723
724 /**
725  * Obtain the peer at offset @a off in @a path.
726  *
727  * @param path peer path to inspect
728  * @param off offset to return, must be smaller than path length
729  * @return the peer at offset @a off
730  */
731 struct CadetPeer *
732 GCPP_get_peer_at_offset (struct CadetPeerPath *path,
733                          unsigned int off)
734 {
735   GNUNET_assert (off < path->entries_length);
736   return path->entries[off]->peer;
737 }
738
739
740 /**
741  * Convert a path to a human-readable string.
742  *
743  * @param path path to convert
744  * @return string, to be freed by caller (unlike other *_2s APIs!)
745  */
746 const char *
747 GCPP_2s (struct CadetPeerPath *path)
748 {
749   static char buf[2048];
750   size_t off;
751   const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
752
753   off = 0;
754   for (unsigned int i = 0;
755        i < path->entries_length;
756        i++)
757   {
758     if ( (path->entries_length > max_plen) &&
759          (i == max_plen / 2) )
760       off += GNUNET_snprintf (&buf[off],
761                               sizeof (buf) - off,
762                               "...-");
763     if ( (path->entries_length > max_plen) &&
764          (i > max_plen / 2) &&
765          (i < path->entries_length - max_plen / 2) )
766       continue;
767     off += GNUNET_snprintf (&buf[off],
768                             sizeof (buf) - off,
769                             "%s%s",
770                             GNUNET_i2s (GCP_get_id (GCPP_get_peer_at_offset (path,
771                                                                              i))),
772                             (i == path->entries_length -1) ? "" : "-");
773   }
774   GNUNET_snprintf (&buf[off],
775                    sizeof (buf) - off,
776                    "(%p)",
777                    path);
778   return buf;
779 }
780
781
782 /* end of gnunet-service-cadet-new_paths.c */