GNUnet 0.27.0
 
Loading...
Searching...
No Matches
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 "gnunet_pils_service.h"
27#include "platform.h"
32
33
34#define LOG(level, ...) GNUNET_log_from (level, "cadet-pat", __VA_ARGS__)
35
36
65
66
72static void
74{
75 double result = 0.0;
76
77 for (unsigned int i = 0; i < path->entries_length; i++)
78 {
79 struct CadetPeer *cp = path->entries[i]->peer;
80
82 i);
83 }
85}
86
87
103{
104 return path->desirability;
105}
106
107
118struct CadetConnection *
120 struct CadetPeer *destination,
121 unsigned int off)
122{
123 struct CadetPeerPathEntry *entry;
124
125 GNUNET_assert (off < path->entries_length);
126 entry = path->entries[off];
127 GNUNET_assert (entry->peer == destination);
128 return entry->cc;
129}
130
131
140void
142 unsigned int off,
143 struct CadetConnection *cc)
144{
145 struct CadetPeerPathEntry *entry;
146
148 "Adding %s to path %s at offset %u\n",
149 GCC_2s (cc),
150 GCPP_2s (path),
151 off);
152 GNUNET_assert (off < path->entries_length);
153 entry = path->entries[off];
154 GNUNET_assert (NULL == entry->cc);
155 GNUNET_assert (NULL != cc);
156 entry->cc = cc;
157}
158
159
168void
170 unsigned int off,
171 struct CadetConnection *cc)
172{
173 struct CadetPeerPathEntry *entry;
174
176 "Removing connection %s to path %s at offset %u\n",
177 GCC_2s (cc),
178 GCPP_2s (path),
179 off);
180 GNUNET_assert (off < path->entries_length);
181 entry = path->entries[off];
182 GNUNET_assert (cc == entry->cc);
183 entry->cc = NULL;
184}
185
186
196static void
197attach_path (struct CadetPeerPath *path, unsigned int stop_at)
198{
199 GNUNET_assert (NULL == path->hn);
200
201 /* Try to attach this path to a peer, working backwards from the end. */
202 while (path->entries_length > stop_at)
203 {
204 unsigned int end = path->entries_length - 1;
205 struct CadetPeerPathEntry *entry = path->entries[end];
206 int force = GNUNET_NO;
207
209 /* If the entry already has a connection using it, force attach. */
210 if (NULL != entry->cc)
211 force = GNUNET_YES;
212 path->hn = GCP_attach_path (entry->peer,
213 path,
214 end,
215 force);
216 if (NULL != path->hn)
217 break;
218
219 /* Attach failed, trim this entry from the path. */
220 GNUNET_assert (NULL == entry->cc);
222 entry,
223 end);
224 GNUNET_free (entry);
225 path->entries[end] = NULL;
227 }
228
229 /* Shrink array to actual path length. */
233}
234
235
243void
245{
246 struct CadetPeerPathEntry *entry;
247
249 "Owner releases path %s\n",
250 GCPP_2s (path));
251 path->hn = NULL;
252 entry = path->entries[path->entries_length - 1];
253 GNUNET_assert (path == entry->path);
254 GNUNET_assert (NULL == entry->cc);
255 /* cut 'off' end of path */
257 entry,
258 path->entries_length - 1);
259 GNUNET_free (entry);
260 path->entries[path->entries_length - 1] = NULL;
262 /* see if new peer at the end likes this path any better */
263 attach_path (path, 0);
264 if (NULL == path->hn)
265 {
266 /* nobody wants us, discard the path */
268 GNUNET_assert (NULL == path->entries);
270 }
271}
272
273
282static void
284 unsigned int off,
285 int delta)
286{
287 struct CadetPeerPathEntry *entry;
288
289 GNUNET_assert (off < path->entries_length);
290 entry = path->entries[off];
291
292 /* Add delta, with checks for overflows */
293 if (delta >= 0)
294 {
295 if (delta + entry->score < entry->score)
296 entry->score = INT_MAX;
297 else
298 entry->score += delta;
299 }
300 else
301 {
302 if (delta + entry->score > entry->score)
303 entry->score = INT_MIN;
304 else
305 entry->score += delta;
306 }
308}
309
310
315{
320
324 struct CadetPeer **cpath;
325
329 unsigned int cpath_length;
330};
331
332
343static int
344check_match (void *cls,
345 struct CadetPeerPath *path,
346 unsigned int off)
347{
348 struct CheckMatchContext *cm_ctx = cls;
349
350 GNUNET_assert (path->entries_length > off);
351 if ((path->entries_length != off + 1) &&
352 (off + 1 != cm_ctx->cpath_length))
353 {
355 "check_match mismatch because path %s is too long (%u vs. %u vs. %u)\n",
356 GCPP_2s (path),
357 path->entries_length,
358 off + 1,
359 cm_ctx->cpath_length);
360 return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
361 }
362 for (unsigned int i = 0; i < off; i++)
363 if (cm_ctx->cpath[i] !=
365 i))
366 {
368 "check_match path %s mismatches at offset %u\n",
369 GCPP_2s (path),
370 i);
371 return GNUNET_YES; /* mismatch, ignore */
372 }
374 "check_match found match with path %s\n",
375 GCPP_2s (path));
376 cm_ctx->match = path;
377 return GNUNET_NO; /* match, we are done! */
378}
379
380
391static void
393 struct CadetPeer **peers_ext,
394 unsigned int num_peers,
395 int force)
396{
397 unsigned int old_len = path->entries_length;
398 int i;
399
400 /* Expand path */
402 path->entries_length,
403 old_len + num_peers);
404 for (i = num_peers - 1; i >= 0; i--)
405 {
406 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
407
408 path->entries[old_len + i] = entry;
409 entry->peer = peers_ext[i];
410 entry->path = path;
411 }
412 for (i = num_peers - 1; i >= 0; i--)
413 {
414 struct CadetPeerPathEntry *entry = path->entries[old_len + i];
415
416 GCP_path_entry_add (entry->peer,
417 entry,
418 old_len + i);
419 }
420
421 /* If we extend an existing path, detach it from the
422 old owner and re-attach to the new one */
423 GCP_detach_path (path->entries[old_len - 1]->peer,
424 path,
425 path->hn);
426 path->hn = NULL;
427 path->entries_length = old_len + num_peers;
428 if (GNUNET_YES == force)
429 {
430 int end = path->entries_length - 1;
431
433 path,
434 end,
435 GNUNET_YES);
436 }
437 else
438 {
439 attach_path (path, old_len);
440 }
441 if (NULL == path->hn)
442 {
443 /* none of the peers is interested in this path;
444 re-attach. */
445 GNUNET_assert (old_len == path->entries_length);
446 path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
447 path,
448 old_len - 1,
449 GNUNET_YES);
450 GNUNET_assert (NULL != path->hn);
451 return;
452 }
454 "Extended path %s\n",
455 GCPP_2s (path));
456}
457
458
471void
473 unsigned int get_path_length,
474 const struct GNUNET_DHT_PathElement *put_path,
475 unsigned int put_path_length)
476{
477 const struct GNUNET_PeerIdentity *my_identity;
478 struct CadetPeer *cpath[get_path_length + put_path_length];
479 struct CheckMatchContext cm_ctx;
480 struct CadetPeerPath *path;
481 unsigned int skip;
482 unsigned int total_len;
483
485
486 /* precompute 'cpath' so we can avoid doing the lookups lots of times */
487 skip = 0;
488 memset (cpath,
489 0,
490 sizeof(cpath)); /* Just to trigger harder errors later. */
491 total_len = get_path_length + put_path_length;
492 for (unsigned int off = 0; off < total_len; off++)
493 {
494 const struct GNUNET_PeerIdentity *pid;
495
496 pid = (off < get_path_length)
497 ? &get_path[get_path_length - off - 1].pred
498 : &put_path[get_path_length + put_path_length - off - 1].pred;
499 /* Check that I am not in the path */
500 if (0 == GNUNET_memcmp (my_identity, pid))
501 {
502 skip = off + 1;
503 continue;
504 }
505 cpath[off - skip] = GCP_get (pid,
506 GNUNET_YES);
507 /* Check that no peer is twice on the path */
508 for (unsigned int i = 0; i < off - skip; i++)
509 {
510 if (cpath[i] == cpath[off - skip])
511 {
512 skip = off - i;
513 break;
514 }
515 }
516 }
517 if (skip >= total_len)
518 {
520 "Path discovered from DHT is one big cycle?\n");
521 return;
522 }
523 total_len -= skip;
524
525 /* First figure out if this path is a subset of an existing path, an
526 extension of an existing path, or a new path. */
527 cm_ctx.cpath_length = total_len;
528 cm_ctx.cpath = cpath;
529 cm_ctx.match = NULL;
530 for (int i = total_len - 1; i >= 0; i--)
531 {
532 GCP_iterate_paths_at (cpath[i],
533 (unsigned int) i,
535 &cm_ctx);
536 if (NULL != cm_ctx.match)
537 {
538 if (i == total_len - 1)
539 {
540 /* Existing path includes this one, nothing to do! */
542 "Path discovered from DHT is already known\n");
543 return;
544 }
545 if (cm_ctx.match->entries_length == i + 1)
546 {
547 /* Existing path ends in the middle of new path, extend it! */
549 "Trying to extend existing path %s by additional links discovered from DHT\n",
550 GCPP_2s (cm_ctx.match));
551 extend_path (cm_ctx.match,
552 &cpath[i + 1],
553 total_len - i - 1,
554 GNUNET_NO);
555 return;
556 }
557 }
558 }
559
560 /* No match at all, create completely new path */
561 path = GNUNET_new (struct CadetPeerPath);
562 path->entries_length = total_len;
564 struct CadetPeerPathEntry *);
565 for (int i = path->entries_length - 1; i >= 0; i--)
566 {
567 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
568
569 path->entries[i] = entry;
570 entry->peer = cpath[i];
571 entry->path = path;
572 }
573 for (int i = path->entries_length - 1; i >= 0; i--)
574 {
575 struct CadetPeerPathEntry *entry = path->entries[i];
576
577 GCP_path_entry_add (entry->peer,
578 entry,
579 i);
580 }
581
582 /* Finally, try to attach it */
583 attach_path (path, 0);
584 if (NULL == path->hn)
585 {
586 /* None of the peers on the path care about it. */
588 "Path discovered from DHT is not interesting to us\n");
590 GNUNET_assert (NULL == path->entries);
592 return;
593 }
595 "Created new path %s based on information from DHT\n",
596 GCPP_2s (path));
597}
598
599
600struct CadetPeerPath *
601GCPP_get_path_from_route (unsigned int path_length,
602 const struct GNUNET_PeerIdentity *pids)
603{
604 struct CheckMatchContext cm_ctx;
605 struct CadetPeer *cpath[path_length];
606 struct CadetPeerPath *path;
607
608 /* precompute inverted 'cpath' so we can avoid doing the lookups and
609 have the correct order */
610 for (unsigned int off = 0; off < path_length; off++)
611 cpath[off] = GCP_get (&pids[path_length - 1 - off],
612 GNUNET_YES);
613
614 /* First figure out if this path is a subset of an existing path, an
615 extension of an existing path, or a new path. */
616 cm_ctx.cpath = cpath;
617 cm_ctx.cpath_length = path_length;
618 cm_ctx.match = NULL;
619 for (int i = path_length - 1; i >= 0; i--)
620 {
621 GCP_iterate_paths_at (cpath[i],
622 (unsigned int) i,
624 &cm_ctx);
625 if (NULL != cm_ctx.match)
626 {
627 if (i == path_length - 1)
628 {
629 /* Existing path includes this one, return the match! */
631 "Returning existing path %s as inverse for incoming connection\n",
632 GCPP_2s (cm_ctx.match));
633 return cm_ctx.match;
634 }
635 if (cm_ctx.match->entries_length == i + 1)
636 {
637 /* Existing path ends in the middle of new path, extend it! */
639 "Extending existing path %s to create inverse for incoming connection\n",
640 GCPP_2s (cm_ctx.match));
641 extend_path (cm_ctx.match,
642 &cpath[i + 1],
643 path_length - i - 1,
644 GNUNET_YES);
645 /* Check that extension was successful */
646 GNUNET_assert (cm_ctx.match->entries_length == path_length);
647 return cm_ctx.match;
648 }
649 /* Eh, we found a match but couldn't use it? Something is wrong. */
650 GNUNET_break (0);
651 }
652 }
653
654 /* No match at all, create completely new path */
655 path = GNUNET_new (struct CadetPeerPath);
656 path->entries_length = path_length;
658 struct CadetPeerPathEntry *);
659 for (int i = path_length - 1; i >= 0; i--)
660 {
661 struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
662
663 path->entries[i] = entry;
664 entry->peer = cpath[i];
665 entry->path = path;
666 }
667 for (int i = path_length - 1; i >= 0; i--)
668 {
669 struct CadetPeerPathEntry *entry = path->entries[i];
670
671 GCP_path_entry_add (entry->peer,
672 entry,
673 i);
674 }
677 "Created new path %s to create inverse for incoming connection\n",
678 GCPP_2s (path));
679 path->hn = GCP_attach_path (cpath[path_length - 1],
680 path,
681 path_length - 1,
682 GNUNET_YES);
683 return path;
684}
685
686
694unsigned int
696{
697 return path->entries_length;
698}
699
700
708unsigned int
710 struct CadetPeer *cp)
711{
712 for (unsigned int off = 0;
713 off < path->entries_length;
714 off++)
715 if (cp == GCPP_get_peer_at_offset (path,
716 off))
717 return off;
718 return UINT_MAX;
719}
720
721
722struct CadetPeer *
724 unsigned int off)
725{
726 GNUNET_assert (off < path->entries_length);
727 return path->entries[off]->peer;
728}
729
730
737const char *
738GCPP_2s (struct CadetPeerPath *path)
739{
740 static char buf[2048];
741 size_t off;
742 const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
743
744 off = 0;
745 for (unsigned int i = 0;
746 i < path->entries_length;
747 i++)
748 {
749 if ((path->entries_length > max_plen) &&
750 (i == max_plen / 2))
751 off += GNUNET_snprintf (&buf[off],
752 sizeof(buf) - off,
753 "...-");
754 if ((path->entries_length > max_plen) &&
755 (i > max_plen / 2) &&
756 (i < path->entries_length - max_plen / 2))
757 continue;
758 off += GNUNET_snprintf (&buf[off],
759 sizeof(buf) - off,
760 "%s%s",
762 path,
763 i))),
764 (i == path->entries_length - 1) ? "" : "-");
765 }
766 GNUNET_snprintf (&buf[off],
767 sizeof(buf) - off,
768 "(%p)",
769 path);
770 return buf;
771}
772
773
774/* 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_PILS_Handle * pils
Handle to PILS.
Definition gnunet-pils.c:44
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 my_identity
Identity of this peer.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static unsigned int num_peers
Number of peers.
const struct GNUNET_PeerIdentity * GNUNET_PILS_get_identity(const struct GNUNET_PILS_Handle *handle)
Return the current peer identity of a given handle.
Definition pils_api.c:727
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,...
struct GNUNET_PeerIdentity pred
Previous peer on the path (matches "pred" in the signed field).
The identity of the host (wraps the signing key of the peer).