GNUnet 0.21.2
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 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 "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_protocols.h"
30#include "gnunet_signatures.h"
32#include "gnunet-service-dht.h"
35#include "dht.h"
36
37#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
38 __VA_ARGS__)
39
51#define SANITY_CHECKS 2
52
56#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
57
61#define DEFAULT_BUCKET_SIZE 8
62
66#define FIND_PEER_REPLICATION_LEVEL 4
67
71#define MAXIMUM_PENDING_PER_PEER 64
72
78#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
79 GNUNET_TIME_UNIT_MINUTES, 2)
80
81
91#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
92 GNUNET_TIME_UNIT_SECONDS, 6)
93
97#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
98
99
101
106{
111
116
121
126
131
136
141
146
151
152 /* trunc_peer (if truncated) */
153
154 /* put path (if tracked) */
155
156 /* sender_sig (if path tracking is on) */
157
158 /* Payload */
159};
160
161
166{
171
176
181
186
191
196
201
206
207 /* trunc_peer (if truncated) */
208
209 /* put path (if tracked) */
210
211 /* get path (if tracked) */
212
213 /* sender_sig (if path tracking is on) */
214
215 /* Payload */
216};
217
218
223{
228
233
238
243
248
253
258
263
264 /* result bloomfilter */
265
266 /* xquery */
267
268};
270
271
275struct PeerInfo;
276
277
281struct Target
282{
286 struct Target *next;
287
291 struct Target *prev;
292
297
302
306 struct PeerInfo *pi;
307
312
316 unsigned int load;
317
323
324};
325
326
331{
336
341
346
350 struct PeerInfo *next;
351
355 struct PeerInfo *prev;
356
360 struct Target *t_head;
361
365 struct Target *t_tail;
366
370 void *hello;
371
376
381};
382
383
388{
392 struct PeerInfo *head;
393
397 struct PeerInfo *tail;
398
402 unsigned int peers_size;
403};
404
405
409static int cache_results;
410
414static unsigned int closest_bucket;
415
420static unsigned int newly_found_peers;
421
426
431
437
441static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
442
447
448
456static void
457send_done_cb (void *cls)
458{
459 struct Target *t = cls;
460 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
461
462 GNUNET_assert (t->load > 0);
463 t->load--;
464 if (0 < t->load)
465 return;
466 if (t->dropped)
467 {
468 GNUNET_free (t);
469 return;
470 }
471 /* move target back to the front */
473 pi->t_tail,
474 t);
476 pi->t_tail,
477 t);
478}
479
480
487static void
488do_send (struct PeerInfo *pi,
489 const struct GNUNET_MessageHeader *msg)
490{
491 struct Target *t;
492
493 for (t = pi->t_head;
494 NULL != t;
495 t = t->next)
496 if (t->load < MAXIMUM_PENDING_PER_PEER)
497 break;
498 if (NULL == t)
499 {
500 /* all targets busy, drop message */
502 "# messages dropped (underlays busy)",
503 1,
504 GNUNET_NO);
505 return;
506 }
507 t->load++;
508 /* rotate busy targets to the end */
509 if (MAXIMUM_PENDING_PER_PEER == t->load)
510 {
512 pi->t_tail,
513 t);
515 pi->t_tail,
516 t);
517 }
518 GDS_u_send (t->u,
519 t->utarget,
520 msg,
521 ntohs (msg->size),
523 t);
524}
525
526
539static void
540sign_path (const void *data,
541 size_t data_size,
542 struct GNUNET_TIME_Absolute exp_time,
543 const struct GNUNET_PeerIdentity *pred,
544 const struct GNUNET_PeerIdentity *succ,
546{
547 struct GNUNET_DHT_HopSignature hs = {
549 .purpose.size = htonl (sizeof (hs)),
550 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
551 .succ = *succ
552 };
553
554 if (NULL != pred)
555 hs.pred = *pred;
557 data_size,
558 &hs.h_data);
560 &hs,
561 sig);
562}
563
564
572static int
573find_bucket (const struct GNUNET_HashCode *hc)
574{
575 struct GNUNET_HashCode xor;
576 unsigned int bits;
577
580 &xor);
582 if (bits == MAX_BUCKETS)
583 {
584 /* How can all bits match? Got my own ID? */
585 GNUNET_break (0);
586 return -1;
587 }
588 return MAX_BUCKETS - bits - 1;
589}
590
591
603 const struct GNUNET_PeerIdentity *key,
604 void *value)
605{
606 struct GNUNET_BLOCK_Group *bg = cls;
607 struct PeerInfo *pi = value;
608
610 &pi->phash,
611 1);
613 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
614 GNUNET_i2s (key));
615 return GNUNET_YES;
616}
617
618
626static void
628{
629 (void) cls;
630
631 /* Compute when to do this again (and if we should
632 even send a message right now) */
633 {
634 struct GNUNET_TIME_Relative next_send_time;
635 bool done_early;
636
637 find_peer_task = NULL;
638 done_early = (newly_found_peers > bucket_size);
639 /* schedule next round, taking longer if we found more peers
640 in the last round. */
641 next_send_time.rel_value_us =
647 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
651 GNUNET_SCHEDULER_add_delayed (next_send_time,
653 NULL);
654 if (done_early)
655 return;
656 }
657
658 /* actually send 'find peer' request */
659 {
660 struct GNUNET_BLOCK_Group *bg;
661 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
662
665 NULL,
666 0,
667 "seen-set-size",
670 NULL);
673 bg);
674 peer_bf
678 if (GNUNET_OK !=
683 0, /* hop count */
685 NULL, 0, /* xquery */
686 bg,
687 peer_bf))
688 {
690 "# Failed to initiate FIND PEER lookup",
691 1,
692 GNUNET_NO);
693 }
694 else
695 {
697 "# FIND PEER messages initiated",
698 1,
699 GNUNET_NO);
700 }
703 }
704}
705
706
714static void
715update_hold (struct PeerBucket *bucket)
716{
717 unsigned int off = 0;
718
719 /* find the peer -- we just go over all of them, should
720 be hardly any more expensive than just finding the 'right'
721 one. */
722 for (struct PeerInfo *pos = bucket->head;
723 NULL != pos;
724 pos = pos->next)
725 {
726 if (off > bucket_size)
727 break; /* We only hold up to #bucket_size peers per bucket */
728 off++;
729 for (struct Target *tp = pos->t_head;
730 NULL != tp;
731 tp = tp->next)
732 if (NULL == tp->ph)
733 tp->ph = GDS_u_hold (tp->u,
734 tp->utarget);
735 }
736}
737
738
739void
740GDS_u_connect (void *cls,
741 struct GNUNET_DHTU_Target *target,
742 const struct GNUNET_PeerIdentity *pid,
743 void **ctx)
744{
745 struct GDS_Underlay *u = cls;
746 struct PeerInfo *pi;
747 struct PeerBucket *bucket;
748 bool do_hold = false;
749
750 /* Check for connect to self message */
752 pid))
753 return;
755 "Connected to peer %s\n",
756 GNUNET_i2s (pid));
758 pid);
759 if (NULL == pi)
760 {
762 "# peers connected",
763 1,
764 GNUNET_NO);
765 pi = GNUNET_new (struct PeerInfo);
766 pi->id = *pid;
768 sizeof(*pid),
769 &pi->phash);
770 pi->peer_bucket = find_bucket (&pi->phash);
771 GNUNET_assert ( (pi->peer_bucket >= 0) &&
772 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
773 bucket = &k_buckets[pi->peer_bucket];
775 bucket->tail,
776 pi);
777 bucket->peers_size++;
779 (unsigned int) pi->peer_bucket + 1);
782 &pi->id,
783 pi,
785 if (bucket->peers_size <= bucket_size)
786 {
788 do_hold = true;
789 }
792 {
793 /* got a first connection, good time to start with FIND PEER requests... */
796 NULL);
797 }
798 }
799 {
800 struct Target *t;
801
802 t = GNUNET_new (struct Target);
803 t->u = u;
804 t->utarget = target;
805 t->pi = pi;
807 pi->t_tail,
808 t);
809 *ctx = t;
810
811 }
812 if (do_hold)
813 update_hold (bucket);
814}
815
816
817void
819{
820 struct Target *t = ctx;
821 struct PeerInfo *pi;
822 struct PeerBucket *bucket;
823 bool was_held = false;
824
825 /* Check for disconnect from self message (on shutdown) */
826 if (NULL == t)
827 return;
828 pi = t->pi;
830 pi->t_tail,
831 t);
832 if (NULL != t->ph)
833 {
834 GDS_u_drop (t->u,
835 t->ph);
836 t->ph = NULL;
837 was_held = true;
838 }
839 if (t->load > 0)
840 {
841 t->dropped = true;
842 t->pi = NULL;
843 }
844 else
845 {
846 GNUNET_free (t);
847 }
848 if (NULL != pi->t_head)
849 return; /* got other connections still */
851 "Disconnected from peer %s\n",
852 GNUNET_i2s (&pi->id));
854 "# peers connected",
855 -1,
856 GNUNET_NO);
859 &pi->id,
860 pi));
863 {
865 find_peer_task = NULL;
866 }
867 GNUNET_assert (pi->peer_bucket >= 0);
868 bucket = &k_buckets[pi->peer_bucket];
870 bucket->tail,
871 pi);
872 GNUNET_assert (bucket->peers_size > 0);
873 bucket->peers_size--;
874 if ( (was_held) &&
875 (bucket->peers_size >= bucket_size - 1) )
876 update_hold (bucket);
877 while ( (closest_bucket > 0) &&
880 GNUNET_free (pi->hello);
881 GNUNET_free (pi);
882}
883
884
893static unsigned int
894get_forward_count (uint16_t hop_count,
895 uint16_t target_replication)
896{
897 uint32_t random_value;
898 uint32_t forward_count;
899 float target_value;
900 float rm1;
901
902 if (hop_count > GDS_NSE_get () * 4.0)
903 {
904 /* forcefully terminate */
906 "# requests TTL-dropped",
907 1,
908 GNUNET_NO);
909 return 0;
910 }
911 if (hop_count > GDS_NSE_get () * 2.0)
912 {
913 /* Once we have reached our ideal number of hops, only forward to 1 peer */
914 return 1;
915 }
916 /* bound by system-wide maximum and minimum */
917 if (0 == target_replication)
918 target_replication = 1; /* 0 is verboten */
919 target_replication =
921 target_replication);
922 rm1 = target_replication - 1.0;
923 target_value =
924 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
925
926 /* Set forward count to floor of target_value */
927 forward_count = (uint32_t) target_value;
928 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
929 target_value = target_value - forward_count;
931 UINT32_MAX);
932 if (random_value < (target_value * UINT32_MAX))
933 forward_count++;
934 return GNUNET_MIN (forward_count,
936}
937
938
951 const struct GNUNET_CONTAINER_BloomFilter *bloom)
952{
954 key))
955 return GNUNET_YES;
956 for (int bucket_num = find_bucket (key);
957 bucket_num < closest_bucket;
958 bucket_num++)
959 {
960 unsigned int count = 0;
961
962 GNUNET_assert (bucket_num >= 0);
963 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
964 NULL != pos;
965 pos = pos->next)
966 {
967 if (count >= bucket_size)
968 break; /* we only consider first #bucket_size entries per bucket */
969 count++;
970 if ( (NULL != bloom) &&
971 (GNUNET_YES ==
973 &pos->phash)) )
974 continue; /* Ignore filtered peers */
975 /* All peers in this bucket must be closer than us, as
976 they mismatch with our PID on the pivotal bit. So
977 because an unfiltered peer exists, we are not the
978 closest. */
979 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
981 key);
982 switch (delta)
983 {
984 case -1: /* pos closer */
985 return GNUNET_NO;
986 case 0: /* identical, impossible! */
987 GNUNET_assert (0);
988 break;
989 case 1: /* I am closer */
990 break;
991 }
992 }
993 }
994 /* No closer (unfiltered) peers found; we must be the closest! */
995 return GNUNET_YES;
996}
997
998
1020static struct PeerInfo *
1022 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1023 uint32_t hops)
1024{
1025 if (0 == closest_bucket)
1026 {
1028 "# Peer selection failed",
1029 1,
1030 GNUNET_NO);
1031 return NULL; /* we have zero connections */
1032 }
1033 if (hops >= GDS_NSE_get ())
1034 {
1035 /* greedy selection (closest peer that is not in Bloom filter) */
1036 struct PeerInfo *chosen = NULL;
1037 int best_bucket;
1038 int bucket_offset;
1039
1040 {
1041 struct GNUNET_HashCode xor;
1042
1045 &xor);
1046 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1047 }
1048 if (best_bucket >= closest_bucket)
1049 bucket_offset = closest_bucket - 1;
1050 else
1051 bucket_offset = best_bucket;
1052 while (-1 != bucket_offset)
1053 {
1054 struct PeerBucket *bucket = &k_buckets[bucket_offset];
1055 unsigned int count = 0;
1056
1057 for (struct PeerInfo *pos = bucket->head;
1058 NULL != pos;
1059 pos = pos->next)
1060 {
1061 if (count >= bucket_size)
1062 break; /* we only consider first #bucket_size entries per bucket */
1063 count++;
1064 if ( (NULL != bloom) &&
1065 (GNUNET_YES ==
1067 &pos->phash)) )
1068 {
1070 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1071 GNUNET_i2s (&pos->id),
1072 GNUNET_h2s (key));
1073 continue;
1074 }
1075 if (NULL == chosen)
1076 {
1077 /* First candidate */
1078 chosen = pos;
1079 }
1080 else
1081 {
1082 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1083 &chosen->phash,
1084 key);
1085 switch (delta)
1086 {
1087 case -1: /* pos closer */
1088 chosen = pos;
1089 break;
1090 case 0: /* identical, impossible! */
1091 GNUNET_assert (0);
1092 break;
1093 case 1: /* chosen closer */
1094 break;
1095 }
1096 }
1097 count++;
1098 } /* for all (#bucket_size) peers in bucket */
1099 if (NULL != chosen)
1100 break;
1101
1102 /* If we chose nothing in first iteration, first go through deeper
1103 buckets (best chance to find a good match), and if we still found
1104 nothing, then to shallower buckets. Terminate on any match in the
1105 current bucket, as this search order guarantees that it can only get
1106 worse as we keep going. */
1107 if (bucket_offset > best_bucket)
1108 {
1109 /* Go through more deeper buckets */
1110 bucket_offset++;
1111 if (bucket_offset == closest_bucket)
1112 {
1113 /* Can't go any deeper, if nothing selected,
1114 go for shallower buckets */
1115 bucket_offset = best_bucket - 1;
1116 }
1117 }
1118 else
1119 {
1120 /* We're either at the 'best_bucket' or already moving
1121 on to shallower buckets. */
1122 if (bucket_offset == best_bucket)
1123 bucket_offset++; /* go for deeper buckets */
1124 else
1125 bucket_offset--; /* go for shallower buckets */
1126 }
1127 } /* for applicable buckets (starting at best match) */
1128 if (NULL == chosen)
1129 {
1131 "# Peer selection failed",
1132 1,
1133 GNUNET_NO);
1134 return NULL;
1135 }
1137 "Selected peer `%s' in greedy routing for %s\n",
1138 GNUNET_i2s (&chosen->id),
1139 GNUNET_h2s (key));
1140 return chosen;
1141 } /* end of 'greedy' peer selection */
1142
1143 /* select "random" peer */
1144 /* count number of peers that are available and not filtered,
1145 but limit to at most #bucket_size peers, starting with
1146 those 'furthest' from us. */
1147 {
1148 unsigned int total = 0;
1149 unsigned int selected;
1150
1151 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1152 {
1153 struct PeerBucket *bucket = &k_buckets[bc];
1154 unsigned int count = 0;
1155
1156 for (struct PeerInfo *pos = bucket->head;
1157 NULL != pos;
1158 pos = pos->next)
1159 {
1160 count++;
1161 if (count > bucket_size)
1162 break; /* limits search to #bucket_size peers per bucket */
1163 if ( (NULL != bloom) &&
1164 (GNUNET_YES ==
1166 &pos->phash)) )
1167 {
1169 "Excluded peer `%s' due to BF match in random routing for %s\n",
1170 GNUNET_i2s (&pos->id),
1171 GNUNET_h2s (key));
1172 continue; /* Ignore filtered peers */
1173 }
1174 total++;
1175 } /* for all peers in bucket */
1176 } /* for all buckets */
1177 if (0 == total) /* No peers to select from! */
1178 {
1180 "# Peer selection failed",
1181 1,
1182 GNUNET_NO);
1183 return NULL;
1184 }
1185
1186 /* Now actually choose a peer */
1188 total);
1189 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1190 {
1191 unsigned int count = 0;
1192
1193 for (struct PeerInfo *pos = k_buckets[bc].head;
1194 pos != NULL;
1195 pos = pos->next)
1196 {
1197 count++;
1198 if (count > bucket_size)
1199 break; /* limits search to #bucket_size peers per bucket */
1200
1201 if ( (NULL != bloom) &&
1202 (GNUNET_YES ==
1204 &pos->phash)) )
1205 continue; /* Ignore bloomfiltered peers */
1206 if (0 == selected--)
1207 {
1209 "Selected peer `%s' in random routing for %s\n",
1210 GNUNET_i2s (&pos->id),
1211 GNUNET_h2s (key));
1212 return pos;
1213 }
1214 } /* for peers in bucket */
1215 } /* for all buckets */
1216 } /* random peer selection scope */
1217 GNUNET_break (0);
1218 return NULL;
1219}
1220
1221
1235static unsigned int
1237 struct GNUNET_CONTAINER_BloomFilter *bloom,
1238 uint16_t hop_count,
1239 uint16_t target_replication,
1240 struct PeerInfo ***targets)
1241{
1242 unsigned int target;
1243 unsigned int off;
1244 struct PeerInfo **rtargets;
1245
1246 GNUNET_assert (NULL != bloom);
1247 target = get_forward_count (hop_count,
1248 target_replication);
1249 if (0 == target)
1250 {
1251 *targets = NULL;
1252 return 0;
1253 }
1254 rtargets = GNUNET_new_array (target,
1255 struct PeerInfo *);
1256 for (off = 0; off < target; off++)
1257 {
1258 struct PeerInfo *nxt;
1259
1260 nxt = select_peer (key,
1261 bloom,
1262 hop_count);
1263 if (NULL == nxt)
1264 break;
1265 rtargets[off] = nxt;
1268 &nxt->phash));
1270 &nxt->phash);
1271 }
1273 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1274 off,
1276 (unsigned int) hop_count,
1277 GNUNET_h2s (key),
1278 target);
1279 if (0 == off)
1280 {
1281 GNUNET_free (rtargets);
1282 *targets = NULL;
1283 return 0;
1284 }
1285 *targets = rtargets;
1287 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1288 GNUNET_h2s (key),
1289 off,
1290 target);
1291 return off;
1292}
1293
1294
1300static void
1302{
1303 struct GNUNET_HELLO_Builder *b;
1304
1306 return;
1307
1309 bd->data_size);
1311 {
1314 NULL);
1315 }
1317}
1318
1319
1322 uint16_t desired_replication_level,
1323 uint16_t hop_count,
1325{
1326 unsigned int target_count;
1327 struct PeerInfo **targets;
1328 size_t msize;
1329 unsigned int skip_count;
1330 enum GNUNET_DHT_RouteOption ro = bd->ro;
1331 unsigned int put_path_length = bd->put_path_length;
1332 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1333 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1334 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1335 const struct GNUNET_PeerIdentity *trunc_peer
1336 = truncated
1337 ? &bd->trunc_peer
1338 : NULL;
1339
1340#if SANITY_CHECKS > 1
1341 unsigned int failure_offset;
1342
1343 failure_offset
1345 bd->data_size,
1346 bd->expiration_time,
1347 trunc_peer,
1348 put_path,
1349 put_path_length,
1350 NULL, 0, /* get_path */
1352 if (0 != failure_offset)
1353 {
1354 GNUNET_break_op (0);
1355 truncated = true;
1356 trunc_peer = &put_path[failure_offset - 1].pred;
1357 put_path = &put_path[failure_offset];
1358 put_path_length = put_path_length - failure_offset;
1360 }
1361#endif
1363 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1365 GNUNET_h2s (&bd->key),
1366 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1367 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1368
1369 /* if we got a HELLO, consider it for our own routing table */
1370 hello_check (bd);
1371 GNUNET_assert (NULL != bf);
1375 "# PUT requests routed",
1376 1,
1377 GNUNET_NO);
1378 if (bd->data_size
1380 - sizeof(struct PeerPutMessage))
1381 {
1382 GNUNET_break (0);
1383 return GNUNET_SYSERR;
1384 }
1385 msize = bd->data_size + sizeof(struct PeerPutMessage);
1386 if (tracking)
1387 {
1388 if (msize + sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1390 {
1392 "Discarding message that is too large due to tracking\n");
1393 return GNUNET_NO;
1394 }
1395 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1396 }
1397 else
1398 {
1399 /* If tracking is disabled, also discard any path we might have
1400 gotten from some broken peer */
1401 GNUNET_break_op (0 == put_path_length);
1402 put_path_length = 0;
1403 }
1404 if (truncated)
1405 msize += sizeof (struct GNUNET_PeerIdentity);
1406 if (msize + put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1408 {
1409 unsigned int mlen;
1410 unsigned int ppl;
1411
1413 "Truncating path that is too large due\n");
1415 if (! truncated)
1416 {
1417 /* We need extra space for the truncation, consider that,
1418 too! */
1419 truncated = true;
1420 mlen -= sizeof (struct GNUNET_PeerIdentity);
1421 msize += sizeof (struct GNUNET_PeerIdentity);
1422 }
1423 /* compute maximum length of path we can keep */
1424 ppl = mlen / sizeof (struct GNUNET_DHT_PathElement);
1425 GNUNET_assert (put_path_length - ppl > 0);
1426 trunc_peer = &put_path[put_path_length - ppl - 1].pred;
1427 put_path = &put_path[put_path_length - ppl];
1428 put_path_length = ppl;
1430 }
1431 else
1432 {
1433 msize += bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement);
1434 }
1435 target_count
1436 = get_target_peers (&bd->key,
1437 bf,
1438 hop_count,
1439 desired_replication_level,
1440 &targets);
1441 if (0 == target_count)
1442 {
1444 "Routing PUT for %s terminates after %u hops at %s\n",
1445 GNUNET_h2s (&bd->key),
1446 (unsigned int) hop_count,
1448 return GNUNET_NO;
1449 }
1450 skip_count = 0;
1451 for (unsigned int i = 0; i < target_count; i++)
1452 {
1453 struct PeerInfo *target = targets[i];
1454 struct PeerPutMessage *ppm;
1455 char buf[msize] GNUNET_ALIGN;
1456 struct GNUNET_DHT_PathElement *pp;
1457 void *data;
1458
1460 "Routing PUT for %s after %u hops to %s\n",
1461 GNUNET_h2s (&bd->key),
1462 (unsigned int) hop_count,
1463 GNUNET_i2s (&target->id));
1464 ppm = (struct PeerPutMessage *) buf;
1466 ppm->header.size = htons (sizeof (buf));
1467 ppm->type = htonl (bd->type);
1468 ppm->options = htons (ro);
1469 ppm->hop_count = htons (hop_count + 1);
1471 ppm->put_path_length = htons (put_path_length);
1475 &target->phash));
1478 ppm->bloomfilter,
1480 ppm->key = bd->key;
1481 if (truncated)
1482 {
1483 void *tgt = &ppm[1];
1484
1485 GNUNET_memcpy (tgt,
1486 trunc_peer,
1487 sizeof (struct GNUNET_PeerIdentity));
1488 pp = (struct GNUNET_DHT_PathElement *)
1489 (tgt + sizeof (struct GNUNET_PeerIdentity));
1490 }
1491 else
1492 {
1493 pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1494 }
1495 GNUNET_memcpy (pp,
1496 put_path,
1497 sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1498 if (tracking)
1499 {
1500 void *tgt = &pp[put_path_length];
1501 struct GNUNET_CRYPTO_EddsaSignature last_sig;
1502
1503 if (0 == put_path_length)
1504 {
1505 /* Note that the signature in 'put_path' was not initialized before,
1506 so this is crucial to avoid sending garbage. */
1507 sign_path (bd->data,
1508 bd->data_size,
1509 bd->expiration_time,
1510 trunc_peer,
1511 &target->id,
1512 &last_sig);
1513 }
1514 else
1515 {
1516 sign_path (bd->data,
1517 bd->data_size,
1518 bd->expiration_time,
1519 &pp[put_path_length - 1].pred,
1520 &target->id,
1521 &last_sig);
1522 }
1524 "Signing PUT PATH %u => %s\n",
1525 put_path_length,
1526 GNUNET_B2S (&last_sig));
1527 memcpy (tgt,
1528 &last_sig,
1529 sizeof (last_sig));
1530 data = tgt + sizeof (last_sig);
1531 }
1532 else /* ! tracking */
1533 {
1534 data = &ppm[1];
1535 }
1537 bd->data,
1538 bd->data_size);
1539 do_send (target,
1540 &ppm->header);
1541 }
1542 GNUNET_free (targets);
1544 "# PUT messages queued for transmission",
1545 target_count - skip_count,
1546 GNUNET_NO);
1547 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1548}
1549
1550
1554 uint16_t desired_replication_level,
1555 uint16_t hop_count,
1556 const struct GNUNET_HashCode *key,
1557 const void *xquery,
1558 size_t xquery_size,
1559 struct GNUNET_BLOCK_Group *bg,
1560 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1561{
1562 unsigned int target_count;
1563 struct PeerInfo **targets;
1564 size_t msize;
1565 size_t result_filter_size;
1566 void *result_filter;
1567 unsigned int skip_count;
1568
1569 GNUNET_assert (NULL != peer_bf);
1571 "# GET requests routed",
1572 1,
1573 GNUNET_NO);
1574 target_count = get_target_peers (key,
1575 peer_bf,
1576 hop_count,
1577 desired_replication_level,
1578 &targets);
1580 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1582 GNUNET_h2s (key),
1584 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1585
1588 if (0 == target_count)
1589 {
1591 "Routing GET for %s terminates after %u hops at %s\n",
1592 GNUNET_h2s (key),
1593 (unsigned int) hop_count,
1595 return GNUNET_NO;
1596 }
1597 if (GNUNET_OK !=
1599 &result_filter,
1600 &result_filter_size))
1601 {
1602 result_filter = NULL;
1603 result_filter_size = 0;
1604 }
1605 msize = xquery_size + result_filter_size;
1606 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1607 {
1608 GNUNET_break (0);
1609 GNUNET_free (result_filter);
1610 GNUNET_free (targets);
1611 return GNUNET_NO;
1612 }
1613 /* forward request */
1614 skip_count = 0;
1615 for (unsigned int i = 0; i < target_count; i++)
1616 {
1617 struct PeerInfo *target = targets[i];
1618 struct PeerGetMessage *pgm;
1619 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1620 char *rf;
1621
1623 "Routing GET for %s after %u hops to %s\n",
1624 GNUNET_h2s (key),
1625 (unsigned int) hop_count,
1626 GNUNET_i2s (&target->id));
1627 pgm = (struct PeerGetMessage *) buf;
1629 pgm->header.size = htons (sizeof (buf));
1630 pgm->type = htonl (type);
1631 pgm->options = htons (options);
1632 pgm->hop_count = htons (hop_count + 1);
1634 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1637 &target->phash));
1640 pgm->bloomfilter,
1642 pgm->key = *key;
1643 rf = (char *) &pgm[1];
1644 GNUNET_memcpy (rf,
1645 result_filter,
1648 xquery,
1649 xquery_size);
1650 do_send (target,
1651 &pgm->header);
1652 }
1654 "# GET messages queued for transmission",
1655 target_count - skip_count,
1656 GNUNET_NO);
1657 GNUNET_free (targets);
1658 GNUNET_free (result_filter);
1659 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1660}
1661
1662
1663struct PeerInfo *
1665{
1667 target);
1668}
1669
1670
1671bool
1673 const struct GNUNET_DATACACHE_Block *bd,
1674 const struct GNUNET_HashCode *query_hash,
1675 unsigned int get_path_length,
1676 const struct GNUNET_DHT_PathElement *get_path)
1677{
1678 struct GNUNET_DHT_PathElement *paths;
1679 size_t msize;
1680 unsigned int ppl = bd->put_path_length;
1681 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1682 enum GNUNET_DHT_RouteOption ro = bd->ro;
1683 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1684 const struct GNUNET_PeerIdentity *trunc_peer
1685 = truncated
1686 ? &bd->trunc_peer
1687 : NULL;
1688 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1689#if SANITY_CHECKS > 1
1690 unsigned int failure_offset;
1691
1692 failure_offset
1694 bd->data_size,
1695 bd->expiration_time,
1696 trunc_peer,
1697 put_path,
1698 ppl,
1699 get_path,
1700 get_path_length,
1702 if (0 != failure_offset)
1703 {
1704 GNUNET_assert (failure_offset <= ppl + get_path_length);
1705 GNUNET_break_op (0);
1706 if (failure_offset < ppl)
1707 {
1708 trunc_peer = &put_path[failure_offset - 1].pred;
1709 put_path += failure_offset;
1710 ppl -= failure_offset;
1711 truncated = true;
1713 }
1714 else
1715 {
1716 failure_offset -= ppl;
1717 if (0 == failure_offset)
1718 trunc_peer = &put_path[ppl - 1].pred;
1719 else
1720 trunc_peer = &get_path[failure_offset - 1].pred;
1721 ppl = 0;
1722 put_path = NULL;
1723 truncated = true;
1725 get_path += failure_offset;
1726 get_path_length -= failure_offset;
1727 }
1728 }
1729#endif
1730 msize = bd->data_size + sizeof (struct PeerResultMessage);
1731 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1732 {
1733 GNUNET_break_op (0);
1734 return false;
1735 }
1736 if (truncated)
1737 msize += sizeof (struct GNUNET_PeerIdentity);
1738 if (tracking)
1739 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1740 if (msize < bd->data_size)
1741 {
1742 GNUNET_break_op (0);
1743 return false;
1744 }
1745 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1746 / sizeof(struct GNUNET_DHT_PathElement)
1747 < (get_path_length + ppl) )
1748 {
1749 get_path_length = 0;
1750 ppl = 0;
1751 }
1752 if ( (get_path_length > UINT16_MAX) ||
1753 (ppl > UINT16_MAX) )
1754 {
1755 GNUNET_break (0);
1756 get_path_length = 0;
1757 ppl = 0;
1758 }
1759 msize += (get_path_length + ppl)
1760 * sizeof(struct GNUNET_DHT_PathElement);
1762 "Forwarding reply for key %s to peer %s\n",
1763 GNUNET_h2s (query_hash),
1764 GNUNET_i2s (&pi->id));
1766 "# RESULT messages queued for transmission",
1767 1,
1768 GNUNET_NO);
1769 {
1770 struct PeerResultMessage *prm;
1771 char buf[msize] GNUNET_ALIGN;
1772 void *data;
1773
1774 prm = (struct PeerResultMessage *) buf;
1776 prm->header.size = htons (sizeof (buf));
1777 prm->type = htonl ((uint32_t) bd->type);
1778 prm->reserved = htons (0);
1779 prm->options = htons ((uint16_t) ro);
1780 prm->put_path_length = htons ((uint16_t) ppl);
1781 prm->get_path_length = htons ((uint16_t) get_path_length);
1783 prm->key = *query_hash;
1784 if (truncated)
1785 {
1786 void *tgt = &prm[1];
1787
1788 GNUNET_memcpy (tgt,
1789 trunc_peer,
1790 sizeof (struct GNUNET_PeerIdentity));
1791 paths = (struct GNUNET_DHT_PathElement *)
1792 (tgt + sizeof (struct GNUNET_PeerIdentity));
1793 }
1794 else
1795 {
1796 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1797 }
1798 if (NULL != put_path)
1799 {
1800 GNUNET_memcpy (paths,
1801 put_path,
1802 ppl * sizeof(struct GNUNET_DHT_PathElement));
1803 }
1804 else
1805 {
1806 GNUNET_assert (0 == ppl);
1807 }
1808 if (NULL != get_path)
1809 {
1810 GNUNET_memcpy (&paths[ppl],
1811 get_path,
1812 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1813 }
1814 else
1815 {
1816 GNUNET_assert (0 == get_path_length);
1817 }
1818 if (tracking)
1819 {
1821 void *tgt = &paths[get_path_length + ppl];
1822 const struct GNUNET_PeerIdentity *pred;
1823
1824 if (ppl + get_path_length > 0)
1825 pred = &paths[ppl + get_path_length - 1].pred;
1826 else if (truncated)
1827 pred = trunc_peer;
1828 else
1829 pred = NULL; /* we are first! */
1830 /* Note that the last signature in 'paths' was not initialized before,
1831 so this is crucial to avoid sending garbage. */
1832 sign_path (bd->data,
1833 bd->data_size,
1834 bd->expiration_time,
1835 pred,
1836 &pi->id,
1837 &sig);
1838 memcpy (tgt,
1839 &sig,
1840 sizeof (sig));
1841 data = tgt + sizeof (sig);
1843 "Signing GET PATH %u/%u of %s => %s\n",
1844 ppl,
1845 get_path_length,
1846 GNUNET_h2s (query_hash),
1847 GNUNET_B2S (&sig));
1848#if SANITY_CHECKS > 1
1849 {
1850 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1851
1852 memcpy (xpaths,
1853 &paths[ppl],
1854 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1855 xpaths[get_path_length].sig = sig;
1856 xpaths[get_path_length].pred = GDS_my_identity;
1857 if (0 !=
1859 bd->data_size,
1860 bd->expiration_time,
1861 trunc_peer,
1862 paths,
1863 ppl,
1864 xpaths,
1865 get_path_length + 1,
1866 &pi->id))
1867 {
1868 GNUNET_break (0);
1869 return false;
1870 }
1871 }
1872#endif
1873 }
1874 else
1875 {
1876 data = &prm[1];
1877 }
1879 bd->data,
1880 bd->data_size);
1881 do_send (pi,
1882 &prm->header);
1883 }
1884 return true;
1885}
1886
1887
1895static enum GNUNET_GenericReturnValue
1897 const struct PeerPutMessage *put)
1898{
1900 = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1901 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1902 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1903 uint16_t msize = ntohs (put->header.size);
1904 uint16_t putlen = ntohs (put->put_path_length);
1905 size_t xsize = (has_path
1906 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1907 : 0)
1908 + (truncated
1909 ? sizeof (struct GNUNET_PeerIdentity)
1910 : 0);
1911 size_t var_meta_size
1912 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1913 + xsize;
1914
1915 (void) cls;
1916 if ( (msize <
1917 sizeof (struct PeerPutMessage) + var_meta_size) ||
1918 (putlen >
1919 (GNUNET_MAX_MESSAGE_SIZE
1920 - sizeof (struct PeerPutMessage)
1921 - xsize)
1922 / sizeof(struct GNUNET_DHT_PathElement)) )
1923 {
1924 GNUNET_break_op (0);
1925 return GNUNET_SYSERR;
1926 }
1927 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1928 {
1929 GNUNET_break_op (0);
1930 return GNUNET_SYSERR;
1931 }
1932 return GNUNET_OK;
1933}
1934
1935
1942static void
1944 const struct PeerPutMessage *put)
1945{
1946 struct Target *t = cls;
1947 struct PeerInfo *peer = t->pi;
1949 = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1950 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1951 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1952 uint16_t msize = ntohs (put->header.size);
1953 uint16_t putlen = ntohs (put->put_path_length);
1954 const struct GNUNET_PeerIdentity *trunc_peer
1955 = truncated
1956 ? (const struct GNUNET_PeerIdentity *) &put[1]
1957 : NULL;
1958 const struct GNUNET_DHT_PathElement *put_path
1959 = truncated
1960 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1961 : (const struct GNUNET_DHT_PathElement *) &put[1];
1962 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1963 = has_path
1964 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1965 : NULL;
1966 const char *data
1967 = has_path
1968 ? (const char *) &last_sig[1]
1969 : (const char *) &put_path[putlen];
1970 size_t var_meta_size
1971 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1972 + (has_path ? sizeof (*last_sig) : 0)
1973 + (truncated ? sizeof (*trunc_peer) : 0);
1974 struct GNUNET_DATACACHE_Block bd = {
1975 .key = put->key,
1976 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1977 .type = ntohl (put->type),
1978 .ro = ro,
1979 .data_size = msize - sizeof(*put) - var_meta_size,
1980 .data = data
1981 };
1982
1983 if (NULL != trunc_peer)
1984 bd.trunc_peer = *trunc_peer;
1986 "PUT for `%s' from %s with RO (%s/%s)\n",
1987 GNUNET_h2s (&put->key),
1988 GNUNET_i2s (&peer->id),
1989 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1990 has_path ? "R" : "-");
1992 {
1994 "# Expired PUTs discarded",
1995 1,
1996 GNUNET_NO);
1997 return;
1998 }
1999 {
2000 /* Only call 'check_block' if that keeps our CPU load (from
2001 the cryptography) below 50% on average */
2002 static struct GNUNET_TIME_Relative avg_latency;
2003 static struct GNUNET_TIME_Absolute next_time;
2004
2005 if (GNUNET_TIME_absolute_is_past (next_time))
2006 {
2007 struct GNUNET_TIME_Absolute now
2009 struct GNUNET_TIME_Relative latency;
2011
2012 if (GNUNET_NO ==
2014 bd.type,
2015 bd.data,
2016 bd.data_size))
2017 {
2018 GNUNET_break_op (0);
2019 return;
2020 }
2021 latency = GNUNET_TIME_absolute_get_duration (now);
2022 /* Use *moving average* to estimate check_block latency */
2023 avg_latency
2026 GNUNET_TIME_relative_multiply (avg_latency,
2027 7),
2028 latency),
2029 8);
2030 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2033 avg_latency.rel_value_us > 0
2034 ? avg_latency.rel_value_us
2035 : 1LLU);
2037 }
2038 }
2039 if (! has_path)
2040 putlen = 0;
2042 "# P2P PUT requests received",
2043 1,
2044 GNUNET_NO);
2046 "# P2P PUT bytes received",
2047 msize,
2048 GNUNET_NO);
2049 {
2050 struct GNUNET_HashCode test_key;
2052
2054 bd.type,
2055 bd.data,
2056 bd.data_size,
2057 &test_key);
2058 switch (ret)
2059 {
2060 case GNUNET_YES:
2061 if (0 != GNUNET_memcmp (&test_key,
2062 &bd.key))
2063 {
2064 GNUNET_break_op (0);
2065 return;
2066 }
2067 break;
2068 case GNUNET_NO:
2069 /* cannot verify, good luck */
2070 break;
2071 case GNUNET_SYSERR:
2072 /* block type not supported, good luck */
2073 break;
2074 }
2075 }
2076
2077 {
2079 struct GNUNET_DHT_PathElement pp[putlen + 1];
2080
2086 &peer->phash));
2087 /* extend 'put path' by sender */
2088 bd.put_path = pp;
2089 bd.put_path_length = putlen + 1;
2090 if (has_path)
2091 {
2092 unsigned int failure_offset;
2093
2094 GNUNET_memcpy (pp,
2095 put_path,
2096 putlen * sizeof(struct GNUNET_DHT_PathElement));
2097 pp[putlen].pred = peer->id;
2098 pp[putlen].sig = *last_sig;
2099#if SANITY_CHECKS
2100 /* TODO: might want to eventually implement probabilistic
2101 load-based path verification, but for now it is all or nothing */
2102 failure_offset
2104 bd.data_size,
2105 bd.expiration_time,
2106 trunc_peer,
2107 pp,
2108 putlen + 1,
2109 NULL, 0, /* get_path */
2111#else
2112 failure_offset = 0;
2113#endif
2114 if (0 != failure_offset)
2115 {
2116 GNUNET_break_op (0);
2118 "Recorded put path invalid at offset %u, truncating\n",
2119 failure_offset);
2120 GNUNET_assert (failure_offset <= putlen + 1);
2121 bd.put_path = &pp[failure_offset];
2122 bd.put_path_length = (putlen + 1) - failure_offset;
2124 bd.trunc_peer = pp[failure_offset - 1].pred;
2125 }
2126 }
2127 else
2128 {
2129 bd.put_path_length = 0;
2130 }
2131
2132 /* give to local clients */
2134 &bd.key,
2135 0, NULL /* get path */));
2136
2137 /* store locally */
2138 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2139 (GDS_am_closest_peer (&put->key,
2140 bf)) )
2142 {
2143 enum GNUNET_GenericReturnValue forwarded;
2144
2145 /* route to other peers */
2146 forwarded
2148 ntohs (put->desired_replication_level),
2149 ntohs (put->hop_count),
2150 bf);
2151 /* notify monitoring clients */
2152 bd.ro |= ((GNUNET_OK == forwarded)
2154 : 0);
2156 ntohs (put->hop_count),
2157 ntohs (put->desired_replication_level));
2158 }
2160 }
2161}
2162
2163
2172static void
2174 const struct GNUNET_HashCode *query_hash,
2175 struct GNUNET_BLOCK_Group *bg)
2176{
2177 size_t block_size = 0;
2178
2179 /* TODO: consider caching our HELLO block for a bit, to
2180 avoid signing too often here... */
2184 NULL,
2185 &block_size,
2187 {
2188 char block[block_size];
2189
2190 if (GNUNET_OK !=
2193 block,
2194 &block_size,
2196 {
2198 "# FIND PEER requests ignored due to lack of HELLO",
2199 1,
2200 GNUNET_NO);
2201 }
2202 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
2205 bg,
2207 NULL, 0,
2208 block,
2209 block_size))
2210 {
2211 struct GNUNET_DATACACHE_Block bd = {
2213 .expiration_time
2216 .key = GDS_my_identity_hash,
2217 .data = block,
2218 .data_size = block_size
2219 };
2220
2222 &bd,
2223 query_hash,
2224 0, NULL /* get path */));
2225 }
2226 else
2227 {
2229 "# FIND PEER requests ignored due to Bloomfilter",
2230 1,
2231 GNUNET_NO);
2232 }
2233 }
2234}
2235
2236
2245static void
2247 const struct GNUNET_HashCode *query_hash,
2248 struct GNUNET_BLOCK_Group *bg)
2249{
2250 /* Force non-random selection by hop count */
2251 struct PeerInfo *peer;
2252
2253 peer = select_peer (query_hash,
2254 NULL,
2255 GDS_NSE_get () + 1);
2256 if ( (NULL != peer->hello) &&
2262 bg,
2263 &peer->phash,
2264 NULL, 0, /* xquery */
2265 peer->hello,
2266 peer->hello_size)) )
2267 {
2268 struct GNUNET_DATACACHE_Block bd = {
2270 .expiration_time = peer->hello_expiration,
2271 .key = peer->phash,
2272 .data = peer->hello,
2273 .data_size = peer->hello_size
2274 };
2275
2277 &bd,
2278 query_hash,
2279 0, NULL /* get path */));
2280 }
2281}
2282
2283
2290static void
2292 const struct GNUNET_DATACACHE_Block *bd)
2293{
2294 struct PeerInfo *peer = cls;
2295
2297 bd,
2298 &bd->key,
2299 0, NULL /* get path */));
2300}
2301
2302
2310static enum GNUNET_GenericReturnValue
2312 const struct PeerGetMessage *get)
2313{
2314 uint16_t msize = ntohs (get->header.size);
2315 uint16_t result_filter_size = ntohs (get->result_filter_size);
2316
2317 (void) cls;
2318 if (msize < sizeof(*get) + result_filter_size)
2319 {
2320 GNUNET_break_op (0);
2321 return GNUNET_SYSERR;
2322 }
2323 return GNUNET_OK;
2324}
2325
2326
2333static void
2335 const struct PeerGetMessage *get)
2336{
2337 struct Target *t = cls;
2338 struct PeerInfo *peer = t->pi;
2339 uint16_t msize = ntohs (get->header.size);
2340 uint16_t result_filter_size = ntohs (get->result_filter_size);
2341 uint16_t hop_count = ntohs (get->hop_count);
2342 enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2344 get->options);
2346 const void *result_filter = (const void *) &get[1];
2347 const void *xquery = result_filter + result_filter_size;
2348 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2349
2350 /* parse and validate message */
2352 "# P2P GET requests received",
2353 1,
2354 GNUNET_NO);
2356 "# P2P GET bytes received",
2357 msize,
2358 GNUNET_NO);
2359 if (GNUNET_NO ==
2361 type,
2362 &get->key,
2363 xquery,
2364 xquery_size))
2365 {
2366 /* request invalid */
2367 GNUNET_break_op (0);
2368 return;
2369 }
2370
2371 {
2372 struct GNUNET_BLOCK_Group *bg;
2373 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2374
2375 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2380 &peer->phash));
2382 type,
2383 result_filter,
2384 result_filter_size,
2385 "filter-size",
2386 result_filter_size,
2387 NULL);
2389 "GET for %s at %s after %u hops\n",
2390 GNUNET_h2s (&get->key),
2392 (unsigned int) hop_count);
2393 /* local lookup (this may update the bg) */
2395 (GDS_am_closest_peer (&get->key,
2396 peer_bf)) )
2397 {
2400 {
2402 "# P2P HELLO lookup requests processed",
2403 1,
2404 GNUNET_NO);
2406 &get->key,
2407 bg);
2410 &get->key,
2411 bg);
2412 }
2414 {
2416 eval = GDS_DATACACHE_get_closest (&get->key,
2417 type,
2418 xquery,
2419 xquery_size,
2420 bg,
2422 peer);
2423 else
2424 eval = GDS_DATACACHE_handle_get (&get->key,
2425 type,
2426 xquery,
2427 xquery_size,
2428 bg,
2430 peer);
2431 }
2432 }
2433 else
2434 {
2436 "# P2P GET requests ONLY routed",
2437 1,
2438 GNUNET_NO);
2439 }
2440
2441 /* remember request for routing replies
2442 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2443 */
2444 GDS_ROUTING_add (&peer->id,
2445 type,
2446 bg, /* bg now owned by routing, but valid at least until end of this function! */
2447 options,
2448 &get->key,
2449 xquery,
2450 xquery_size);
2451
2452 /* P2P forwarding */
2453 {
2454 bool forwarded = false;
2455 uint16_t desired_replication_level = ntohs (
2456 get->desired_replication_level);
2457
2458 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2459 forwarded = (GNUNET_OK ==
2461 options,
2462 desired_replication_level,
2463 hop_count,
2464 &get->key,
2465 xquery,
2466 xquery_size,
2467 bg,
2468 peer_bf));
2470 options
2471 | (forwarded
2472 ? 0
2474 type,
2475 hop_count,
2476 desired_replication_level,
2477 &get->key);
2478 }
2479 /* clean up; note that 'bg' is owned by routing now! */
2481 }
2482}
2483
2484
2494static bool
2496 const struct GNUNET_HashCode *query_hash,
2497 unsigned int get_path_length,
2498 const struct GNUNET_DHT_PathElement *get_path)
2499{
2500 /* forward to local clients */
2502 "Forwarding reply to local clients\n");
2503 if (! GDS_CLIENTS_handle_reply (bd,
2504 query_hash,
2505 get_path_length,
2506 get_path))
2507 {
2508 GNUNET_break (0);
2509 return false;
2510 }
2512 get_path,
2513 get_path_length);
2515 {
2516 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2517 + bd->put_path_length)];
2518 struct GNUNET_DATACACHE_Block bdx = *bd;
2519
2520 if (NULL != bd->put_path)
2521 GNUNET_memcpy (xput_path,
2522 bd->put_path,
2523 bd->put_path_length * sizeof(struct
2525 GNUNET_memcpy (&xput_path[bd->put_path_length],
2526 get_path,
2527 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2528 bdx.put_path = xput_path;
2529 bdx.put_path_length += get_path_length;
2531 }
2532 /* forward to other peers */
2534 query_hash,
2535 get_path_length,
2536 get_path);
2537 return true;
2538}
2539
2540
2548static enum GNUNET_GenericReturnValue
2550 const struct PeerResultMessage *prm)
2551{
2552 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2554 = (enum GNUNET_DHT_RouteOption) ntohs (prm->options);
2555 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2556 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2557
2558 uint16_t get_path_length = ntohs (prm->get_path_length);
2559 uint16_t put_path_length = ntohs (prm->put_path_length);
2560 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2561 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2562
2563 (void) cls;
2564 if ( (msize < vsize) ||
2565 (msize - vsize <
2566 (get_path_length + put_path_length)
2567 * sizeof(struct GNUNET_DHT_PathElement)) ||
2568 (get_path_length >
2569 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2570 (put_path_length >
2571 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2572 {
2573 GNUNET_break_op (0);
2574 return GNUNET_SYSERR;
2575 }
2576 return GNUNET_OK;
2577}
2578
2579
2586static void
2588 const struct PeerResultMessage *prm)
2589{
2590 struct Target *t = cls;
2591 struct PeerInfo *peer = t->pi;
2592 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2594 = (enum GNUNET_DHT_RouteOption) ntohs (prm->options);
2595 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2596 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2597 uint16_t get_path_length = ntohs (prm->get_path_length);
2598 uint16_t put_path_length = ntohs (prm->put_path_length);
2599 const struct GNUNET_PeerIdentity *trunc_peer
2600 = truncated
2601 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2602 : NULL;
2603 const struct GNUNET_DHT_PathElement *put_path
2604 = truncated
2605 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2606 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2607 const struct GNUNET_DHT_PathElement *get_path
2608 = &put_path[put_path_length];
2609 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2610 = tracked
2611 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2612 : NULL;
2613 const void *data
2614 = tracked
2615 ? (const void *) &last_sig[1]
2616 : (const void *) &get_path[get_path_length];
2617 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2618 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2619 struct GNUNET_DATACACHE_Block bd = {
2621 .put_path = put_path,
2622 .put_path_length = put_path_length,
2623 .key = prm->key,
2624 .type = ntohl (prm->type),
2625 .ro = ro,
2626 .data = data,
2627 .data_size = msize - vsize - (get_path_length + put_path_length)
2628 * sizeof(struct GNUNET_DHT_PathElement)
2629 };
2630
2631 /* parse and validate message */
2632 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2633 {
2635 "# Expired results discarded",
2636 1,
2637 GNUNET_NO);
2638 return;
2639 }
2640 if (GNUNET_OK !=
2642 bd.type,
2643 bd.data,
2644 bd.data_size))
2645 {
2646 GNUNET_break_op (0);
2647 return;
2648 }
2650 "# P2P RESULTS received",
2651 1,
2652 GNUNET_NO);
2654 "# P2P RESULT bytes received",
2655 msize,
2656 GNUNET_NO);
2657 {
2659
2661 bd.type,
2662 bd.data,
2663 bd.data_size,
2664 &bd.key);
2665 if (GNUNET_NO == ret)
2666 bd.key = prm->key;
2667 }
2668
2669 /* if we got a HELLO, consider it for our own routing table */
2670 hello_check (&bd);
2671
2672 /* Need to append 'peer' to 'get_path' */
2673 if (tracked)
2674 {
2675 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2676 struct GNUNET_DHT_PathElement *gp = xget_path;
2677 unsigned int failure_offset;
2678
2679 GNUNET_memcpy (xget_path,
2680 get_path,
2681 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2682 xget_path[get_path_length].pred = peer->id;
2683 /* use memcpy(), as last_sig may not be aligned */
2684 memcpy (&xget_path[get_path_length].sig,
2685 last_sig,
2686 sizeof (*last_sig));
2687#if SANITY_CHECKS
2688 /* TODO: might want to eventually implement probabilistic
2689 load-based path verification, but for now it is all or nothing */
2690 failure_offset
2691 = GNUNET_DHT_verify_path (bd.data,
2692 bd.data_size,
2693 bd.expiration_time,
2694 trunc_peer,
2695 put_path,
2696 put_path_length,
2697 gp,
2698 get_path_length + 1,
2700#else
2701 failure_offset = 0;
2702#endif
2703 if (0 != failure_offset)
2704 {
2706 "Recorded path invalid at offset %u, truncating\n",
2707 failure_offset);
2708 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2709 + 1);
2710 if (failure_offset < bd.put_path_length)
2711 {
2712 /* failure on put path */
2713 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2714 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2715 bd.put_path = &bd.put_path[failure_offset];
2716 bd.put_path_length -= failure_offset;
2717 truncated = true;
2718 }
2719 else
2720 {
2721 /* failure on get path */
2722 failure_offset -= bd.put_path_length;
2723 if (0 == failure_offset)
2724 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2725 else
2726 trunc_peer = &gp[failure_offset - 1].pred;
2727 get_path_length -= failure_offset;
2728 gp = &gp[failure_offset];
2729 bd.put_path_length = 0;
2730 bd.put_path = NULL;
2731 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2732 truncated = true;
2733 }
2734 }
2736 "Extending GET path of length %u with %s\n",
2737 get_path_length,
2738 GNUNET_i2s (&peer->id));
2739 if (truncated)
2740 {
2741 GNUNET_assert (NULL != trunc_peer);
2742 bd.trunc_peer = *trunc_peer;
2743 }
2745 &prm->key,
2746 get_path_length + 1,
2747 gp));
2748 }
2749 else
2750 {
2751 if (truncated)
2752 {
2753 GNUNET_assert (NULL != trunc_peer);
2754 bd.trunc_peer = *trunc_peer;
2755 }
2757 &prm->key,
2758 0,
2759 NULL));
2760 }
2761}
2762
2763
2771static enum GNUNET_GenericReturnValue
2773 const struct GNUNET_MessageHeader *hello)
2774{
2775 struct Target *t = cls;
2776 struct PeerInfo *peer = t->pi;
2778 size_t hellob_size;
2779 void *hellob;
2781
2783 &peer->id,
2784 &hellob,
2785 &hellob_size,
2786 &expiration);
2787 GNUNET_free (hellob);
2788 return ret;
2789}
2790
2791
2798static void
2800 const struct GNUNET_MessageHeader *hello)
2801{
2802 struct Target *t = cls;
2803 struct PeerInfo *peer = t->pi;
2804
2805 GNUNET_free (peer->hello);
2806 peer->hello_size = 0;
2809 &peer->id,
2810 &peer->hello,
2811 &peer->hello_size,
2812 &peer->hello_expiration));
2813}
2814
2815
2816void
2817GDS_u_receive (void *cls,
2818 void **tctx,
2819 void **sctx,
2820 const void *message,
2821 size_t message_size)
2822{
2823 struct Target *t = *tctx;
2824 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2825 GNUNET_MQ_hd_var_size (dht_p2p_get,
2827 struct PeerGetMessage,
2828 t),
2829 GNUNET_MQ_hd_var_size (dht_p2p_put,
2831 struct PeerPutMessage,
2832 t),
2833 GNUNET_MQ_hd_var_size (dht_p2p_result,
2835 struct PeerResultMessage,
2836 t),
2837 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2839 struct GNUNET_MessageHeader,
2840 t),
2842 };
2843 const struct GNUNET_MessageHeader *mh = message;
2844
2845 (void) cls; /* the 'struct GDS_Underlay' */
2846 (void) sctx; /* our receiver address */
2847 if (NULL == t)
2848 {
2849 /* Received message claiming to originate from myself?
2850 Ignore! */
2851 GNUNET_break_op (0);
2852 return;
2853 }
2854 if (message_size < sizeof (*mh))
2855 {
2856 GNUNET_break_op (0);
2857 return;
2858 }
2859 if (message_size != ntohs (mh->size))
2860 {
2861 GNUNET_break_op (0);
2862 return;
2863 }
2865 "Handling message of type %u from peer %s\n",
2866 ntohs (mh->type),
2867 GNUNET_i2s (&t->pi->id));
2868 if (GNUNET_OK !=
2869 GNUNET_MQ_handle_message (core_handlers,
2870 mh))
2871 {
2872 GNUNET_break_op (0);
2873 return;
2874 }
2875}
2876
2877
2885void
2887 const struct GNUNET_PeerIdentity *pid,
2888 const char *uri)
2889{
2890 (void) cls;
2891 struct GNUNET_HashCode phash;
2892 int peer_bucket;
2893 struct PeerBucket *bucket;
2894
2895 if (0 == GNUNET_memcmp (&GDS_my_identity,
2896 pid))
2897 {
2899 "Got a HELLO for my own PID, ignoring it\n");
2900 return; /* that's us! */
2901 }
2903 sizeof(*pid),
2904 &phash);
2905 peer_bucket = find_bucket (&phash);
2906 GNUNET_assert ( (peer_bucket >= 0) &&
2907 ((unsigned int) peer_bucket < MAX_BUCKETS));
2908 bucket = &k_buckets[peer_bucket];
2909 for (struct PeerInfo *pi = bucket->head;
2910 NULL != pi;
2911 pi = pi->next)
2912 if (0 ==
2913 GNUNET_memcmp (&pi->id,
2914 pid))
2915 {
2916 /* already connected */
2918 uri);
2919 return;
2920 }
2921 if (bucket->peers_size >= bucket_size)
2922 return; /* do not care */
2924 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2925 GNUNET_i2s (pid),
2926 uri,
2927 peer_bucket,
2928 bucket->peers_size,
2929 bucket_size);
2930 /* new peer that we like! */
2932 uri);
2933}
2934
2935
2941void
2943{
2944 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2945 {
2946 struct PeerBucket *bucket = &k_buckets[bc];
2947 unsigned int count = 0;
2948
2949 for (struct PeerInfo *pos = bucket->head;
2950 NULL != pos;
2951 pos = pos->next)
2952 {
2953 if (count >= bucket_size)
2954 break; /* we only consider first #bucket_size entries per bucket */
2955 count++;
2956 do_send (pos,
2957 msg);
2958 }
2959 }
2960}
2961
2962
2965{
2966
2967 unsigned long long temp_config_num;
2968
2971 "DHT",
2972 "DISABLE_TRY_CONNECT");
2973 if (GNUNET_OK ==
2975 "DHT",
2976 "bucket_size",
2977 &temp_config_num))
2978 bucket_size = (unsigned int) temp_config_num;
2981 "DHT",
2982 "CACHE_RESULTS");
2984 GNUNET_YES);
2985 return GNUNET_OK;
2986}
2987
2988
2989void
2991{
2992 if (NULL == all_connected_peers)
2993 return;
2994 GNUNET_assert (0 ==
2997 all_connected_peers = NULL;
2998 GNUNET_assert (NULL == find_peer_task);
2999}
3000
3001
3002struct GNUNET_PeerIdentity *
3004{
3005 return &GDS_my_identity;
3006}
3007
3008
3009/* 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
static int ret
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_CADET_Handle * mh
Cadet handle.
Definition: gnunet-cadet.c:92
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 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 ...
struct GNUNET_PeerIdentity GDS_my_identity
Identity of this peer.
double GDS_NSE_get(void)
Return the current NSE.
struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key
Our private key.
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.
struct GNUNET_HELLO_Builder * GDS_my_hello
Our HELLO.
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.
struct GNUNET_HashCode GDS_my_identity_hash
Hash of the identity of this peer.
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...
bool 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)
Handle a reply (route to origin).
static void handle_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Core handler for p2p result messages.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put(const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
Perform a PUT operation.
#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.
struct PeerInfo * GDS_NEIGHBOURS_lookup_peer(const struct GNUNET_PeerIdentity *target)
Lookup peer by peer's identity.
struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id()
Get the ID of the local node.
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 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 void handle_find_local_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for nearby HELLOs.
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.
#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 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.
#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 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 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 unsigned int bucket_size
Maximum size for each bucket.
static void handle_find_my_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for a HELLO.
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 void sign_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, struct GNUNET_CRYPTO_EddsaSignature *sig)
Sign that we are routing a message from pred to succ.
static struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
The buckets.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init()
Initialize neighbours subsystem.
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.
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_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_SCHEDULER_Task * t
Main task.
Helper library for handling HELLO URIs.
Constants for network protocols.
#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:363
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:337
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:319
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:296
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:192
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:175
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:247
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:276
@ 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.
#define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
What is the maximum size for encrypted messages? Note that this number imposes a clear limit on the m...
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
#define GNUNET_CRYPTO_eddsa_sign(priv, ps, sig)
EdDSA sign a given block.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
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:1351
@ 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:41
void GNUNET_CRYPTO_hash_xor(const struct GNUNET_HashCode *a, const struct GNUNET_HashCode *b, struct GNUNET_HashCode *result)
compute result = a ^ b
Definition: crypto_hash.c:135
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).
Definition: crypto_hash.c:243
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_builder_free(struct GNUNET_HELLO_Builder *builder)
Release resources of a builder.
Definition: hello-uri.c:373
const struct GNUNET_PeerIdentity * GNUNET_HELLO_builder_iterate(const struct GNUNET_HELLO_Builder *builder, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a builder.
Definition: hello-uri.c:909
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:931
struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_block(const void *block, size_t block_size)
Parse block into builder.
Definition: hello-uri.c:414
enum GNUNET_GenericReturnValue GNUNET_HELLO_builder_to_block(const struct GNUNET_HELLO_Builder *builder, const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, void *block, size_t *block_size, struct GNUNET_TIME_Relative expiration_time)
Generate DHT block from a builder.
Definition: hello-uri.c:782
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
unsigned int GNUNET_CRYPTO_hash_count_leading_zeros(const struct GNUNET_HashCode *h)
Count the number of leading 0 bits in h.
Definition: crypto_hash.c:177
#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_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:981
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:1305
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:1278
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:436
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:585
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:484
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
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:550
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:638
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition: time.c:669
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
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.
#define GNUNET_SIGNATURE_PURPOSE_DHT_HOP
Signature by which a peer affirms that it forwarded a message in the DHT.
Information we keep per underlay.
Block group data.
Internal representation of the hash map.
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
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.
Message signed by a peer when doing path tracking.
struct GNUNET_HashCode h_data
Hash over the payload of the block.
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
Must be GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
struct GNUNET_PeerIdentity pred
Previous hop the message was received from.
struct GNUNET_PeerIdentity succ
Next hop the message was forwarded to.
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 building (or parsing) HELLO URIs.
Definition: hello-uri.c:205
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:136
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:140
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.
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 hop_count
Hop count.
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.
uint16_t desired_replication_level
Replication level for this message.
uint16_t hop_count
Hop count.
uint32_t type
Content type, must not be zero.
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT.
struct GNUNET_HashCode key
The key we are storing under.
uint16_t options
Processing options.
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
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.