GNUnet 0.22.2
gnunet-service-cadet_paths.c
Go to the documentation of this file.
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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
26#include "platform.h"
31
32
33#define LOG(level, ...) GNUNET_log_from (level, "cadet-pat", __VA_ARGS__)
34
35
40{
46
52
58
62 unsigned int entries_length;
63};
64
65
71static void
73{
74 double result = 0.0;
75
76 for (unsigned int i = 0; i < path->entries_length; i++)
77 {
78 struct CadetPeer *cp = path->entries[i]->peer;
79
81 i);
82 }
84}
85
86
102{
103 return path->desirability;
104}
105
106
117struct CadetConnection *
119 struct CadetPeer *destination,
120 unsigned int off)
121{
122 struct CadetPeerPathEntry *entry;
123
124 GNUNET_assert (off < path->entries_length);
125 entry = path->entries[off];
126 GNUNET_assert (entry->peer == destination);
127 return entry->cc;
128}
129
130
139void
141 unsigned int off,
142 struct CadetConnection *cc)
143{
144 struct CadetPeerPathEntry *entry;
145
147 "Adding %s to path %s at offset %u\n",
148 GCC_2s (cc),
149 GCPP_2s (path),
150 off);
151 GNUNET_assert (off < path->entries_length);
152 entry = path->entries[off];
153 GNUNET_assert (NULL == entry->cc);
154 GNUNET_assert (NULL != cc);
155 entry->cc = cc;
156}
157
158
167void
169 unsigned int off,
170 struct CadetConnection *cc)
171{
172 struct CadetPeerPathEntry *entry;
173
175 "Removing connection %s to path %s at offset %u\n",
176 GCC_2s (cc),
177 GCPP_2s (path),
178 off);
179 GNUNET_assert (off < path->entries_length);
180 entry = path->entries[off];
181 GNUNET_assert (cc == entry->cc);
182 entry->cc = NULL;
183}
184
185
195static void
196attach_path (struct CadetPeerPath *path, unsigned int stop_at)
197{
198 GNUNET_assert (NULL == path->hn);
199
200 /* Try to attach this path to a peer, working backwards from the end. */
201 while (path->entries_length > stop_at)
202 {
203 unsigned int end = path->entries_length - 1;
204 struct CadetPeerPathEntry *entry = path->entries[end];
205 int force = GNUNET_NO;
206
208 /* If the entry already has a connection using it, force attach. */
209 if (NULL != entry->cc)
210 force = GNUNET_YES;
211 path->hn = GCP_attach_path (entry->peer,
212 path,
213 end,
214 force);
215 if (NULL != path->hn)
216 break;
217
218 /* Attach failed, trim this entry from the path. */
219 GNUNET_assert (NULL == entry->cc);
221 entry,
222 end);
223 GNUNET_free (entry);
224 path->entries[end] = NULL;
226 }
227
228 /* Shrink array to actual path length. */
232}
233
234
242void
244{
245 struct CadetPeerPathEntry *entry;
246
248 "Owner releases path %s\n",
249 GCPP_2s (path));
250 path->hn = NULL;
251 entry = path->entries[path->entries_length - 1];
252 GNUNET_assert (path == entry->path);
253 GNUNET_assert (NULL == entry->cc);
254 /* cut 'off' end of path */
256 entry,
257 path->entries_length - 1);
258 GNUNET_free (entry);
259 path->entries[path->entries_length - 1] = NULL;
261 /* see if new peer at the end likes this path any better */
262 attach_path (path, 0);
263 if (NULL == path->hn)
264 {
265 /* nobody wants us, discard the path */
267 GNUNET_assert (NULL == path->entries);
269 }
270}
271
272
281static void
283 unsigned int off,
284 int delta)
285{
286 struct CadetPeerPathEntry *entry;
287
288 GNUNET_assert (off < path->entries_length);
289 entry = path->entries[off];
290
291 /* Add delta, with checks for overflows */
292 if (delta >= 0)
293 {
294 if (delta + entry->score < entry->score)
295 entry->score = INT_MAX;
296 else
297 entry->score += delta;
298 }
299 else
300 {
301 if (delta + entry->score > entry->score)
302 entry->score = INT_MIN;
303 else
304 entry->score += delta;
305 }
307}
308
309
314{
319
323 struct CadetPeer **cpath;
324
328 unsigned int cpath_length;
329};
330
331
342static int
343check_match (void *cls,
344 struct CadetPeerPath *path,
345 unsigned int off)
346{
347 struct CheckMatchContext *cm_ctx = cls;
348
349 GNUNET_assert (path->entries_length > off);
350 if ((path->entries_length != off + 1) &&
351 (off + 1 != cm_ctx->cpath_length))
352 {
354 "check_match mismatch because path %s is too long (%u vs. %u vs. %u)\n",
355 GCPP_2s (path),
356 path->entries_length,
357 off + 1,
358 cm_ctx->cpath_length);
359 return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
360 }
361 for (unsigned int i = 0; i < off; i++)
362 if (cm_ctx->cpath[i] !=
364 i))
365 {
367 "check_match path %s mismatches at offset %u\n",
368 GCPP_2s (path),
369 i);
370 return GNUNET_YES; /* mismatch, ignore */
371 }
373 "check_match found match with path %s\n",
374 GCPP_2s (path));
375 cm_ctx->match = path;
376 return GNUNET_NO; /* match, we are done! */
377}
378
379
390static void
392 struct CadetPeer **peers_ext,
393 unsigned int num_peers,
394 int force)
395{
396 unsigned int old_len = path->entries_length;
397 int i;
398
399 /* Expand path */
401 path->entries_length,
402 old_len + num_peers);
403 for (i = num_peers - 1; i >= 0; i--)
404 {
405 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
406
407 path->entries[old_len + i] = entry;
408 entry->peer = peers_ext[i];
409 entry->path = path;
410 }
411 for (i = num_peers - 1; i >= 0; i--)
412 {
413 struct CadetPeerPathEntry *entry = path->entries[old_len + i];
414
415 GCP_path_entry_add (entry->peer,
416 entry,
417 old_len + i);
418 }
419
420 /* If we extend an existing path, detach it from the
421 old owner and re-attach to the new one */
422 GCP_detach_path (path->entries[old_len - 1]->peer,
423 path,
424 path->hn);
425 path->hn = NULL;
426 path->entries_length = old_len + num_peers;
427 if (GNUNET_YES == force)
428 {
429 int end = path->entries_length - 1;
430
432 path,
433 end,
434 GNUNET_YES);
435 }
436 else
437 {
438 attach_path (path, old_len);
439 }
440 if (NULL == path->hn)
441 {
442 /* none of the peers is interested in this path;
443 re-attach. */
444 GNUNET_assert (old_len == path->entries_length);
445 path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
446 path,
447 old_len - 1,
448 GNUNET_YES);
449 GNUNET_assert (NULL != path->hn);
450 return;
451 }
453 "Extended path %s\n",
454 GCPP_2s (path));
455}
456
457
470void
472 unsigned int get_path_length,
473 const struct GNUNET_DHT_PathElement *put_path,
474 unsigned int put_path_length)
475{
476 struct CadetPeer *cpath[get_path_length + put_path_length];
477 struct CheckMatchContext cm_ctx;
478 struct CadetPeerPath *path;
479 unsigned int skip;
480 unsigned int total_len;
481
482 /* precompute 'cpath' so we can avoid doing the lookups lots of times */
483 skip = 0;
484 memset (cpath,
485 0,
486 sizeof(cpath)); /* Just to trigger harder errors later. */
487 total_len = get_path_length + put_path_length;
488 for (unsigned int off = 0; off < total_len; off++)
489 {
490 const struct GNUNET_PeerIdentity *pid;
491
492 pid = (off < get_path_length)
493 ? &get_path[get_path_length - off - 1].pred
494 : &put_path[get_path_length + put_path_length - off - 1].pred;
495 /* Check that I am not in the path */
496 if (0 == GNUNET_memcmp (&my_full_id,
497 pid))
498 {
499 skip = off + 1;
500 continue;
501 }
502 cpath[off - skip] = GCP_get (pid,
503 GNUNET_YES);
504 /* Check that no peer is twice on the path */
505 for (unsigned int i = 0; i < off - skip; i++)
506 {
507 if (cpath[i] == cpath[off - skip])
508 {
509 skip = off - i;
510 break;
511 }
512 }
513 }
514 if (skip >= total_len)
515 {
517 "Path discovered from DHT is one big cycle?\n");
518 return;
519 }
520 total_len -= skip;
521
522 /* First figure out if this path is a subset of an existing path, an
523 extension of an existing path, or a new path. */
524 cm_ctx.cpath_length = total_len;
525 cm_ctx.cpath = cpath;
526 cm_ctx.match = NULL;
527 for (int i = total_len - 1; i >= 0; i--)
528 {
529 GCP_iterate_paths_at (cpath[i],
530 (unsigned int) i,
532 &cm_ctx);
533 if (NULL != cm_ctx.match)
534 {
535 if (i == total_len - 1)
536 {
537 /* Existing path includes this one, nothing to do! */
539 "Path discovered from DHT is already known\n");
540 return;
541 }
542 if (cm_ctx.match->entries_length == i + 1)
543 {
544 /* Existing path ends in the middle of new path, extend it! */
546 "Trying to extend existing path %s by additional links discovered from DHT\n",
547 GCPP_2s (cm_ctx.match));
548 extend_path (cm_ctx.match,
549 &cpath[i + 1],
550 total_len - i - 1,
551 GNUNET_NO);
552 return;
553 }
554 }
555 }
556
557 /* No match at all, create completely new path */
558 path = GNUNET_new (struct CadetPeerPath);
559 path->entries_length = total_len;
561 struct CadetPeerPathEntry *);
562 for (int i = path->entries_length - 1; i >= 0; i--)
563 {
564 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
565
566 path->entries[i] = entry;
567 entry->peer = cpath[i];
568 entry->path = path;
569 }
570 for (int i = path->entries_length - 1; i >= 0; i--)
571 {
572 struct CadetPeerPathEntry *entry = path->entries[i];
573
574 GCP_path_entry_add (entry->peer,
575 entry,
576 i);
577 }
578
579 /* Finally, try to attach it */
580 attach_path (path, 0);
581 if (NULL == path->hn)
582 {
583 /* None of the peers on the path care about it. */
585 "Path discovered from DHT is not interesting to us\n");
587 GNUNET_assert (NULL == path->entries);
589 return;
590 }
592 "Created new path %s based on information from DHT\n",
593 GCPP_2s (path));
594}
595
596
597struct CadetPeerPath *
598GCPP_get_path_from_route (unsigned int path_length,
599 const struct GNUNET_PeerIdentity *pids)
600{
601 struct CheckMatchContext cm_ctx;
602 struct CadetPeer *cpath[path_length];
603 struct CadetPeerPath *path;
604
605 /* precompute inverted 'cpath' so we can avoid doing the lookups and
606 have the correct order */
607 for (unsigned int off = 0; off < path_length; off++)
608 cpath[off] = GCP_get (&pids[path_length - 1 - off],
609 GNUNET_YES);
610
611 /* First figure out if this path is a subset of an existing path, an
612 extension of an existing path, or a new path. */
613 cm_ctx.cpath = cpath;
614 cm_ctx.cpath_length = path_length;
615 cm_ctx.match = NULL;
616 for (int i = path_length - 1; i >= 0; i--)
617 {
618 GCP_iterate_paths_at (cpath[i],
619 (unsigned int) i,
621 &cm_ctx);
622 if (NULL != cm_ctx.match)
623 {
624 if (i == path_length - 1)
625 {
626 /* Existing path includes this one, return the match! */
628 "Returning existing path %s as inverse for incoming connection\n",
629 GCPP_2s (cm_ctx.match));
630 return cm_ctx.match;
631 }
632 if (cm_ctx.match->entries_length == i + 1)
633 {
634 /* Existing path ends in the middle of new path, extend it! */
636 "Extending existing path %s to create inverse for incoming connection\n",
637 GCPP_2s (cm_ctx.match));
638 extend_path (cm_ctx.match,
639 &cpath[i + 1],
640 path_length - i - 1,
641 GNUNET_YES);
642 /* Check that extension was successful */
643 GNUNET_assert (cm_ctx.match->entries_length == path_length);
644 return cm_ctx.match;
645 }
646 /* Eh, we found a match but couldn't use it? Something is wrong. */
647 GNUNET_break (0);
648 }
649 }
650
651 /* No match at all, create completely new path */
652 path = GNUNET_new (struct CadetPeerPath);
653 path->entries_length = path_length;
655 struct CadetPeerPathEntry *);
656 for (int i = path_length - 1; i >= 0; i--)
657 {
658 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
659
660 path->entries[i] = entry;
661 entry->peer = cpath[i];
662 entry->path = path;
663 }
664 for (int i = path_length - 1; i >= 0; i--)
665 {
666 struct CadetPeerPathEntry *entry = path->entries[i];
667
668 GCP_path_entry_add (entry->peer,
669 entry,
670 i);
671 }
674 "Created new path %s to create inverse for incoming connection\n",
675 GCPP_2s (path));
676 path->hn = GCP_attach_path (cpath[path_length - 1],
677 path,
678 path_length - 1,
679 GNUNET_YES);
680 return path;
681}
682
683
691unsigned int
693{
694 return path->entries_length;
695}
696
697
705unsigned int
707 struct CadetPeer *cp)
708{
709 for (unsigned int off = 0;
710 off < path->entries_length;
711 off++)
712 if (cp == GCPP_get_peer_at_offset (path,
713 off))
714 return off;
715 return UINT_MAX;
716}
717
718
719struct CadetPeer *
721 unsigned int off)
722{
723 GNUNET_assert (off < path->entries_length);
724 return path->entries[off]->peer;
725}
726
727
734const char *
735GCPP_2s (struct CadetPeerPath *path)
736{
737 static char buf[2048];
738 size_t off;
739 const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
740
741 off = 0;
742 for (unsigned int i = 0;
743 i < path->entries_length;
744 i++)
745 {
746 if ((path->entries_length > max_plen) &&
747 (i == max_plen / 2))
748 off += GNUNET_snprintf (&buf[off],
749 sizeof(buf) - off,
750 "...-");
751 if ((path->entries_length > max_plen) &&
752 (i > max_plen / 2) &&
753 (i < path->entries_length - max_plen / 2))
754 continue;
755 off += GNUNET_snprintf (&buf[off],
756 sizeof(buf) - off,
757 "%s%s",
759 path,
760 i))),
761 (i == path->entries_length - 1) ? "" : "-");
762 }
763 GNUNET_snprintf (&buf[off],
764 sizeof(buf) - off,
765 "(%p)",
766 path);
767 return buf;
768}
769
770
771/* end of gnunet-service-cadet-new_paths.c */
#define INT_MAX
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:33
static struct GNUNET_PeerIdentity my_full_id
Peer identity.
Definition: gnunet-core.c:65
static int result
Global testing status.
const char * GCC_2s(const struct CadetConnection *cc)
Get a (static) string for a connection.
A connection is a live end-to-end messaging mechanism where the peers are identified by a path and kn...
static int check_match(void *cls, struct CadetPeerPath *path, unsigned int off)
Check if the given path is identical on all of the hops until off, and not longer than off.
const char * GCPP_2s(struct CadetPeerPath *path)
Convert a path to a human-readable string.
void GCPP_try_path_from_dht(const struct GNUNET_DHT_PathElement *get_path, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_length)
Create a peer path based on the result of a DHT lookup.
static void GCPP_update_score(struct CadetPeerPath *path, unsigned int off, int delta)
Updates the score for an entry on the path based on our experiences with using path.
unsigned int GCPP_get_length(struct CadetPeerPath *path)
Return the length of the path.
static void attach_path(struct CadetPeerPath *path, unsigned int stop_at)
Tries to attach path to a peer, working backwards from the end and stopping at stop_at.
static void recalculate_path_desirability(struct CadetPeerPath *path)
Calculate the path's desirability score.
struct CadetConnection * GCPP_get_connection(struct CadetPeerPath *path, struct CadetPeer *destination, unsigned int off)
Return connection to destination using path, or return NULL if no such connection exists.
GNUNET_CONTAINER_HeapCostType GCPP_get_desirability(const struct CadetPeerPath *path)
Return how much we like keeping the path.
void GCPP_del_connection(struct CadetPeerPath *path, unsigned int off, struct CadetConnection *cc)
Notify path that it is no longer used for connection cc which ended at the path's offset off.
void GCPP_release(struct CadetPeerPath *path)
The owning peer of this path is no longer interested in maintaining it, so the path should be discard...
static void extend_path(struct CadetPeerPath *path, struct CadetPeer **peers_ext, unsigned int num_peers, int force)
Extend path path by the num_peers from the peers array, assuming the owners past the current owner wa...
#define LOG(level,...)
void GCPP_add_connection(struct CadetPeerPath *path, unsigned int off, struct CadetConnection *cc)
Notify path that it is used for connection cc which ends at the path's offset off.
struct CadetPeer * GCPP_get_peer_at_offset(struct CadetPeerPath *path, unsigned int off)
Obtain the peer at offset off in path.
struct CadetPeerPath * GCPP_get_path_from_route(unsigned int path_length, const struct GNUNET_PeerIdentity *pids)
We got an incoming connection, obtain the corresponding path.
unsigned int GCPP_find_peer(struct CadetPeerPath *path, struct CadetPeer *cp)
Find peer's offset on path.
const struct GNUNET_PeerIdentity * GCP_get_id(struct CadetPeer *cp)
Obtain the peer identity for a struct CadetPeer.
void GCP_detach_path(struct CadetPeer *cp, struct CadetPeerPath *path, struct GNUNET_CONTAINER_HeapNode *hn)
This peer can no longer own path as the path has been extended and a peer further down the line is no...
void GCP_path_entry_add(struct CadetPeer *cp, struct CadetPeerPathEntry *entry, unsigned int off)
Add an entry to the DLL of all of the paths that this peer is on.
struct CadetPeer * GCP_get(const struct GNUNET_PeerIdentity *peer_id, int create)
Retrieve the CadetPeer structure associated with the peer.
void GCP_path_entry_remove(struct CadetPeer *cp, struct CadetPeerPathEntry *entry, unsigned int off)
Remove an entry from the DLL of all of the paths that this peer is on.
struct GNUNET_CONTAINER_HeapNode * GCP_attach_path(struct CadetPeer *cp, struct CadetPeerPath *path, unsigned int off, int force)
Try adding a path to this cp.
unsigned int GCP_iterate_paths_at(struct CadetPeer *cp, unsigned int dist, GCP_PathIterator callback, void *callback_cls)
Iterate over the paths to peer where peer is at distance dist from us.
double GCP_get_desirability_of_path(struct CadetPeer *cp, unsigned int off)
Calculate how desirable a path is for cp if cp is at offset off in the path.
Information we track per peer.
Information we track per tunnel.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static unsigned int num_peers
Number of peers.
uint64_t GNUNET_CONTAINER_HeapCostType
Cost by which elements in a heap can be ordered.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
@ GNUNET_YES
@ GNUNET_NO
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
Low-level connection to a destination.
struct CadetPeerPath * path
Path we are using to our destination.
unsigned int off
Offset of our destination in path.
struct CadetPeer * destination
To which peer does this connection go?
Entry in a peer path.
int score
Path's historic score up to this point.
struct CadetPeer * peer
The peer at this offset of the path.
struct CadetConnection * cc
Connection using this path, or NULL for none.
struct CadetPeerPath * path
Path this entry belongs to.
Information regarding a possible path to reach a peer.
unsigned int entries_length
Length of the entries array.
struct CadetPeerPathEntry ** entries
Array of all the peers on the path.
GNUNET_CONTAINER_HeapCostType desirability
Desirability of the path.
struct GNUNET_CONTAINER_HeapNode * hn
Node of this path in the owner's heap.
Struct containing all information regarding a given peer.
Closure for #find_peer_at() and check_match().
struct CadetPeerPath * match
Set to a matching path, if any.
unsigned int cpath_length
How long is the cpath array?
struct CadetPeer ** cpath
Array the combined paths.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
The identity of the host (wraps the signing key of the peer).