GNUnet 0.28.0-dev.3-20-gf1136b0b8
 
Loading...
Searching...
No Matches
gnunet-service-dht_neighbours.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2017, 2021-2022, 2026 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 */
20
27#include "gnunet_common.h"
28#include "gnunet_constants.h"
30#include "gnunet_dht_service.h"
31#include "gnunet_protocols.h"
33#include "gnunet_pils_service.h"
34#include "gnunet-service-dht.h"
37#include "dht.h"
38#include "dht_helper.h"
40#include "gnunet_util_lib.h"
41
42#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
43 __VA_ARGS__)
44
56#define SANITY_CHECKS 2
57
61#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
62
66#define DEFAULT_BUCKET_SIZE 8
67
71#define FIND_PEER_REPLICATION_LEVEL 4
72
76#define MAXIMUM_PENDING_PER_PEER 64
77
83#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
84 GNUNET_TIME_UNIT_MINUTES, 2)
85
86
96#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
97 GNUNET_TIME_UNIT_SECONDS, 6)
98
102#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
103
104
106
107
112{
117
122
127
132
137
142
147
152
153 /* trunc_peer (if truncated) */
154
155 /* put path (if tracked) */
156
157 /* get path (if tracked) */
158
159 /* sender_sig (if path tracking is on) */
160
161 /* Payload */
162};
163
164
169{
174
179
184
189
194
199
204
209
210 /* result bloomfilter */
211
212 /* xquery */
213
214};
216
217
221struct PeerInfo;
222
223
227struct Target
228{
232 struct Target *next;
233
237 struct Target *prev;
238
243
248
252 struct PeerInfo *pi;
253
258
262 unsigned int load;
263
269
270};
271
272
277{
282
287
292
296 struct PeerInfo *next;
297
301 struct PeerInfo *prev;
302
306 struct Target *t_head;
307
311 struct Target *t_tail;
312
316 void *hello;
317
322
327};
328
329
334{
338 struct PeerInfo *head;
339
343 struct PeerInfo *tail;
344
348 unsigned int peers_size;
349};
350
351
355static int cache_results;
356
360static unsigned int closest_bucket;
361
366static unsigned int newly_found_peers;
367
372
377
383
387static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
388
393
394
402static void
403send_done_cb (void *cls)
404{
405 struct Target *t = cls;
406 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
407
408 GNUNET_assert (t->load > 0);
409 t->load--;
410 if (0 < t->load)
411 return;
412 if (t->dropped)
413 {
414 GNUNET_free (t);
415 return;
416 }
417 /* move target back to the front */
419 pi->t_tail,
420 t);
422 pi->t_tail,
423 t);
424}
425
426
433static void
434do_send (struct PeerInfo *pi,
435 const struct GNUNET_MessageHeader *msg)
436{
437 struct Target *t;
438
439 for (t = pi->t_head;
440 NULL != t;
441 t = t->next)
442 if (t->load < MAXIMUM_PENDING_PER_PEER)
443 break;
444 if (NULL == t)
445 {
446 /* all targets busy, drop message */
448 "# messages dropped (underlays busy)",
449 1,
450 GNUNET_NO);
451 return;
452 }
453 t->load++;
454 /* rotate busy targets to the end */
455 if (MAXIMUM_PENDING_PER_PEER == t->load)
456 {
458 pi->t_tail,
459 t);
461 pi->t_tail,
462 t);
463 }
464 GDS_u_send (t->u,
465 t->utarget,
466 msg,
467 ntohs (msg->size),
469 t);
470}
471
472
480static int
481find_bucket (const struct GNUNET_HashCode *hc)
482{
483 const struct GNUNET_HashCode *my_identity_hash;
484 struct GNUNET_HashCode xor;
485 unsigned int bits;
486
487 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
488 GNUNET_assert (NULL != my_identity_hash);
489
491 my_identity_hash,
492 &xor);
494 if (bits == MAX_BUCKETS)
495 {
496 /* How can all bits match? Got my own ID? */
497 GNUNET_break (0);
498 return -1;
499 }
500 return MAX_BUCKETS - bits - 1;
501}
502
503
515 const struct GNUNET_PeerIdentity *key,
516 void *value)
517{
518 struct GNUNET_BLOCK_Group *bg = cls;
519 struct PeerInfo *pi = value;
520
522 &pi->phash,
523 1);
525 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
526 GNUNET_i2s (key));
527 return GNUNET_YES;
528}
529
530
538static void
540{
541 (void) cls;
542
543 /* Compute when to do this again (and if we should
544 even send a message right now) */
545 {
546 struct GNUNET_TIME_Relative next_send_time;
547 bool done_early;
548
549 find_peer_task = NULL;
550 done_early = (newly_found_peers > bucket_size);
551 /* schedule next round, taking longer if we found more peers
552 in the last round. */
553 next_send_time.rel_value_us =
558 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
562 GNUNET_SCHEDULER_add_delayed (next_send_time,
564 NULL);
565 if (done_early)
566 return;
567 }
568
569 /* actually send 'find peer' request */
570 {
571 const struct GNUNET_HashCode *my_identity_hash;
572 struct GNUNET_BLOCK_Group *bg;
573 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
574
575 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
576 GNUNET_assert (NULL != my_identity_hash);
577
580 NULL,
581 0,
582 "seen-set-size",
585 NULL);
588 bg);
589 peer_bf
593 if (GNUNET_OK !=
598 0, /* hop count */
599 my_identity_hash,
600 NULL, 0, /* xquery */
601 bg,
602 peer_bf))
603 {
605 "# Failed to initiate FIND PEER lookup",
606 1,
607 GNUNET_NO);
608 }
609 else
610 {
612 "# FIND PEER messages initiated",
613 1,
614 GNUNET_NO);
615 }
618 }
619}
620
621
629static void
630update_hold (struct PeerBucket *bucket)
631{
632 unsigned int off = 0;
633
634 /* find the peer -- we just go over all of them, should
635 be hardly any more expensive than just finding the 'right'
636 one. */
637 for (struct PeerInfo *pos = bucket->head;
638 NULL != pos;
639 pos = pos->next)
640 {
641 if (off > bucket_size)
642 break; /* We only hold up to #bucket_size peers per bucket */
643 off++;
644 for (struct Target *tp = pos->t_head;
645 NULL != tp;
646 tp = tp->next)
647 if (NULL == tp->ph)
648 tp->ph = GDS_u_hold (tp->u,
649 tp->utarget);
650 }
651}
652
653
654void
655GDS_u_connect (void *cls,
656 struct GNUNET_DHTU_Target *target,
657 const struct GNUNET_PeerIdentity *pid,
658 void **ctx)
659{
660 const struct GNUNET_PeerIdentity *my_identity;
661 struct GDS_Underlay *u = cls;
662 struct PeerInfo *pi;
663 struct PeerBucket *bucket;
664 bool do_hold = false;
665
667 GNUNET_assert (NULL != my_identity);
668
669 /* Check for connect to self message */
670 if (0 == GNUNET_memcmp (my_identity, pid))
671 return;
673 "Connected to peer %s\n",
674 GNUNET_i2s (pid));
676 pid);
677 if (NULL == pi)
678 {
680 "# peers connected",
681 1,
682 GNUNET_NO);
683 pi = GNUNET_new (struct PeerInfo);
684 pi->id = *pid;
686 sizeof(*pid),
687 &pi->phash);
688 pi->peer_bucket = find_bucket (&pi->phash);
689 GNUNET_assert ( (pi->peer_bucket >= 0) &&
690 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
691 bucket = &k_buckets[pi->peer_bucket];
693 bucket->tail,
694 pi);
695 bucket->peers_size++;
697 (unsigned int) pi->peer_bucket + 1);
700 &pi->id,
701 pi,
703 if (bucket->peers_size <= bucket_size)
704 {
706 do_hold = true;
707 }
710 {
711 /* got a first connection, good time to start with FIND PEER requests... */
714 NULL);
715 }
716 }
717 {
718 struct Target *t;
719
720 t = GNUNET_new (struct Target);
721 t->u = u;
722 t->utarget = target;
723 t->pi = pi;
725 pi->t_tail,
726 t);
727 *ctx = t;
728
729 }
730 if (do_hold)
731 update_hold (bucket);
732}
733
734
735void
737{
738 struct Target *t = ctx;
739 struct PeerInfo *pi;
740 struct PeerBucket *bucket;
741 bool was_held = false;
742
743 /* Check for disconnect from self message (on shutdown) */
744 if (NULL == t)
745 return;
746 pi = t->pi;
748 pi->t_tail,
749 t);
750 if (NULL != t->ph)
751 {
752 GDS_u_drop (t->u,
753 t->ph);
754 t->ph = NULL;
755 was_held = true;
756 }
757 if (t->load > 0)
758 {
759 t->dropped = true;
760 t->pi = NULL;
761 }
762 else
763 {
764 GNUNET_free (t);
765 }
766 if (NULL != pi->t_head)
767 return; /* got other connections still */
769 "Disconnected from peer %s\n",
770 GNUNET_i2s (&pi->id));
772 "# peers connected",
773 -1,
774 GNUNET_NO);
777 &pi->id,
778 pi));
781 {
783 find_peer_task = NULL;
784 }
785 GNUNET_assert (pi->peer_bucket >= 0);
786 bucket = &k_buckets[pi->peer_bucket];
788 bucket->tail,
789 pi);
790 GNUNET_assert (bucket->peers_size > 0);
791 bucket->peers_size--;
792 if ( (was_held) &&
793 (bucket->peers_size >= bucket_size - 1) )
794 update_hold (bucket);
795 while ( (closest_bucket > 0) &&
798 GNUNET_free (pi->hello);
799 GNUNET_free (pi);
800}
801
802
811static unsigned int
812get_forward_count (uint16_t hop_count,
813 uint16_t target_replication)
814{
815 uint32_t random_value;
816 uint32_t forward_count;
817 float target_value;
818 double rm1;
819
820 if (hop_count > GDS_NSE_get () * 4.0)
821 {
822 /* forcefully terminate */
824 "# requests TTL-dropped",
825 1,
826 GNUNET_NO);
827 return 0;
828 }
829 if (hop_count > GDS_NSE_get () * 2.0)
830 {
831 /* Once we have reached our ideal number of hops, only forward to 1 peer */
832 return 1;
833 }
834 /* bound by system-wide maximum and minimum */
835 if (0 == target_replication)
836 target_replication = 1; /* 0 is verboten */
837 target_replication =
839 target_replication);
840 rm1 = target_replication - 1.0;
841 target_value =
842 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
843
844 /* Set forward count to floor of target_value */
845 forward_count = (uint32_t) target_value;
846 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
847 target_value = target_value - forward_count;
848 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
849 if (random_value < (target_value * UINT32_MAX))
850 forward_count++;
851 return GNUNET_MIN (forward_count,
853}
854
855
868 const struct GNUNET_CONTAINER_BloomFilter *bloom)
869{
870 const struct GNUNET_HashCode *my_identity_hash;
871 int delta;
872 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
873 GNUNET_assert (NULL != my_identity_hash);
874 if (0 == GNUNET_memcmp (my_identity_hash, key))
875 return GNUNET_YES;
876 for (int bucket_num = find_bucket (key);
877 bucket_num < closest_bucket;
878 bucket_num++)
879 {
880 unsigned int count = 0;
881 GNUNET_assert (bucket_num >= 0);
882 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
883 NULL != pos;
884 pos = pos->next)
885 {
886 if (count >= bucket_size)
887 break; /* we only consider first #bucket_size entries per bucket */
888 count++;
889 if ( (NULL != bloom) &&
890 (GNUNET_YES ==
892 &pos->phash)) )
893 continue; /* Ignore filtered peers */
894 /* All peers in this bucket must be closer than us, as
895 they mismatch with our PID on the pivotal bit. So
896 because an unfiltered peer exists, we are not the
897 closest. */
898 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
899 my_identity_hash,
900 key);
901 switch (delta)
902 {
903 case -1: /* pos closer */
904 return GNUNET_NO;
905 case 0: /* identical, impossible! */
906 GNUNET_assert (0);
907 break;
908 case 1: /* I am closer */
909 break;
910 }
911 }
912 }
913 /* No closer (unfiltered) peers found; we must be the closest! */
914 return GNUNET_YES;
915}
916
917
939static struct PeerInfo *
941 const struct GNUNET_CONTAINER_BloomFilter *bloom,
942 uint32_t hops)
943{
944 if (0 == closest_bucket)
945 {
947 "# Peer selection failed",
948 1,
949 GNUNET_NO);
950 return NULL; /* we have zero connections */
951 }
952 if (hops >= GDS_NSE_get ())
953 {
954 /* greedy selection (closest peer that is not in Bloom filter) */
955 struct PeerInfo *chosen = NULL;
956 int best_bucket;
957 int bucket_offset;
958
959 {
960 const struct GNUNET_HashCode *my_identity_hash;
961 struct GNUNET_HashCode xor;
962 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
963 GNUNET_assert (NULL != my_identity_hash);
965 my_identity_hash,
966 &xor);
967 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
968 }
969 if (best_bucket >= closest_bucket)
970 bucket_offset = closest_bucket - 1;
971 else
972 bucket_offset = best_bucket;
973 while (-1 != bucket_offset)
974 {
975 struct PeerBucket *bucket = &k_buckets[bucket_offset];
976 unsigned int count = 0;
977
978 for (struct PeerInfo *pos = bucket->head;
979 NULL != pos;
980 pos = pos->next)
981 {
982 if (count >= bucket_size)
983 break; /* we only consider first #bucket_size entries per bucket */
984 count++;
985 if ( (NULL != bloom) &&
986 (GNUNET_YES ==
988 &pos->phash)) )
989 {
991 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
992 GNUNET_i2s (&pos->id),
993 GNUNET_h2s (key));
994 continue;
995 }
996 if (NULL == chosen)
997 {
998 /* First candidate */
999 chosen = pos;
1000 }
1001 else
1002 {
1003 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1004 &chosen->phash,
1005 key);
1006 switch (delta)
1007 {
1008 case -1: /* pos closer */
1009 chosen = pos;
1010 break;
1011 case 0: /* identical, impossible! */
1012 GNUNET_assert (0);
1013 break;
1014 case 1: /* chosen closer */
1015 break;
1016 }
1017 }
1018 count++;
1019 } /* for all (#bucket_size) peers in bucket */
1020 if (NULL != chosen)
1021 break;
1022
1023 /* If we chose nothing in first iteration, first go through deeper
1024 buckets (best chance to find a good match), and if we still found
1025 nothing, then to shallower buckets. Terminate on any match in the
1026 current bucket, as this search order guarantees that it can only get
1027 worse as we keep going. */
1028 if (bucket_offset > best_bucket)
1029 {
1030 /* Go through more deeper buckets */
1031 bucket_offset++;
1032 if (bucket_offset == closest_bucket)
1033 {
1034 /* Can't go any deeper, if nothing selected,
1035 go for shallower buckets */
1036 bucket_offset = best_bucket - 1;
1037 }
1038 }
1039 else
1040 {
1041 /* We're either at the 'best_bucket' or already moving
1042 on to shallower buckets. */
1043 if (bucket_offset == best_bucket)
1044 bucket_offset++; /* go for deeper buckets */
1045 else
1046 bucket_offset--; /* go for shallower buckets */
1047 }
1048 } /* for applicable buckets (starting at best match) */
1049 if (NULL == chosen)
1050 {
1052 "# Peer selection failed",
1053 1,
1054 GNUNET_NO);
1055 return NULL;
1056 }
1058 "Selected peer `%s' in greedy routing for %s\n",
1059 GNUNET_i2s (&chosen->id),
1060 GNUNET_h2s (key));
1061 return chosen;
1062 } /* end of 'greedy' peer selection */
1063
1064 /* select "random" peer */
1065 /* count number of peers that are available and not filtered,
1066 but limit to at most #bucket_size peers, starting with
1067 those 'furthest' from us. */
1068 {
1069 unsigned int total = 0;
1070 unsigned int selected;
1071
1072 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1073 {
1074 struct PeerBucket *bucket = &k_buckets[bc];
1075 unsigned int count = 0;
1076
1077 for (struct PeerInfo *pos = bucket->head;
1078 NULL != pos;
1079 pos = pos->next)
1080 {
1081 count++;
1082 if (count > bucket_size)
1083 break; /* limits search to #bucket_size peers per bucket */
1084 if ( (NULL != bloom) &&
1085 (GNUNET_YES ==
1087 &pos->phash)) )
1088 {
1090 "Excluded peer `%s' due to BF match in random routing for %s\n",
1091 GNUNET_i2s (&pos->id),
1092 GNUNET_h2s (key));
1093 continue; /* Ignore filtered peers */
1094 }
1095 total++;
1096 } /* for all peers in bucket */
1097 } /* for all buckets */
1098 if (0 == total) /* No peers to select from! */
1099 {
1101 "# Peer selection failed",
1102 1,
1103 GNUNET_NO);
1104 return NULL;
1105 }
1106
1107 /* Now actually choose a peer */
1108 selected = GNUNET_CRYPTO_random_u32 (total);
1109 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1110 {
1111 unsigned int count = 0;
1112
1113 for (struct PeerInfo *pos = k_buckets[bc].head;
1114 pos != NULL;
1115 pos = pos->next)
1116 {
1117 count++;
1118 if (count > bucket_size)
1119 break; /* limits search to #bucket_size peers per bucket */
1120
1121 if ( (NULL != bloom) &&
1122 (GNUNET_YES ==
1124 &pos->phash)) )
1125 continue; /* Ignore bloomfiltered peers */
1126 if (0 == selected--)
1127 {
1129 "Selected peer `%s' in random routing for %s\n",
1130 GNUNET_i2s (&pos->id),
1131 GNUNET_h2s (key));
1132 return pos;
1133 }
1134 } /* for peers in bucket */
1135 } /* for all buckets */
1136 } /* random peer selection scope */
1137 GNUNET_break (0);
1138 return NULL;
1139}
1140
1141
1155static unsigned int
1157 struct GNUNET_CONTAINER_BloomFilter *bloom,
1158 uint16_t hop_count,
1159 uint16_t target_replication,
1160 struct PeerInfo ***targets)
1161{
1162 unsigned int target;
1163 unsigned int off;
1164 struct PeerInfo **rtargets;
1165
1166 GNUNET_assert (NULL != bloom);
1167 target = get_forward_count (hop_count,
1168 target_replication);
1169 if (0 == target)
1170 {
1171 *targets = NULL;
1172 return 0;
1173 }
1174 rtargets = GNUNET_new_array (target,
1175 struct PeerInfo *);
1176 for (off = 0; off < target; off++)
1177 {
1178 struct PeerInfo *nxt;
1179
1180 nxt = select_peer (key,
1181 bloom,
1182 hop_count);
1183 if (NULL == nxt)
1184 break;
1185 rtargets[off] = nxt;
1186 }
1188 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1189 off,
1191 (unsigned int) hop_count,
1192 GNUNET_h2s (key),
1193 target);
1194 if (0 == off)
1195 {
1196 GNUNET_free (rtargets);
1197 *targets = NULL;
1198 return 0;
1199 }
1200 *targets = rtargets;
1202 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1203 GNUNET_h2s (key),
1204 off,
1205 target);
1206 return off;
1207}
1208
1209
1215static void
1217{
1218 struct GNUNET_HELLO_Parser *b;
1219
1221 return;
1222
1224 bd->data_size);
1226 {
1229 NULL);
1230 }
1232}
1233
1234
1236{
1237 unsigned int hop_count;
1238 unsigned int target_count;
1241 unsigned int index;
1242 unsigned int *queued;
1244 void *cb_cls;
1245};
1246
1247
1248static bool
1250 size_t msize,
1251 struct PeerPutMessage *ppm)
1252{
1253 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1254 struct PeerInfo *target;
1255
1256 if (NULL == ppm)
1257 {
1258 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1259 if (*(gds_routing->queued) >= gds_routing->target_count)
1260 {
1261 if (gds_routing->cb)
1262 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1263
1264 GNUNET_free (gds_routing->targets);
1265 GNUNET_free (gds_routing->queued);
1266 }
1267
1268 return true;
1269 }
1270
1271 target = gds_routing->targets[gds_routing->index];
1272
1274 "Routing PUT for %s after %u hops to %s\n",
1275 GNUNET_h2s (&(gds_routing->key)),
1276 (unsigned int) gds_routing->hop_count,
1277 GNUNET_i2s (&target->id));
1278 do_send (target,
1279 &ppm->header);
1280 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1281
1282 if (*(gds_routing->queued) >= gds_routing->target_count)
1283 {
1284 if (gds_routing->cb)
1285 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1286
1287 GNUNET_free (gds_routing->targets);
1289 "# PUT messages queued for transmission",
1290 gds_routing->target_count,
1291 GNUNET_NO);
1292 GNUNET_free (gds_routing->queued);
1293 }
1294
1295 return true;
1296}
1297
1298
1299void
1301 uint16_t desired_replication_level,
1302 uint16_t hop_count,
1305 void *cb_cls)
1306{
1307 const struct GNUNET_PeerIdentity *my_identity;
1308 const struct GNUNET_HashCode *my_identity_hash;
1309 struct GDS_RoutingPutCallbackData gds_routing;
1310 size_t msize;
1311 enum GNUNET_DHT_RouteOption ro = bd->ro;
1312 unsigned int put_path_length = bd->put_path_length;
1313 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1314 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1315 const struct GNUNET_PeerIdentity *trunc_peer
1316 = truncated
1317 ? &bd->trunc_peer
1318 : NULL;
1319 struct GNUNET_PeerIdentity trunc_peer_out;
1321
1323 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1324 GNUNET_assert (NULL != my_identity);
1325
1328 bd->ro, &ro,
1329 bd->expiration_time,
1330 bd->data, bd->data_size,
1331 put_path, put_path_length,
1332 &put_path_length,
1333 trunc_peer,
1334 &trunc_peer_out,
1335 &truncated);
1336 if (truncated)
1337 trunc_peer = &trunc_peer_out;
1338 /* Path may have been truncated by the call above */
1340 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1342 GNUNET_h2s (&bd->key),
1343 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1344 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1345
1346 /* if we got a HELLO, consider it for our own routing table */
1347 hello_check (bd);
1348 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1349 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1351 "# PUT requests routed",
1352 1,
1353 GNUNET_NO);
1354 if (GNUNET_OK != ret)
1355 {
1356 if (cb)
1357 cb (cb_cls, ret);
1358 return;
1359 }
1360 gds_routing.target_count
1361 = get_target_peers (&bd->key,
1362 bf,
1363 hop_count,
1364 desired_replication_level,
1365 &(gds_routing.targets));
1366 if (0 == gds_routing.target_count)
1367 {
1369 "Routing PUT for %s terminates after %u hops at %s\n",
1370 GNUNET_h2s (&bd->key),
1371 (unsigned int) hop_count,
1373 if (cb)
1374 cb (cb_cls, GNUNET_NO);
1375 if (gds_routing.targets)
1376 GNUNET_free (gds_routing.targets);
1377 return;
1378 }
1379 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1380 sizeof (gds_routing.key));
1381 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1382 {
1383 struct PeerInfo *target = gds_routing.targets[i];
1384
1386 &target->phash);
1387 }
1388
1389 gds_routing.queued = GNUNET_new (unsigned int);
1390 *(gds_routing.queued) = 0;
1391
1392 gds_routing.cb = cb;
1393 gds_routing.cb_cls = cb_cls;
1394
1395 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1396 {
1397 struct PeerInfo *target = gds_routing.targets[i];
1398 struct PeerPutMessage *ppm;
1399 char buf[msize] GNUNET_ALIGN;
1400
1401 gds_routing.index = i;
1402
1403 ppm = (struct PeerPutMessage *) buf;
1404 GDS_helper_make_put_message (ppm, msize,
1405 NULL,
1406 &target->id,
1407 &target->phash,
1408 bf,
1409 &bd->key,
1410 ro,
1411 bd->type,
1412 bd->expiration_time,
1413 bd->data, bd->data_size,
1414 put_path, put_path_length,
1415 hop_count,
1417 trunc_peer,
1419 sizeof (gds_routing),
1420 &gds_routing);
1421 }
1422}
1423
1424
1429 uint16_t hop_count,
1430 const struct GNUNET_HashCode *key,
1431 const void *xquery,
1432 size_t xquery_size,
1433 struct GNUNET_BLOCK_Group *bg,
1434 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1435{
1436 const struct GNUNET_PeerIdentity *my_identity;
1437 const struct GNUNET_HashCode *my_identity_hash;
1438 unsigned int target_count;
1439 struct PeerInfo **targets;
1440 size_t msize;
1441 size_t result_filter_size;
1442 void *result_filter;
1443
1445 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1446
1447 if (NULL == my_identity_hash)
1448 return GNUNET_NO;
1449
1450 GNUNET_assert (NULL != peer_bf);
1452 "# GET requests routed",
1453 1,
1454 GNUNET_NO);
1455 target_count = get_target_peers (key,
1456 peer_bf,
1457 hop_count,
1458 desired_replication_level,
1459 &targets);
1461 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1463 GNUNET_h2s (key),
1465 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1466 GNUNET_assert (NULL != my_identity_hash);
1467 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1468 if (0 == target_count)
1469 {
1471 "Routing GET for %s terminates after %u hops at %s\n",
1472 GNUNET_h2s (key),
1473 (unsigned int) hop_count,
1475 return GNUNET_NO;
1476 }
1477 if (GNUNET_OK !=
1479 &result_filter,
1480 &result_filter_size))
1481 {
1482 result_filter = NULL;
1483 result_filter_size = 0;
1484 }
1485 msize = xquery_size + result_filter_size;
1486 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1487 {
1488 GNUNET_break (0);
1489 GNUNET_free (result_filter);
1490 GNUNET_free (targets);
1491 return GNUNET_NO;
1492 }
1493 /* update BF */
1494 for (unsigned int i = 0; i < target_count; i++)
1495 {
1496 struct PeerInfo *target = targets[i];
1497
1499 &target->phash);
1500 }
1501 /* forward request */
1502 for (unsigned int i = 0; i < target_count; i++)
1503 {
1504 struct PeerInfo *target = targets[i];
1505 struct PeerGetMessage *pgm;
1506 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1507 char *rf;
1508
1510 "Routing GET for %s after %u hops to %s\n",
1511 GNUNET_h2s (key),
1512 (unsigned int) hop_count,
1513 GNUNET_i2s (&target->id));
1514 pgm = (struct PeerGetMessage *) buf;
1516 pgm->header.size = htons (sizeof (buf));
1517 pgm->type = htonl (type);
1518 pgm->options = htons (options);
1519 pgm->hop_count = htons (hop_count + 1);
1521 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1524 pgm->bloomfilter,
1526 pgm->key = *key;
1527 rf = (char *) &pgm[1];
1528 GNUNET_memcpy (rf,
1529 result_filter,
1532 xquery,
1533 xquery_size);
1534 do_send (target,
1535 &pgm->header);
1536 }
1538 "# GET messages queued for transmission",
1539 target_count,
1540 GNUNET_NO);
1541 GNUNET_free (targets);
1542 GNUNET_free (result_filter);
1543 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1544}
1545
1546
1547struct PeerInfo *
1553
1554
1570
1571
1572static void
1574{
1575 if (reply->block_data)
1576 GNUNET_free (reply->block_data);
1577 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1578 GNUNET_free (reply->put_path);
1579 if (reply->buf)
1580 GNUNET_free (reply->buf);
1581}
1582
1583
1584static void
1587 bool success)
1588{
1589 GNUNET_break (success);
1590 if (cb)
1591 cb (cls);
1592}
1593
1594
1595static bool
1597 const struct GNUNET_CRYPTO_EddsaSignature *sig)
1598{
1599 struct GDS_NeighboursReply *reply = cls;
1600 struct PeerResultMessage *prm = reply->prm;
1601 struct GNUNET_DHT_PathElement *paths = reply->paths;
1602 unsigned int ppl = ntohs (prm->put_path_length);
1603 unsigned int get_path_length = ntohs (prm->get_path_length);
1604 void *tgt = &paths[get_path_length + ppl];
1605 void *data;
1606
1607 if (! sig)
1608 {
1610 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1611 return true;
1612 }
1613
1614 memcpy (tgt,
1615 sig,
1616 sizeof (*sig));
1617 data = tgt + sizeof (*sig);
1619 "Signing GET PATH %u/%u of %s => %s\n",
1620 ppl,
1621 get_path_length,
1622 GNUNET_h2s (&prm->key),
1623 GNUNET_B2S (sig));
1624#if SANITY_CHECKS > 1
1625 {
1626 const struct GNUNET_PeerIdentity *my_identity;
1627 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1628 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1629 NULL : &reply->trunc_peer_id;
1630
1632 GNUNET_assert (NULL != my_identity);
1633
1634 memcpy (xpaths,
1635 &paths[ppl],
1636 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1637 xpaths[get_path_length].sig = *sig;
1638 xpaths[get_path_length].pred = *my_identity;
1639 if (0 !=
1641 reply->bd.data_size,
1642 reply->bd.expiration_time,
1643 trunc_peer,
1644 paths,
1645 ppl,
1646 xpaths,
1647 get_path_length + 1,
1648 &reply->pi->id))
1649 {
1650 GNUNET_break (0);
1652 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1653 return true;
1654 }
1655 }
1656#endif
1658 reply->bd.data,
1659 reply->bd.data_size);
1660 do_send (reply->pi,
1661 &prm->header);
1663 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1664 return true;
1665}
1666
1667
1668void
1670 const struct GNUNET_DATACACHE_Block *bd,
1671 const struct GNUNET_HashCode *query_hash,
1672 unsigned int get_path_length,
1673 const struct GNUNET_DHT_PathElement *get_path,
1675 void *cb_cls)
1676{
1677 struct GNUNET_DHT_PathElement *paths;
1678 size_t msize;
1679 unsigned int ppl = bd->put_path_length;
1680 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1681 enum GNUNET_DHT_RouteOption ro = bd->ro;
1682 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1683 const struct GNUNET_PeerIdentity *trunc_peer
1684 = truncated
1685 ? &bd->trunc_peer
1686 : NULL;
1687 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1688#if SANITY_CHECKS > 1
1689 const struct GNUNET_PeerIdentity *my_identity;
1690 unsigned int failure_offset;
1691
1693 GNUNET_assert (NULL != my_identity);
1694
1695 failure_offset
1697 bd->data_size,
1698 bd->expiration_time,
1699 trunc_peer,
1700 put_path,
1701 ppl,
1702 get_path,
1703 get_path_length,
1704 my_identity);
1705 if (0 != failure_offset)
1706 {
1707 GNUNET_assert (failure_offset <= ppl + get_path_length);
1708 GNUNET_break_op (0);
1709 if (failure_offset < ppl)
1710 {
1711 trunc_peer = &put_path[failure_offset - 1].pred;
1712 put_path += failure_offset;
1713 ppl -= failure_offset;
1714 truncated = true;
1716 }
1717 else
1718 {
1719 failure_offset -= ppl;
1720 if (0 == failure_offset)
1721 trunc_peer = &put_path[ppl - 1].pred;
1722 else
1723 trunc_peer = &get_path[failure_offset - 1].pred;
1724 ppl = 0;
1725 put_path = NULL;
1726 truncated = true;
1728 get_path += failure_offset;
1729 get_path_length -= failure_offset;
1730 }
1731 }
1732#endif
1733 msize = bd->data_size + sizeof (struct PeerResultMessage);
1734 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1735 {
1736 GNUNET_break_op (0);
1737 safe_neighbours_callback (cb_cls, cb, false);
1738 return;
1739 }
1740 if (truncated)
1741 msize += sizeof (struct GNUNET_PeerIdentity);
1742 if (tracking)
1743 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1744 if (msize < bd->data_size)
1745 {
1746 GNUNET_break_op (0);
1747 safe_neighbours_callback (cb_cls, cb, false);
1748 return;
1749 }
1750 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1751 / sizeof(struct GNUNET_DHT_PathElement)
1752 < (get_path_length + ppl) )
1753 {
1754 get_path_length = 0;
1755 ppl = 0;
1756 }
1757 if ( (get_path_length > UINT16_MAX) ||
1758 (ppl > UINT16_MAX) )
1759 {
1760 GNUNET_break (0);
1761 get_path_length = 0;
1762 ppl = 0;
1763 }
1764 msize += (get_path_length + ppl)
1765 * sizeof(struct GNUNET_DHT_PathElement);
1767 "Forwarding reply for key %s to peer %s\n",
1768 GNUNET_h2s (query_hash),
1769 GNUNET_i2s (&pi->id));
1771 "# RESULT messages queued for transmission",
1772 1,
1773 GNUNET_NO);
1774 {
1775 struct PeerResultMessage *prm;
1776 char buf[msize] GNUNET_ALIGN;
1777
1778 prm = (struct PeerResultMessage *) buf;
1780 prm->header.size = htons (sizeof (buf));
1781 prm->type = htonl ((uint32_t) bd->type);
1782 prm->reserved = htons (0);
1783 prm->options = htons ((uint16_t) ro);
1784 prm->put_path_length = htons ((uint16_t) ppl);
1785 prm->get_path_length = htons ((uint16_t) get_path_length);
1787 prm->key = *query_hash;
1788 if (truncated)
1789 {
1790 void *tgt = &prm[1];
1791
1792 GNUNET_memcpy (tgt,
1793 trunc_peer,
1794 sizeof (struct GNUNET_PeerIdentity));
1795 paths = (struct GNUNET_DHT_PathElement *)
1796 (tgt + sizeof (struct GNUNET_PeerIdentity));
1797 }
1798 else
1799 {
1800 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1801 }
1802 if (NULL != put_path)
1803 {
1804 GNUNET_memcpy (paths,
1805 put_path,
1806 ppl * sizeof(struct GNUNET_DHT_PathElement));
1807 }
1808 else
1809 {
1810 GNUNET_assert (0 == ppl);
1811 }
1812 if (NULL != get_path)
1813 {
1814 GNUNET_memcpy (&paths[ppl],
1815 get_path,
1816 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1817 }
1818 else
1819 {
1820 GNUNET_assert (0 == get_path_length);
1821 }
1822 if (tracking)
1823 {
1824 struct GDS_NeighboursReply reply;
1825 const struct GNUNET_PeerIdentity *pred;
1826
1827 reply.pi = pi;
1828 GNUNET_memcpy (&reply.bd, bd, sizeof (reply.bd));
1829 reply.block_data = GNUNET_memdup (bd->data, bd->data_size);
1830 reply.put_path = GNUNET_memdup (bd->put_path,
1831 sizeof (struct GNUNET_DHT_PathElement)
1832 * bd->put_path_length);
1833
1834 reply.bd.data = reply.block_data;
1835 reply.bd.put_path = reply.put_path;
1836
1837 reply.buf = GNUNET_memdup (buf, msize);
1838 reply.prm = (struct PeerResultMessage*) reply.buf;
1839 reply.paths = (struct GNUNET_DHT_PathElement*) (reply.buf + (buf - (const
1840 char*)
1841 paths));
1842
1843 if (trunc_peer)
1844 {
1845 reply.trunc_peer_is_null = false;
1846 GNUNET_memcpy (&reply.trunc_peer_id, trunc_peer,
1847 sizeof (reply.trunc_peer_id));
1848 }
1849 else
1850 {
1851 reply.trunc_peer_is_null = true;
1852 }
1853
1854 reply.cb = cb;
1855 reply.cb_cls = cb_cls;
1856
1857 if (ppl + get_path_length > 0)
1858 pred = &paths[ppl + get_path_length - 1].pred;
1859 else if (truncated)
1860 pred = trunc_peer;
1861 else
1862 pred = NULL; /* we are first! */
1863 /* Note that the last signature in 'paths' was not initialized before,
1864 so this is crucial to avoid sending garbage. */
1866 bd->data_size,
1867 NULL,
1868 bd->expiration_time,
1869 pred,
1870 &pi->id,
1872 sizeof (reply),
1873 &reply);
1874 }
1875 else
1876 {
1877 void *data;
1878 data = &prm[1];
1880 bd->data,
1881 bd->data_size);
1882 do_send (pi,
1883 &prm->header);
1884 safe_neighbours_callback (cb_cls, cb, true);
1885 return;
1886 }
1887 }
1888}
1889
1890
1898static enum GNUNET_GenericReturnValue
1900 const struct PeerPutMessage *put)
1901{
1902 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1903 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1904 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1905 uint16_t msize = ntohs (put->header.size);
1906 uint16_t putlen = ntohs (put->put_path_length);
1907 size_t xsize = (has_path
1908 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1909 : 0)
1910 + (truncated
1911 ? sizeof (struct GNUNET_PeerIdentity)
1912 : 0);
1913 size_t var_meta_size
1914 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1915 + xsize;
1916
1917 (void) cls;
1918 if ( (msize <
1919 sizeof (struct PeerPutMessage) + var_meta_size) ||
1920 (putlen >
1921 (GNUNET_MAX_MESSAGE_SIZE
1922 - sizeof (struct PeerPutMessage)
1923 - xsize)
1924 / sizeof(struct GNUNET_DHT_PathElement)) )
1925 {
1926 GNUNET_break_op (0);
1927 return GNUNET_SYSERR;
1928 }
1929 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1930 {
1931 GNUNET_break_op (0);
1932 return GNUNET_SYSERR;
1933 }
1934 return GNUNET_OK;
1935}
1936
1937
1948
1949
1950static void
1952 enum GNUNET_GenericReturnValue forwarded)
1953{
1954 struct ForwardedDHTPut *put = cls;
1955
1956 /* notify monitoring clients */
1957 put->block.ro |= ((GNUNET_OK == forwarded)
1959 : 0);
1961 put->hop_count,
1963
1964 if (put->put_path)
1965 GNUNET_free (put->put_path);
1966 GNUNET_free (put->data);
1967 GNUNET_free (put);
1968}
1969
1970
1977static void
1979 const struct PeerPutMessage *put)
1980{
1981 struct Target *t = cls;
1982 struct PeerInfo *peer = t->pi;
1983 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1984 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1985 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1986 uint16_t msize = ntohs (put->header.size);
1987 uint16_t putlen = ntohs (put->put_path_length);
1988 const struct GNUNET_PeerIdentity *trunc_peer
1989 = truncated
1990 ? (const struct GNUNET_PeerIdentity *) &put[1]
1991 : NULL;
1992 const struct GNUNET_DHT_PathElement *put_path
1993 = truncated
1994 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1995 : (const struct GNUNET_DHT_PathElement *) &put[1];
1996 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1997 = has_path
1998 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1999 : NULL;
2000 const char *data
2001 = has_path
2002 ? (const char *) &last_sig[1]
2003 : (const char *) &put_path[putlen];
2004 size_t var_meta_size
2005 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2006 + (has_path ? sizeof (*last_sig) : 0)
2007 + (truncated ? sizeof (*trunc_peer) : 0);
2008 struct GNUNET_DATACACHE_Block bd = {
2009 .key = put->key,
2010 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2011 .type = ntohl (put->type),
2012 .ro = ro,
2013 .data_size = msize - sizeof(*put) - var_meta_size,
2014 .data = data
2015 };
2016
2017 if (NULL != trunc_peer)
2018 bd.trunc_peer = *trunc_peer;
2020 "PUT for `%s' from %s with RO (%s/%s)\n",
2021 GNUNET_h2s (&put->key),
2022 GNUNET_i2s (&peer->id),
2023 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2024 has_path ? "R" : "-");
2026 {
2028 "# Expired PUTs discarded",
2029 1,
2030 GNUNET_NO);
2031 return;
2032 }
2033 {
2034 /* Only call 'check_block' if that keeps our CPU load (from
2035 the cryptography) below 50% on average */
2036 static struct GNUNET_TIME_Relative avg_latency;
2037 static struct GNUNET_TIME_Absolute next_time;
2038
2039 if (GNUNET_TIME_absolute_is_past (next_time))
2040 {
2041 struct GNUNET_TIME_Absolute now
2043 struct GNUNET_TIME_Relative latency;
2045
2046 if (GNUNET_NO ==
2048 bd.type,
2049 bd.data,
2050 bd.data_size))
2051 {
2052 GNUNET_break_op (0);
2053 return;
2054 }
2055 latency = GNUNET_TIME_absolute_get_duration (now);
2056 /* Use *moving average* to estimate check_block latency */
2057 avg_latency
2060 GNUNET_TIME_relative_multiply (avg_latency,
2061 7),
2062 latency),
2063 8);
2064 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2066 = GNUNET_CRYPTO_random_u64 (avg_latency.rel_value_us > 0
2067 ? avg_latency.rel_value_us
2068 : 1LLU);
2070 }
2071 }
2072 if (! has_path)
2073 putlen = 0;
2075 "# P2P PUT requests received",
2076 1,
2077 GNUNET_NO);
2079 "# P2P PUT bytes received",
2080 msize,
2081 GNUNET_NO);
2082 {
2083 struct GNUNET_HashCode test_key;
2085
2087 bd.type,
2088 bd.data,
2089 bd.data_size,
2090 &test_key);
2091 switch (ret)
2092 {
2093 case GNUNET_YES:
2094 if (0 != GNUNET_memcmp (&test_key,
2095 &bd.key))
2096 {
2097 GNUNET_break_op (0);
2098 return;
2099 }
2100 break;
2101 case GNUNET_NO:
2102 /* cannot verify, good luck */
2103 break;
2104 case GNUNET_SYSERR:
2105 /* block type not supported, good luck */
2106 break;
2107 }
2108 }
2109
2110 {
2112 struct GNUNET_DHT_PathElement pp[putlen + 1];
2113
2119 &peer->phash));
2120 /* extend 'put path' by sender */
2121 bd.put_path = pp;
2122 bd.put_path_length = putlen + 1;
2123 if (has_path)
2124 {
2125 unsigned int failure_offset;
2126
2127 GNUNET_memcpy (pp,
2128 put_path,
2129 putlen * sizeof(struct GNUNET_DHT_PathElement));
2130 pp[putlen].pred = peer->id;
2131 pp[putlen].sig = *last_sig;
2132#if SANITY_CHECKS
2133 {
2134 const struct GNUNET_PeerIdentity *my_identity;
2136 GNUNET_assert (NULL != my_identity);
2137 /* TODO: might want to eventually implement probabilistic
2138 load-based path verification, but for now it is all or nothing */
2139 failure_offset
2141 bd.data_size,
2142 bd.expiration_time,
2143 trunc_peer,
2144 pp,
2145 putlen + 1,
2146 NULL, 0, /* get_path */
2147 my_identity);
2148 }
2149#else
2150 failure_offset = 0;
2151#endif
2152 if (0 != failure_offset)
2153 {
2154 GNUNET_break_op (0);
2156 "Recorded put path invalid at offset %u, truncating\n",
2157 failure_offset);
2158 GNUNET_assert (failure_offset <= putlen + 1);
2159 bd.put_path = &pp[failure_offset];
2160 bd.put_path_length = (putlen + 1) - failure_offset;
2162 bd.trunc_peer = pp[failure_offset - 1].pred;
2163 }
2164 }
2165 else
2166 {
2167 bd.put_path_length = 0;
2168 }
2169
2170 /* give to local clients */
2172 &bd.key,
2173 0, NULL /* get path */));
2174
2175 /* store locally */
2176 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2177 (GDS_am_closest_peer (&put->key,
2178 bf)) )
2180
2181 {
2183 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2184
2185 if (bd.put_path_length > 0)
2186 {
2187 forward->put_path = GNUNET_memdup (
2188 bd.put_path,
2189 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2190 forward->block.put_path = forward->put_path;
2191 }
2192
2193 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2194 forward->block.data = forward->data;
2195
2196 forward->desired_replication_level = ntohs (put->desired_replication_level
2197 );
2198 forward->hop_count = ntohs (put->hop_count);
2199
2200 /* route to other peers */
2202 forward->desired_replication_level,
2203 forward->hop_count,
2204 bf,
2206 forward);
2207 }
2209 }
2210}
2211
2212
2214{
2215 struct PeerInfo *pi;
2218};
2219
2220
2229static void
2231 const struct GNUNET_HashCode *query_hash,
2232 struct GNUNET_BLOCK_Group *bg,
2234 void *cb_cls)
2235{
2236 const struct GNUNET_HashCode *my_identity_hash;
2237 const struct GNUNET_PeerIdentity *my_identity;
2238 struct GNUNET_TIME_Absolute block_expiration;
2239 size_t block_size;
2240 void *block;
2241
2242 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2245 "Handle finding my own HELLO %s\n",
2246 GNUNET_h2s (my_identity_hash));
2247 if (NULL == GDS_my_hello)
2248 {
2250 "# FIND PEER requests ignored due to lack of HELLO",
2251 1,
2252 GNUNET_NO);
2253 if (cb)
2254 cb (cb_cls);
2255 return;
2256 }
2257
2260 &block,
2261 &block_size,
2262 &block_expiration))
2263 {
2264 if (cb)
2265 cb (cb_cls);
2266 return;
2267 }
2268
2272 bg,
2273 my_identity_hash,
2274 NULL, 0,
2275 block,
2276 block_size))
2277 {
2278 struct GNUNET_DATACACHE_Block bd = {
2280 .expiration_time
2283 .key = *my_identity_hash,
2284 .data = block,
2285 .data_size = block_size
2286 };
2287
2289 &bd,
2290 query_hash,
2291 0, NULL /* get path */,
2292 cb,
2293 cb_cls);
2294 }
2295 else
2296 {
2298 "# FIND PEER requests ignored due to Bloomfilter",
2299 1,
2300 GNUNET_NO);
2301 if (cb)
2302 cb (cb_cls);
2303 }
2304
2305 GNUNET_free (block);
2306}
2307
2308
2317static void
2319 const struct GNUNET_HashCode *query_hash,
2320 struct GNUNET_BLOCK_Group *bg,
2322 void *cb_cls)
2323{
2324 /* Force non-random selection by hop count */
2325 struct PeerInfo *peer;
2326
2327 peer = select_peer (query_hash,
2328 NULL,
2329 GDS_NSE_get () + 1);
2331 "Handle finding local HELLO %s\n",
2332 GNUNET_h2s (&peer->phash));
2333 if ( (NULL != peer->hello) &&
2339 bg,
2340 &peer->phash,
2341 NULL, 0, /* xquery */
2342 peer->hello,
2343 peer->hello_size)) )
2344 {
2345 struct GNUNET_DATACACHE_Block bd = {
2347 .expiration_time = peer->hello_expiration,
2348 .key = peer->phash,
2349 .data = peer->hello,
2350 .data_size = peer->hello_size
2351 };
2352
2354 &bd,
2355 query_hash,
2356 0, NULL /* get path */,
2357 cb,
2358 cb_cls);
2359 }
2360 else if (cb)
2361 cb (cb_cls);
2362}
2363
2364
2371
2372
2379static void
2381 const struct GNUNET_DATACACHE_Block *bd)
2382{
2383 struct HandleCallbackLocal *local = cls;
2384
2386 bd,
2387 &bd->key,
2388 0, NULL /* get path */,
2389 local->cb,
2390 local->cb_cls);
2391}
2392
2393
2401static enum GNUNET_GenericReturnValue
2403 const struct PeerGetMessage *get)
2404{
2405 uint16_t msize = ntohs (get->header.size);
2406 uint16_t result_filter_size = ntohs (get->result_filter_size);
2407
2408 (void) cls;
2409 if (msize < sizeof(*get) + result_filter_size)
2410 {
2411 GNUNET_break_op (0);
2412 return GNUNET_SYSERR;
2413 }
2414 return GNUNET_OK;
2415}
2416
2417
2426
2427
2428static void
2430{
2431 struct HandleCallbackGet *handle = cls;
2432 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2433 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2434 const void *result_filter = (const void *) &handle->get[1];
2435 uint16_t msize = ntohs (handle->get->header.size);
2436 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2437 const void *xquery = result_filter + result_filter_size;
2438 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2439
2440 /* remember request for routing replies
2441 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2442 */
2443 GDS_ROUTING_add (&handle->t->pi->id,
2444 type,
2445 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2446 options,
2447 &handle->get->key,
2448 xquery,
2449 xquery_size);
2450
2451 /* P2P forwarding */
2452 {
2453 bool forwarded = false;
2454 uint16_t desired_replication_level = ntohs (
2455 handle->get->desired_replication_level);
2456 uint16_t hop_count = ntohs (handle->get->hop_count);
2457
2459 forwarded = (GNUNET_OK ==
2461 options,
2462 desired_replication_level,
2463 hop_count,
2464 &handle->get->key,
2465 xquery,
2466 xquery_size,
2467 handle->bg,
2468 handle->peer_bf));
2470 options
2471 | (forwarded
2472 ? 0
2474 type,
2475 hop_count,
2476 desired_replication_level,
2477 &handle->get->key);
2478 }
2479 /* clean up; note that 'bg' is owned by routing now! */
2481
2482 GNUNET_free (handle->get);
2484}
2485
2486
2487static void
2489{
2490 struct HandleCallbackGet *handle = cls;
2491 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2492
2494 "Handle getting local HELLO %s of type %u\n",
2495 GNUNET_h2s (&handle->get->key),
2496 type);
2497
2499 {
2500 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2501 const void *result_filter = (const void *) &handle->get[1];
2502 uint16_t msize = ntohs (handle->get->header.size);
2503 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2504 const void *xquery = result_filter + result_filter_size;
2505 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2506 struct HandleCallbackLocal local;
2507 local.peer = handle->t->pi;
2509 local.cb_cls = handle;
2510
2512 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2513 type,
2514 xquery,
2515 xquery_size,
2516 handle->bg,
2518 &local);
2519 else
2520 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2521 type,
2522 xquery,
2523 xquery_size,
2524 handle->bg,
2526 &local);
2527 }
2528 else
2530}
2531
2532
2533static void
2535{
2536 struct HandleCallbackGet *handle = cls;
2537 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2538
2541 &handle->get->key,
2542 handle->bg,
2544 handle);
2545 else
2547}
2548
2549
2556static void
2558 const struct PeerGetMessage *get)
2559{
2560 struct Target *t = cls;
2561 struct PeerInfo *peer = t->pi;
2562 uint16_t msize = ntohs (get->header.size);
2563 uint16_t result_filter_size = ntohs (get->result_filter_size);
2564 uint16_t hop_count = ntohs (get->hop_count);
2565 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2566 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2567 const void *result_filter = (const void *) &get[1];
2568 const void *xquery = result_filter + result_filter_size;
2569 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2570
2571 /* parse and validate message */
2573 "# P2P GET requests received",
2574 1,
2575 GNUNET_NO);
2577 "# P2P GET bytes received",
2578 msize,
2579 GNUNET_NO);
2580 if (GNUNET_NO ==
2582 type,
2583 &get->key,
2584 xquery,
2585 xquery_size))
2586 {
2587 /* request invalid */
2588 GNUNET_break_op (0);
2589 return;
2590 }
2591
2592 {
2593 const struct GNUNET_PeerIdentity *my_identity;
2594 struct HandleCallbackGet *handle;
2595
2597 handle->t = t;
2598 handle->get = GNUNET_memdup (get, msize);
2600
2602 GNUNET_assert (NULL != my_identity);
2603
2604 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2609 &peer->phash));
2611 type,
2612 result_filter,
2613 result_filter_size,
2614 "filter-size",
2615 result_filter_size,
2616 NULL);
2618 "GET for %s at %s after %u hops\n",
2619 GNUNET_h2s (&get->key),
2621 (unsigned int) hop_count);
2622 /* local lookup (this may update the bg) */
2624 (GDS_am_closest_peer (&get->key,
2625 handle->peer_bf)) )
2626 {
2629 {
2631 "# P2P HELLO lookup requests processed",
2632 1,
2633 GNUNET_NO);
2635 &get->key,
2636 handle->bg,
2638 handle);
2639 }
2640 else
2642 }
2643 else
2644 {
2646 "# P2P GET requests ONLY routed",
2647 1,
2648 GNUNET_NO);
2650 }
2651 }
2652}
2653
2654
2663static void
2665 const struct GNUNET_HashCode *query_hash,
2666 unsigned int get_path_length,
2667 const struct GNUNET_DHT_PathElement *get_path)
2668{
2669 /* forward to local clients */
2671 "Forwarding reply to local clients\n");
2672 if (! GDS_CLIENTS_handle_reply (bd,
2673 query_hash,
2674 get_path_length,
2675 get_path))
2676 {
2677 GNUNET_break (0);
2678 return;
2679 }
2681 get_path,
2682 get_path_length);
2684 {
2685 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2686 + bd->put_path_length)];
2687 struct GNUNET_DATACACHE_Block bdx = *bd;
2688
2689 if (NULL != bd->put_path)
2690 GNUNET_memcpy (xput_path,
2691 bd->put_path,
2692 bd->put_path_length * sizeof(struct
2694 GNUNET_memcpy (&xput_path[bd->put_path_length],
2695 get_path,
2696 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2697 bdx.put_path = xput_path;
2698 bdx.put_path_length += get_path_length;
2700 }
2701 /* forward to other peers */
2703 query_hash,
2704 get_path_length,
2705 get_path);
2706}
2707
2708
2716static enum GNUNET_GenericReturnValue
2718 const struct PeerResultMessage *prm)
2719{
2720 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2721 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2722 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2723 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2724
2725 uint16_t get_path_length = ntohs (prm->get_path_length);
2726 uint16_t put_path_length = ntohs (prm->put_path_length);
2727 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2728 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2729
2730 (void) cls;
2731 if ( (msize < vsize) ||
2732 (msize - vsize <
2733 (get_path_length + put_path_length)
2734 * sizeof(struct GNUNET_DHT_PathElement)) ||
2735 (get_path_length >
2736 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2737 (put_path_length >
2738 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2739 {
2740 GNUNET_break_op (0);
2741 return GNUNET_SYSERR;
2742 }
2743 return GNUNET_OK;
2744}
2745
2746
2753static void
2755 const struct PeerResultMessage *prm)
2756{
2757 struct Target *t = cls;
2758 struct PeerInfo *peer = t->pi;
2759 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2760 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2761 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2762 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2763 uint16_t get_path_length = ntohs (prm->get_path_length);
2764 uint16_t put_path_length = ntohs (prm->put_path_length);
2765 const struct GNUNET_PeerIdentity *trunc_peer
2766 = truncated
2767 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2768 : NULL;
2769 const struct GNUNET_DHT_PathElement *put_path
2770 = truncated
2771 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2772 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2773 const struct GNUNET_DHT_PathElement *get_path
2774 = &put_path[put_path_length];
2775 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2776 = tracked
2777 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2778 : NULL;
2779 const void *data
2780 = tracked
2781 ? (const void *) &last_sig[1]
2782 : (const void *) &get_path[get_path_length];
2783 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2784 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2785 struct GNUNET_DATACACHE_Block bd = {
2787 .put_path = put_path,
2788 .put_path_length = put_path_length,
2789 .key = prm->key,
2790 .type = ntohl (prm->type),
2791 .ro = ro,
2792 .data = data,
2793 .data_size = msize - vsize - (get_path_length + put_path_length)
2794 * sizeof(struct GNUNET_DHT_PathElement)
2795 };
2796
2797 /* parse and validate message */
2798 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2799 {
2801 "# Expired results discarded",
2802 1,
2803 GNUNET_NO);
2804 return;
2805 }
2806 if (GNUNET_OK !=
2808 bd.type,
2809 bd.data,
2810 bd.data_size))
2811 {
2812 GNUNET_break_op (0);
2813 return;
2814 }
2816 "# P2P RESULTS received",
2817 1,
2818 GNUNET_NO);
2820 "# P2P RESULT bytes received",
2821 msize,
2822 GNUNET_NO);
2823 {
2825
2827 bd.type,
2828 bd.data,
2829 bd.data_size,
2830 &bd.key);
2831 if (GNUNET_NO == ret)
2832 bd.key = prm->key;
2833 }
2834
2835 /* if we got a HELLO, consider it for our own routing table */
2836 hello_check (&bd);
2837
2838 /* Need to append 'peer' to 'get_path' */
2839 if (tracked)
2840 {
2841 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2842 struct GNUNET_DHT_PathElement *gp = xget_path;
2843 unsigned int failure_offset;
2844
2845 GNUNET_memcpy (xget_path,
2846 get_path,
2847 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2848 xget_path[get_path_length].pred = peer->id;
2849 /* use memcpy(), as last_sig may not be aligned */
2850 memcpy (&xget_path[get_path_length].sig,
2851 last_sig,
2852 sizeof (*last_sig));
2853#if SANITY_CHECKS
2854 {
2855 const struct GNUNET_PeerIdentity *my_identity;
2857 GNUNET_assert (NULL != my_identity);
2858 /* TODO: might want to eventually implement probabilistic
2859 load-based path verification, but for now it is all or nothing */
2860 failure_offset
2861 = GNUNET_DHT_verify_path (bd.data,
2862 bd.data_size,
2863 bd.expiration_time,
2864 trunc_peer,
2865 put_path,
2866 put_path_length,
2867 gp,
2868 get_path_length + 1,
2869 my_identity);
2870 }
2871#else
2872 failure_offset = 0;
2873#endif
2874 if (0 != failure_offset)
2875 {
2877 "Recorded path invalid at offset %u, truncating\n",
2878 failure_offset);
2879 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2880 + 1);
2881 if (failure_offset < bd.put_path_length)
2882 {
2883 /* failure on put path */
2884 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2885 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2886 bd.put_path = &bd.put_path[failure_offset];
2887 bd.put_path_length -= failure_offset;
2888 truncated = true;
2889 }
2890 else
2891 {
2892 /* failure on get path */
2893 failure_offset -= bd.put_path_length;
2894 if (0 == failure_offset)
2895 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2896 else
2897 trunc_peer = &gp[failure_offset - 1].pred;
2898 get_path_length -= failure_offset;
2899 gp = &gp[failure_offset];
2900 bd.put_path_length = 0;
2901 bd.put_path = NULL;
2902 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2903 truncated = true;
2904 }
2905 }
2907 "Extending GET path of length %u with %s\n",
2908 get_path_length,
2909 GNUNET_i2s (&peer->id));
2910 if (truncated)
2911 {
2912 GNUNET_assert (NULL != trunc_peer);
2913 bd.trunc_peer = *trunc_peer;
2914 }
2916 &prm->key,
2917 get_path_length + 1,
2918 gp);
2919 }
2920 else
2921 {
2922 if (truncated)
2923 {
2924 GNUNET_assert (NULL != trunc_peer);
2925 bd.trunc_peer = *trunc_peer;
2926 }
2928 &prm->key,
2929 0,
2930 NULL);
2931 }
2932}
2933
2934
2942static enum GNUNET_GenericReturnValue
2944 const struct GNUNET_MessageHeader *hello)
2945{
2946 struct Target *t = cls;
2947 struct PeerInfo *peer = t->pi;
2949 size_t hellob_size;
2950 void *hellob;
2952
2954 &peer->id,
2955 &hellob,
2956 &hellob_size,
2957 &expiration);
2958 GNUNET_free (hellob);
2959 return ret;
2960}
2961
2962
2969static void
2971 const struct GNUNET_MessageHeader *hello)
2972{
2973 struct Target *t = cls;
2974 struct PeerInfo *peer = t->pi;
2975
2976 GNUNET_free (peer->hello);
2977 peer->hello_size = 0;
2980 &peer->id,
2981 &peer->hello,
2982 &peer->hello_size,
2983 &peer->hello_expiration));
2984}
2985
2986
2987void
2988GDS_u_receive (void *cls,
2989 void **tctx,
2990 void **sctx,
2991 const void *message,
2992 size_t message_size)
2993{
2994 struct Target *t = *tctx;
2995 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2996 GNUNET_MQ_hd_var_size (dht_p2p_get,
2998 struct PeerGetMessage,
2999 t),
3000 GNUNET_MQ_hd_var_size (dht_p2p_put,
3002 struct PeerPutMessage,
3003 t),
3004 GNUNET_MQ_hd_var_size (dht_p2p_result,
3006 struct PeerResultMessage,
3007 t),
3008 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3010 struct GNUNET_MessageHeader,
3011 t),
3013 };
3014 const struct GNUNET_MessageHeader *mh = message;
3015
3016 (void) cls; /* the 'struct GDS_Underlay' */
3017 (void) sctx; /* our receiver address */
3018 if (NULL == t)
3019 {
3020 /* Received message claiming to originate from myself?
3021 Ignore! */
3022 GNUNET_break_op (0);
3023 return;
3024 }
3025 if (message_size < sizeof (*mh))
3026 {
3027 GNUNET_break_op (0);
3028 return;
3029 }
3030 if (message_size != ntohs (mh->size))
3031 {
3032 GNUNET_break_op (0);
3033 return;
3034 }
3036 "Handling message of type %u from peer %s\n",
3037 ntohs (mh->type),
3038 GNUNET_i2s (&t->pi->id));
3039 if (GNUNET_OK !=
3040 GNUNET_MQ_handle_message (core_handlers,
3041 mh))
3042 {
3043 GNUNET_break_op (0);
3044 return;
3045 }
3046}
3047
3048
3056void
3058 const struct GNUNET_PeerIdentity *pid,
3059 const char *uri)
3060{
3061 const struct GNUNET_PeerIdentity *my_identity;
3062 struct GNUNET_HashCode phash;
3063 int peer_bucket;
3064 struct PeerBucket *bucket;
3065 (void) cls;
3066
3068 GNUNET_assert (NULL != my_identity);
3069
3070 if (0 == GNUNET_memcmp (my_identity, pid))
3071 {
3073 "Got a HELLO for my own PID, ignoring it\n");
3074 return; /* that's us! */
3075 }
3077 sizeof(*pid),
3078 &phash);
3079 peer_bucket = find_bucket (&phash);
3080 GNUNET_assert ( (peer_bucket >= 0) &&
3081 ((unsigned int) peer_bucket < MAX_BUCKETS));
3082 bucket = &k_buckets[peer_bucket];
3083 for (struct PeerInfo *pi = bucket->head;
3084 NULL != pi;
3085 pi = pi->next)
3086 if (0 ==
3087 GNUNET_memcmp (&pi->id,
3088 pid))
3089 {
3090 /* already connected */
3092 uri);
3093 return;
3094 }
3095 if (bucket->peers_size >= bucket_size)
3096 return; /* do not care */
3098 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3099 GNUNET_i2s (pid),
3100 uri,
3101 peer_bucket,
3102 bucket->peers_size,
3103 bucket_size);
3104 /* new peer that we like! */
3106 uri);
3107}
3108
3109
3115void
3117{
3118 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3119 {
3120 struct PeerBucket *bucket = &k_buckets[bc];
3121 unsigned int count = 0;
3122
3123 for (struct PeerInfo *pos = bucket->head;
3124 NULL != pos;
3125 pos = pos->next)
3126 {
3127 if (count >= bucket_size)
3128 break; /* we only consider first #bucket_size entries per bucket */
3129 count++;
3130 do_send (pos,
3131 msg);
3132 }
3133 }
3134}
3135
3136
3139{
3140
3141 unsigned long long temp_config_num;
3142
3145 "DHT",
3146 "DISABLE_TRY_CONNECT");
3147 if (GNUNET_OK ==
3149 "DHT",
3150 "bucket_size",
3151 &temp_config_num))
3152 bucket_size = (unsigned int) temp_config_num;
3155 "DHT",
3156 "CACHE_RESULTS");
3158 GNUNET_YES);
3159 return GNUNET_OK;
3160}
3161
3162
3163void
3174
3175
3176const struct GNUNET_PeerIdentity *
3181
3182
3183/* end of gnunet-service-dht_neighbours.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MessageHeader * msg
Definition 005.c:2
static mp_limb_t u[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
#define DHT_BLOOM_SIZE
Size of the bloom filter the DHT uses to filter peers.
Definition dht.h:34
bool GDS_helper_make_put_message(struct PeerPutMessage *ppm, size_t msize, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, const struct GNUNET_PeerIdentity *target, const struct GNUNET_HashCode *target_hash, const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *block_key, enum GNUNET_DHT_RouteOption ro, enum GNUNET_BLOCK_Type block_type, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_len, size_t hop_count, uint32_t desired_replication_level, const struct GNUNET_PeerIdentity *trunc_peer, GDS_HelperMsgCallback cb, size_t cb_data_size, void *cb_data)
Definition dht_helper.c:326
bool GDS_helper_sign_path(const void *data, size_t data_size, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, GDS_HelperCallback cb, size_t cb_data_size, void *cb_data)
Sign that we are routing a message from pred to succ.
Definition dht_helper.c:226
enum GNUNET_GenericReturnValue GDS_helper_put_message_get_size(size_t *msize_out, const struct GNUNET_PeerIdentity *my_identity, enum GNUNET_DHT_RouteOption ro_in, enum GNUNET_DHT_RouteOption *ro_out, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path_in, unsigned int put_path_len_in, unsigned int *put_path_len_out, const struct GNUNET_PeerIdentity *trunc_peer, struct GNUNET_PeerIdentity *trunc_peer_out, bool *truncated)
Definition dht_helper.c:96
Helper functions for DHT.
struct GNUNET_PILS_Handle * GDS_pils
Handle for the pils service.
static int forward
Search direction: forward.
Definition gnunet-abd.c:163
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_CADET_Handle * mh
Cadet handle.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_TIME_Relative expiration
User supplied expiration value.
static int get
Get DID Documement for DID Flag.
Definition gnunet-did.c:63
static struct GNUNET_FS_Handle * ctx
static struct GNUNET_SCHEDULER_Task * t
Main task.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static size_t data_size
Number of bytes in data.
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
double GDS_NSE_get(void)
Return the current NSE.
struct GNUNET_MessageHeader * GDS_my_hello
Our HELLO.
struct GNUNET_DHTU_PreferenceHandle * GDS_u_hold(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target)
Create a hold on target at underlay u.
void GDS_u_send(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target, const void *msg, size_t msg_size, GNUNET_SCHEDULER_TaskCallback finished_cb, void *finished_cb_cls)
Send message to some other participant over the network.
void GDS_u_drop(struct GDS_Underlay *u, struct GNUNET_DHTU_PreferenceHandle *ph)
Drop a hold ph from underlay u.
void GDS_u_try_connect(const struct GNUNET_PeerIdentity *pid, const char *address)
Ask all underlays to connect to peer pid at address.
GNUnet DHT globals.
void GDS_CLIENTS_process_get(enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, const struct GNUNET_HashCode *key)
Check if some client is monitoring GET messages and notify them in that case.
void GDS_CLIENTS_process_get_resp(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_DHT_PathElement *get_path, unsigned int get_path_length)
Check if some client is monitoring GET RESP messages and notify them in that case.
struct GNUNET_STATISTICS_Handle * GDS_stats
Handle for the statistics service.
struct GNUNET_BLOCK_Context * GDS_block_context
Our handle to the BLOCK library.
void GDS_CLIENTS_process_put(const struct GNUNET_DATACACHE_Block *bd, uint32_t hop_count, uint32_t desired_replication_level)
Check if some client is monitoring PUT messages and notify them in that case.
bool GDS_CLIENTS_handle_reply(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Handle a reply we've received from another peer.
const struct GNUNET_CONFIGURATION_Handle * GDS_cfg
Configuration we use.
enum GNUNET_BLOCK_ReplyEvaluationResult GDS_DATACACHE_get_closest(const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, GDS_DATACACHE_GetCallback cb, void *cb_cls)
Handle a request for data close to a key that we have received from another peer.
enum GNUNET_BLOCK_ReplyEvaluationResult GDS_DATACACHE_handle_get(const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, GDS_DATACACHE_GetCallback gc, void *gc_cls)
Handle a GET request we've received from another peer.
void GDS_DATACACHE_handle_put(const struct GNUNET_DATACACHE_Block *bd)
Handle a datum we've received from another peer.
static void send_find_peer_message(void *cls)
Task to send a find peer message for our own peer identifier so that we can find the closest peers in...
static void handle_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Core handler for p2p result messages.
void GDS_NEIGHBOURS_handle_reply(struct PeerInfo *pi, const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
Handle a reply (route to origin).
#define MAXIMUM_PENDING_PER_PEER
Maximum allowed number of pending messages per peer.
static int disable_try_connect
Option for testing that disables the 'connect' function of the DHT.
void GDS_try_connect(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
Callback function used to extract URIs from a builder.
static void cleanup_neighbours_reply(struct GDS_NeighboursReply *reply)
struct PeerInfo * GDS_NEIGHBOURS_lookup_peer(const struct GNUNET_PeerIdentity *target)
Lookup peer by peer's identity.
static void handle_find_my_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
We have received a request for a HELLO.
static unsigned int newly_found_peers
How many peers have we added since we sent out our last find peer request?
static void send_done_cb(void *cls)
Function called whenever we finished sending to a target.
static struct PeerInfo * select_peer(const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hops)
Select a peer from the routing table that would be a good routing destination for sending a message f...
#define DEFAULT_BUCKET_SIZE
What is the maximum number of peers in a given bucket.
void GDS_NEIGHBOURS_done()
Shutdown neighbours subsystem.
void GDS_u_disconnect(void *ctx)
Function to call when we disconnected from a peer and can henceforth cannot transmit to that peer any...
static void handle_dht_p2p_hello(void *cls, const struct GNUNET_MessageHeader *hello)
Core handler for p2p HELLO messages.
static void cb_forwarded_dht_p2p_put(void *cls, enum GNUNET_GenericReturnValue forwarded)
static void handle_dht_p2p_get(void *cls, const struct PeerGetMessage *get)
Core handler for p2p get requests.
void GDS_NEIGHBOURS_broadcast(const struct GNUNET_MessageHeader *msg)
Send msg to all peers in our buckets.
#define FIND_PEER_REPLICATION_LEVEL
Desired replication level for FIND PEER requests.
static unsigned int get_forward_count(uint16_t hop_count, uint16_t target_replication)
To how many peers should we (on average) forward the request to obtain the desired target_replication...
static void do_send(struct PeerInfo *pi, const struct GNUNET_MessageHeader *msg)
Send msg to pi.
static int find_bucket(const struct GNUNET_HashCode *hc)
Find the optimal bucket for this key.
static enum GNUNET_GenericReturnValue check_dht_p2p_put(void *cls, const struct PeerPutMessage *put)
Check validity of a p2p put request.
static struct GNUNET_CONTAINER_MultiPeerMap * all_connected_peers
Hash map of all CORE-connected peers, for easy removal from k_buckets on disconnect.
static void handle_local_result(void *cls, const struct GNUNET_DATACACHE_Block *bd)
Handle an exact result from local datacache for a GET operation.
static void cb_handle_dht_p2p_get_my_hello(void *cls)
#define DHT_MINIMUM_FIND_PEER_INTERVAL
How long at least to wait before sending another find peer request.
static int cache_results
Do we cache all results that we are routing in the local datacache?
void GDS_u_connect(void *cls, struct GNUNET_DHTU_Target *target, const struct GNUNET_PeerIdentity *pid, void **ctx)
Function to call when we connect to a peer and can henceforth transmit to that peer.
static enum GNUNET_GenericReturnValue check_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Check validity of p2p result message.
static struct GNUNET_SCHEDULER_Task * find_peer_task
Task that sends FIND PEER requests.
static bool cb_routing_put_message(void *cls, size_t msize, struct PeerPutMessage *ppm)
#define MAX_BUCKETS
How many buckets will we allow in total.
static enum GNUNET_GenericReturnValue check_dht_p2p_get(void *cls, const struct PeerGetMessage *get)
Check validity of p2p get request.
static enum GNUNET_GenericReturnValue check_dht_p2p_hello(void *cls, const struct GNUNET_MessageHeader *hello)
Check validity of a p2p hello message.
static void cb_handle_dht_p2p_get_local_hello(void *cls)
static unsigned int get_target_peers(const struct GNUNET_HashCode *key, struct GNUNET_CONTAINER_BloomFilter *bloom, uint16_t hop_count, uint16_t target_replication, struct PeerInfo ***targets)
Compute the set of peers that the given request should be forwarded to.
static void hello_check(const struct GNUNET_DATACACHE_Block *bd)
If we got a HELLO, consider it for our own routing table.
static void safe_neighbours_callback(void *cls, GNUNET_SCHEDULER_TaskCallback cb, bool success)
static enum GNUNET_GenericReturnValue add_known_to_bloom(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Add each of the peers we already know to the Bloom filter of the request so that we don't get duplica...
static void handle_find_local_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
We have received a request for nearby HELLOs.
static unsigned int bucket_size
Maximum size for each bucket.
static void process_reply_with_path(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Process a reply, after the get_path has been updated.
enum GNUNET_GenericReturnValue GDS_am_closest_peer(const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom)
Check whether my identity is closer than any known peers.
static unsigned int closest_bucket
The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
static bool cb_path_signed(void *cls, const struct GNUNET_CRYPTO_EddsaSignature *sig)
static struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
The buckets.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init()
Initialize neighbours subsystem.
static void cb_handle_dht_p2p_get_local_result(void *cls)
static void update_hold(struct PeerBucket *bucket)
The list of the first bucket_size peers of bucket changed.
void GDS_u_receive(void *cls, void **tctx, void **sctx, const void *message, size_t message_size)
Function to call when we receive a message.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_get(enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint16_t desired_replication_level, uint16_t hop_count, const struct GNUNET_HashCode *key, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, struct GNUNET_CONTAINER_BloomFilter *peer_bf)
Perform a GET operation.
void GDS_NEIGHBOURS_handle_put(const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf, GDS_PutOperationCallback cb, void *cb_cls)
Perform a PUT operation.
const struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id()
Get the ID of the local node.
static void handle_dht_p2p_put(void *cls, const struct PeerPutMessage *put)
Core handler for p2p put requests.
#define DHT_AVG_FIND_PEER_INTERVAL
How long to additionally wait on average per bucket_size to send out the FIND PEER requests if we did...
GNUnet DHT routing code.
void(* GDS_PutOperationCallback)(void *cls, enum GNUNET_GenericReturnValue forwarded)
void GDS_ROUTING_add(const struct GNUNET_PeerIdentity *sender, enum GNUNET_BLOCK_Type type, struct GNUNET_BLOCK_Group *bg, enum GNUNET_DHT_RouteOption options, const struct GNUNET_HashCode *key, const void *xquery, size_t xquery_size)
Add a new entry to our routing table.
void GDS_ROUTING_process(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Handle a reply (route to origin).
GNUnet DHT tracking of requests for routing replies.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static struct GNUNET_VPN_Handle * handle
Handle to vpn service.
Definition gnunet-vpn.c:35
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
@ GNUNET_BLOCK_TYPE_ANY
Identifier for any block.
@ GNUNET_BLOCK_TYPE_DHT_HELLO
Type of a block that contains a DHT-NG HELLO for a peer.
API to the DHT service.
Helper library for handling HELLO URIs.
const struct GNUNET_HashCode * GNUNET_PILS_get_identity_hash(const struct GNUNET_PILS_Handle *handle)
Return the hash of the current peer identity from a given handle.
Definition pils_api.c:736
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
Constants for network protocols.
API to schedule computations using continuation passing style.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_BLOCK_group_set_seen(struct GNUNET_BLOCK_Group *bg, const struct GNUNET_HashCode *seen_results, unsigned int seen_results_count)
Update block group to filter out the given results.
Definition block.c:365
enum GNUNET_BLOCK_ReplyEvaluationResult GNUNET_BLOCK_check_reply(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, struct GNUNET_BLOCK_Group *group, const struct GNUNET_HashCode *query, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size)
Function called to validate if a reply is good for a particular query.
Definition block.c:339
enum GNUNET_GenericReturnValue GNUNET_BLOCK_check_block(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size)
Function called to validate a block.
Definition block.c:321
enum GNUNET_GenericReturnValue GNUNET_BLOCK_check_query(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode *query, const void *xquery, size_t xquery_size)
Function called to validate a request.
Definition block.c:298
GNUNET_BLOCK_ReplyEvaluationResult
Possible ways for how a block may relate to a query.
void GNUNET_BLOCK_group_destroy(struct GNUNET_BLOCK_Group *bg)
Destroy resources used by a block group.
Definition block.c:194
enum GNUNET_GenericReturnValue GNUNET_BLOCK_group_serialize(struct GNUNET_BLOCK_Group *bg, void **raw_data, size_t *raw_data_size)
Serialize state of a block group.
Definition block.c:177
struct GNUNET_BLOCK_Group * GNUNET_BLOCK_group_create(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *raw_data, size_t raw_data_size,...)
Create a new block group.
Definition block.c:249
enum GNUNET_GenericReturnValue GNUNET_BLOCK_get_key(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, struct GNUNET_HashCode *key)
Function called to obtain the key for a block.
Definition block.c:278
@ GNUNET_BLOCK_REPLY_OK_MORE
Valid result, and there may be more.
@ GNUNET_BLOCK_REPLY_OK_LAST
Last possible valid result.
struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_init(const char *data, size_t size, unsigned int k)
Create a Bloom filter from raw bits.
void GNUNET_CONTAINER_bloomfilter_add(struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Add an element to the filter.
bool GNUNET_CONTAINER_bloomfilter_test(const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Test if an element is in the filter.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_bloomfilter_get_raw_data(const struct GNUNET_CONTAINER_BloomFilter *bf, char *data, size_t size)
Copy the raw data of this Bloom filter into the given data array.
void GNUNET_CONTAINER_bloomfilter_free(struct GNUNET_CONTAINER_BloomFilter *bf)
Free the space associated with a filter in memory, flush to drive if needed (do not free the space on...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
#define GNUNET_CONSTANTS_BLOOMFILTER_K
K-value that must be used for the bloom filters in 'GET' queries.
uint64_t GNUNET_CRYPTO_random_u64(uint64_t max)
Generate a random unsigned 64-bit value.
uint32_t GNUNET_CRYPTO_random_u32(uint32_t i)
Produce a random value.
GNUNET_DHT_RouteOption
Options for routing.
#define GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL
Maximum allowed replication level for all requests.
unsigned int GNUNET_DHT_verify_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *trunc_peer, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_len, const struct GNUNET_DHT_PathElement *get_path, unsigned int get_path_len, const struct GNUNET_PeerIdentity *me)
Verify signatures on a path consisting of put_path and get_path in reverse order (starting at the las...
Definition dht_api.c:1354
@ GNUNET_DHT_RO_TRUNCATED
Flag set if the path was truncated.
@ GNUNET_DHT_RO_RECORD_ROUTE
We should keep track of the route that the message took in the P2P network.
@ GNUNET_DHT_RO_LAST_HOP
Flag given to monitors if this was the last hop for a GET/PUT.
@ GNUNET_DHT_RO_FIND_APPROXIMATE
Approximate results are fine.
@ GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
Each peer along the way should process the request (otherwise only peers locally closest to the key w...
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:40
void GNUNET_CRYPTO_hash_xor(const struct GNUNET_HashCode *a, const struct GNUNET_HashCode *b, struct GNUNET_HashCode *result)
compute result = a ^ b
int GNUNET_CRYPTO_hash_xorcmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2, const struct GNUNET_HashCode *target)
Find out which of the two GNUNET_CRYPTO_hash codes is closer to target in the XOR metric (Kademlia).
void * GNUNET_CONTAINER_multipeermap_get(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Given a key find a value in the map matching the key.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
unsigned int GNUNET_CONTAINER_multipeermap_size(const struct GNUNET_CONTAINER_MultiPeerMap *map)
Get the number of key-value pairs in the map.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
void GNUNET_HELLO_parser_free(struct GNUNET_HELLO_Parser *parser)
Release resources of a builder.
Definition hello-uri.c:380
enum GNUNET_GenericReturnValue GNUNET_HELLO_dht_msg_to_block(const struct GNUNET_MessageHeader *hello, const struct GNUNET_PeerIdentity *pid, void **block, size_t *block_size, struct GNUNET_TIME_Absolute *block_expiration)
Convert a DHT hello message to a HELLO block.
Definition hello-uri.c:1044
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_iterate(const struct GNUNET_HELLO_Parser *parser, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a parser.
Definition hello-uri.c:1022
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
struct GNUNET_HELLO_Parser * GNUNET_HELLO_parser_from_block(const void *block, size_t block_size)
Parse block.
Definition hello-uri.c:560
unsigned int GNUNET_CRYPTO_hash_count_leading_zeros(const struct GNUNET_HashCode *h)
Count the number of leading 0 bits in h.
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
#define GNUNET_MAX(a, b)
#define GNUNET_NZL(l)
Macro used to avoid using 0 for the length of a variable-size array (Non-Zero-Length).
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
#define GNUNET_MIN(a, b)
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_PACKED
gcc-ism to get packed structs.
uint32_t bits[512/8/sizeof(uint32_t)]
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
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.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#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.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
enum GNUNET_GenericReturnValue GNUNET_MQ_handle_message(const struct GNUNET_MQ_MessageHandler *handlers, const struct GNUNET_MessageHeader *mh)
Call the message message handler that was registered for the type of the given message in the given h...
Definition mq.c:205
#define GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO
HELLO advertising a neighbours addresses.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
Data is returned to peer from DHT.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_GET
Peer tries to find data in DHT.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
Peer is storing data in DHT.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
void(* GNUNET_SCHEDULER_TaskCallback)(void *cls)
Signature of the main function of a task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition time.c:737
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition time.c:583
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition time.c:486
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
const struct GNUNET_HashCode * query_hash
struct GNUNET_BLOCK_Group * bg
struct GNUNET_DATACACHE_Block block
struct GNUNET_DHT_PathElement * put_path
struct GNUNET_DHT_PathElement * paths
struct GNUNET_PeerIdentity trunc_peer_id
struct PeerResultMessage * prm
GNUNET_SCHEDULER_TaskCallback cb
struct GNUNET_DHT_PathElement * put_path
struct GNUNET_DATACACHE_Block bd
Information we keep per underlay.
Internal representation of the hash map.
an ECC signature using EdDSA.
Information about a block stored in the datacache.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
enum GNUNET_DHT_RouteOption ro
Options for routing for the block.
struct GNUNET_PeerIdentity trunc_peer
If the path was truncated, this is the peer ID at which the path was truncated.
struct GNUNET_HashCode key
Key of the block.
size_t data_size
Number of bytes in data.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
Opaque handle expressing a preference of the DHT to keep a particular target connected.
Opaque handle that the underlay offers for the target peer when sending messages to another peer.
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).
struct GNUNET_CRYPTO_EddsaSignature sig
Signature affirming the hop of type GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
Context for parsing HELLOs.
Definition hello-uri.c:233
A 512-bit hashcode.
Message handler for a specific message type.
Header for all communications.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition scheduler.c:141
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition scheduler.c:145
Time for absolute time used by GNUnet, in microseconds and in network byte order.
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
struct GNUNET_CONTAINER_BloomFilter * peer_bf
struct GNUNET_BLOCK_Group * bg
enum GNUNET_BLOCK_ReplyEvaluationResult eval
GNUNET_SCHEDULER_TaskCallback cb
Peers are grouped into buckets.
struct PeerInfo * head
Head of DLL.
struct PeerInfo * tail
Tail of DLL.
unsigned int peers_size
Number of peers in the bucket.
uint16_t result_filter_size
Size of the result filter.
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_GET.
uint16_t desired_replication_level
Desired replication level for this request.
uint16_t options
Processing options.
struct GNUNET_HashCode key
The key we are looking for.
uint32_t type
Desired content type.
Entry for a peer in a bucket.
struct GNUNET_TIME_Absolute hello_expiration
When does our HELLO from this peer expire?
size_t hello_size
Number of bytes in hello.
struct PeerInfo * next
Next peer entry (DLL)
struct GNUNET_PeerIdentity id
What is the identity of the peer?
struct Target * t_tail
Tail of DLL of targets for this peer.
struct PeerInfo * prev
Prev peer entry (DLL)
struct GNUNET_HashCode phash
Hash of id.
int peer_bucket
Which bucket is this peer in?
struct Target * t_head
Head of DLL of targets for this peer.
void * hello
Block with a HELLO of this peer.
P2P PUT message.
Definition dht.h:429
uint16_t desired_replication_level
Replication level for this message.
Definition dht.h:453
uint16_t hop_count
Hop count.
Definition dht.h:448
uint32_t type
Content type, must not be zero.
Definition dht.h:438
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
Definition dht.h:468
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT.
Definition dht.h:433
struct GNUNET_HashCode key
The key we are storing under.
Definition dht.h:473
uint16_t options
Processing options.
Definition dht.h:443
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
Definition dht.h:463
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
Definition dht.h:458
uint16_t get_path_length
Length of the GET path that follows (if tracked).
uint16_t options
Message options, actually an 'enum GNUNET_DHT_RouteOption' value in NBO.
struct GNUNET_HashCode key
The key of the corresponding GET request.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT.
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
List of targets that we can use to reach this peer.
struct Target * prev
Kept in a DLL.
struct PeerInfo * pi
Peer this is a target for.
struct Target * next
Kept in a DLL.
unsigned int load
Set to number of messages are waiting for the transmission to finish.
struct GNUNET_DHTU_PreferenceHandle * ph
Handle used to 'hold' the connection to this peer.
struct GDS_Underlay * u
Underlay providing this target.
struct GNUNET_DHTU_Target * utarget
Handle for sending messages to this peer.
bool dropped
Set to true if the target was dropped, but we could not clean up yet because busy was also true.