GNUnet  0.11.x
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"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_hello_uri_lib.h"
33 #include "gnunet-service-dht.h"
36 #include "dht.h"
37 
38 #define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
39  __VA_ARGS__)
40 
52 #define SANITY_CHECKS 2
53 
57 #define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
58 
62 #define DEFAULT_BUCKET_SIZE 8
63 
67 #define FIND_PEER_REPLICATION_LEVEL 4
68 
72 #define MAXIMUM_PENDING_PER_PEER 64
73 
79 #define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
80  GNUNET_TIME_UNIT_MINUTES, 2)
81 
82 
92 #define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
93  GNUNET_TIME_UNIT_SECONDS, 6)
94 
98 #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
99 
100 
102 
107 {
112 
116  uint32_t type GNUNET_PACKED;
117 
122 
127 
132 
137 
142 
147 
151  struct GNUNET_HashCode key;
152 
153  /* put path (if tracked) */
154 
155  /* Payload */
156 };
157 
158 
163 {
168 
172  uint32_t type GNUNET_PACKED;
173 
178 
183 
188 
193 
197  struct GNUNET_HashCode key;
198 
199  /* put path (if tracked) */
200 
201  /* get path (if tracked) */
202 
203  /* Payload */
204 };
205 
206 
211 {
216 
220  uint32_t type GNUNET_PACKED;
221 
226 
231 
236 
240  uint16_t xquery_size;
241 
246 
250  struct GNUNET_HashCode key;
251 
255  uint32_t bf_mutator;
256 
257  /* xquery */
258 
259  /* result bloomfilter */
260 };
262 
263 
267 struct PeerInfo;
268 
269 
273 struct Target
274 {
278  struct Target *next;
279 
283  struct Target *prev;
284 
289 
293  struct GDS_Underlay *u;
294 
298  struct PeerInfo *pi;
299 
304 
308  unsigned int load;
309 
314  bool dropped;
315 
316 };
317 
318 
322 struct PeerInfo
323 {
327  struct GNUNET_PeerIdentity id;
328 
332  struct GNUNET_HashCode phash;
333 
338 
342  struct PeerInfo *next;
343 
347  struct PeerInfo *prev;
348 
352  struct Target *t_head;
353 
357  struct Target *t_tail;
358 
362  void *hello;
363 
367  size_t hello_size;
368 
373 };
374 
375 
380 {
384  struct PeerInfo *head;
385 
389  struct PeerInfo *tail;
390 
394  unsigned int peers_size;
395 };
396 
397 
401 static int cache_results;
402 
406 static unsigned int closest_bucket;
407 
412 static unsigned int newly_found_peers;
413 
418 
422 static struct PeerBucket k_buckets[MAX_BUCKETS];
423 
429 
433 static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
434 
439 
440 
448 static void
449 send_done_cb (void *cls)
450 {
451  struct Target *t = cls;
452  struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
453 
454  GNUNET_assert (t->load > 0);
455  t->load--;
456  if (0 < t->load)
457  return;
458  if (t->dropped)
459  {
460  GNUNET_free (t);
461  return;
462  }
463  /* move target back to the front */
465  pi->t_tail,
466  t);
468  pi->t_tail,
469  t);
470 }
471 
472 
479 static void
480 do_send (struct PeerInfo *pi,
481  const struct GNUNET_MessageHeader *msg)
482 {
483  struct Target *t;
484 
485  for (t = pi->t_head;
486  NULL != t;
487  t = t->next)
488  if (t->load < MAXIMUM_PENDING_PER_PEER)
489  break;
490  if (NULL == t)
491  {
492  /* all targets busy, drop message */
494  "# messages dropped (underlays busy)",
495  1,
496  GNUNET_NO);
497  return;
498  }
499  t->load++;
500  /* rotate busy targets to the end */
501  if (MAXIMUM_PENDING_PER_PEER == t->load)
502  {
504  pi->t_tail,
505  t);
507  pi->t_tail,
508  t);
509  }
510  GDS_u_send (t->u,
511  t->utarget,
512  msg,
513  ntohs (msg->size),
514  &send_done_cb,
515  t);
516 }
517 
518 
532 static void
533 sign_path (const void *data,
534  size_t data_size,
535  struct GNUNET_TIME_Absolute exp_time,
536  const struct GNUNET_PeerIdentity *pred,
537  const struct GNUNET_PeerIdentity *succ,
538  struct GNUNET_CRYPTO_EddsaSignature *sig)
539 {
540  struct GNUNET_DHT_HopSignature hs = {
542  .purpose.size = htonl (sizeof (hs)),
543  .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
544  .pred = *pred,
545  .succ = *succ
546  };
547 
549  data_size,
550  &hs.h_data);
552  &hs,
553  sig);
554 }
555 
556 
564 static int
565 find_bucket (const struct GNUNET_HashCode *hc)
566 {
567  struct GNUNET_HashCode xor;
568  unsigned int bits;
569 
572  &xor);
574  if (bits == MAX_BUCKETS)
575  {
576  /* How can all bits match? Got my own ID? */
577  GNUNET_break (0);
578  return -1;
579  }
580  return MAX_BUCKETS - bits - 1;
581 }
582 
583 
593 static enum GNUNET_GenericReturnValue
594 add_known_to_bloom (void *cls,
595  const struct GNUNET_PeerIdentity *key,
596  void *value)
597 {
598  struct GNUNET_BLOCK_Group *bg = cls;
599  struct PeerInfo *pi = value;
600 
602  &pi->phash,
603  1);
605  "Adding known peer (%s) to Bloom filter for FIND PEER\n",
606  GNUNET_i2s (key));
607  return GNUNET_YES;
608 }
609 
610 
618 static void
620 {
621  (void) cls;
622 
623  /* Compute when to do this again (and if we should
624  even send a message right now) */
625  {
626  struct GNUNET_TIME_Relative next_send_time;
627  bool done_early;
628 
629  find_peer_task = NULL;
630  done_early = (newly_found_peers > bucket_size);
631  /* schedule next round, taking longer if we found more peers
632  in the last round. */
633  next_send_time.rel_value_us =
634  DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
639  1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
640  newly_found_peers = 0;
641  GNUNET_assert (NULL == find_peer_task);
643  GNUNET_SCHEDULER_add_delayed (next_send_time,
645  NULL);
646  if (done_early)
647  return;
648  }
649 
650  /* actually send 'find peer' request */
651  {
652  struct GNUNET_BLOCK_Group *bg;
653  struct GNUNET_CONTAINER_BloomFilter *peer_bf;
654 
659  UINT32_MAX),
660  NULL,
661  0,
662  "filter-size",
664  NULL);
667  bg);
668  peer_bf
672  if (GNUNET_OK !=
677  0, /* hop count */
679  NULL, 0, /* xquery */
680  bg,
681  peer_bf))
682  {
684  "# Failed to initiate FIND PEER lookup",
685  1,
686  GNUNET_NO);
687  }
688  else
689  {
691  "# FIND PEER messages initiated",
692  1,
693  GNUNET_NO);
694  }
697  }
698 }
699 
700 
708 static void
709 update_hold (struct PeerBucket *bucket)
710 {
711  unsigned int off = 0;
712 
713  /* find the peer -- we just go over all of them, should
714  be hardly any more expensive than just finding the 'right'
715  one. */
716  for (struct PeerInfo *pos = bucket->head;
717  NULL != pos;
718  pos = pos->next)
719  {
720  if (off > bucket_size)
721  break; /* We only hold up to #bucket_size peers per bucket */
722  off++;
723  for (struct Target *tp = pos->t_head;
724  NULL != tp;
725  tp = tp->next)
726  if (NULL == tp->ph)
727  tp->ph = GDS_u_hold (tp->u,
728  tp->utarget);
729  }
730 }
731 
732 
733 void
734 GDS_u_connect (void *cls,
735  struct GNUNET_DHTU_Target *target,
736  const struct GNUNET_PeerIdentity *pid,
737  void **ctx)
738 {
739  struct GDS_Underlay *u = cls;
740  struct PeerInfo *pi;
741  struct PeerBucket *bucket;
742  bool do_hold = false;
743 
744  /* Check for connect to self message */
745  if (0 == GNUNET_memcmp (&GDS_my_identity,
746  pid))
747  return;
749  "Connected to peer %s\n",
750  GNUNET_i2s (pid));
752  pid);
753  if (NULL == pi)
754  {
756  "# peers connected",
757  1,
758  GNUNET_NO);
759  pi = GNUNET_new (struct PeerInfo);
760  pi->id = *pid;
762  sizeof(*pid),
763  &pi->phash);
764  pi->peer_bucket = find_bucket (&pi->phash);
765  GNUNET_assert ( (pi->peer_bucket >= 0) &&
766  ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
767  bucket = &k_buckets[pi->peer_bucket];
769  bucket->tail,
770  pi);
771  bucket->peers_size++;
773  (unsigned int) pi->peer_bucket + 1);
776  &pi->id,
777  pi,
779  if (bucket->peers_size <= bucket_size)
780  {
782  do_hold = true;
783  }
786  {
787  /* got a first connection, good time to start with FIND PEER requests... */
788  GNUNET_assert (NULL == find_peer_task);
790  NULL);
791  }
792  }
793  {
794  struct Target *t;
795 
796  t = GNUNET_new (struct Target);
797  t->u = u;
798  t->utarget = target;
799  t->pi = pi;
801  pi->t_tail,
802  t);
803  *ctx = t;
804 
805  }
806  if (do_hold)
807  update_hold (bucket);
808 }
809 
810 
811 void
813 {
814  struct Target *t = ctx;
815  struct PeerInfo *pi;
816  struct PeerBucket *bucket;
817  bool was_held = false;
818 
819  /* Check for disconnect from self message (on shutdown) */
820  if (NULL == t)
821  return;
822  pi = t->pi;
824  pi->t_tail,
825  t);
826  if (NULL != t->ph)
827  {
828  GDS_u_drop (t->u,
829  t->ph);
830  t->ph = NULL;
831  was_held = true;
832  }
833  if (t->load > 0)
834  {
835  t->dropped = true;
836  t->pi = NULL;
837  }
838  else
839  {
840  GNUNET_free (t);
841  }
842  if (NULL != pi->t_head)
843  return; /* got other connections still */
845  "Disconnected from peer %s\n",
846  GNUNET_i2s (&pi->id));
848  "# peers connected",
849  -1,
850  GNUNET_NO);
853  &pi->id,
854  pi));
857  {
859  find_peer_task = NULL;
860  }
861  GNUNET_assert (pi->peer_bucket >= 0);
862  bucket = &k_buckets[pi->peer_bucket];
864  bucket->tail,
865  pi);
866  GNUNET_assert (bucket->peers_size > 0);
867  bucket->peers_size--;
868  if ( (was_held) &&
869  (bucket->peers_size >= bucket_size - 1) )
870  update_hold (bucket);
871  while ( (closest_bucket > 0) &&
872  (0 == k_buckets[closest_bucket - 1].peers_size))
873  closest_bucket--;
874  GNUNET_free (pi->hello);
875  GNUNET_free (pi);
876 }
877 
878 
887 static unsigned int
888 get_forward_count (uint16_t hop_count,
889  uint16_t target_replication)
890 {
891  uint32_t random_value;
892  uint32_t forward_count;
893  float target_value;
894  float rm1;
895 
896  if (hop_count > GDS_NSE_get () * 4.0)
897  {
898  /* forcefully terminate */
900  "# requests TTL-dropped",
901  1,
902  GNUNET_NO);
903  return 0;
904  }
905  if (hop_count > GDS_NSE_get () * 2.0)
906  {
907  /* Once we have reached our ideal number of hops, only forward to 1 peer */
908  return 1;
909  }
910  /* bound by system-wide maximum and minimum */
911  if (0 == target_replication)
912  target_replication = 1; /* 0 is verboten */
913  target_replication =
915  target_replication);
916  rm1 = target_replication - 1.0;
917  target_value =
918  1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
919 
920  /* Set forward count to floor of target_value */
921  forward_count = (uint32_t) target_value;
922  /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
923  target_value = target_value - forward_count;
925  UINT32_MAX);
926  if (random_value < (target_value * UINT32_MAX))
927  forward_count++;
928  return GNUNET_MIN (forward_count,
930 }
931 
932 
945  const struct GNUNET_CONTAINER_BloomFilter *bloom)
946 {
948  key))
949  return GNUNET_YES;
950  for (int bucket_num = find_bucket (key);
951  bucket_num < closest_bucket;
952  bucket_num++)
953  {
954  unsigned int count = 0;
955 
956  GNUNET_assert (bucket_num >= 0);
957  for (struct PeerInfo *pos = k_buckets[bucket_num].head;
958  NULL != pos;
959  pos = pos->next)
960  {
961  if (count >= bucket_size)
962  break; /* we only consider first #bucket_size entries per bucket */
963  count++;
964  if ( (NULL != bloom) &&
965  (GNUNET_YES ==
967  &pos->phash)) )
968  continue; /* Ignore filtered peers */
969  /* All peers in this bucket must be closer than us, as
970  they mismatch with our PID on the pivotal bit. So
971  because an unfiltered peer exists, we are not the
972  closest. */
973  int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
975  key);
976  switch (delta)
977  {
978  case -1: /* pos closer */
979  return GNUNET_NO;
980  case 0: /* identical, impossible! */
981  GNUNET_assert (0);
982  break;
983  case 1: /* I am closer */
984  break;
985  }
986  }
987  }
988  /* No closer (unfiltered) peers found; we must be the closest! */
989  return GNUNET_YES;
990 }
991 
992 
1014 static struct PeerInfo *
1016  const struct GNUNET_CONTAINER_BloomFilter *bloom,
1017  uint32_t hops)
1018 {
1019  if (0 == closest_bucket)
1020  {
1022  "# Peer selection failed",
1023  1,
1024  GNUNET_NO);
1025  return NULL; /* we have zero connections */
1026  }
1027  if (hops >= GDS_NSE_get ())
1028  {
1029  /* greedy selection (closest peer that is not in Bloom filter) */
1030  struct PeerInfo *chosen = NULL;
1031  int best_bucket;
1032  int bucket_offset;
1033 
1034  {
1035  struct GNUNET_HashCode xor;
1036 
1039  &xor);
1040  best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1041  }
1042  if (best_bucket >= closest_bucket)
1043  bucket_offset = closest_bucket - 1;
1044  else
1045  bucket_offset = best_bucket;
1046  while (-1 != bucket_offset)
1047  {
1048  struct PeerBucket *bucket = &k_buckets[bucket_offset];
1049  unsigned int count = 0;
1050 
1051  for (struct PeerInfo *pos = bucket->head;
1052  NULL != pos;
1053  pos = pos->next)
1054  {
1055  if (count >= bucket_size)
1056  break; /* we only consider first #bucket_size entries per bucket */
1057  count++;
1058  if ( (NULL != bloom) &&
1059  (GNUNET_YES ==
1061  &pos->phash)) )
1062  {
1064  "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1065  GNUNET_i2s (&pos->id),
1066  GNUNET_h2s (key));
1067  continue;
1068  }
1069  if (NULL == chosen)
1070  {
1071  /* First candidate */
1072  chosen = pos;
1073  }
1074  else
1075  {
1076  int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1077  &chosen->phash,
1078  key);
1079  switch (delta)
1080  {
1081  case -1: /* pos closer */
1082  chosen = pos;
1083  break;
1084  case 0: /* identical, impossible! */
1085  GNUNET_assert (0);
1086  break;
1087  case 1: /* chosen closer */
1088  break;
1089  }
1090  }
1091  count++;
1092  } /* for all (#bucket_size) peers in bucket */
1093  if (NULL != chosen)
1094  break;
1095 
1096  /* If we chose nothing in first iteration, first go through deeper
1097  buckets (best chance to find a good match), and if we still found
1098  nothing, then to shallower buckets. Terminate on any match in the
1099  current bucket, as this search order guarantees that it can only get
1100  worse as we keep going. */
1101  if (bucket_offset > best_bucket)
1102  {
1103  /* Go through more deeper buckets */
1104  bucket_offset++;
1105  if (bucket_offset == closest_bucket)
1106  {
1107  /* Can't go any deeper, if nothing selected,
1108  go for shallower buckets */
1109  bucket_offset = best_bucket - 1;
1110  }
1111  }
1112  else
1113  {
1114  /* We're either at the 'best_bucket' or already moving
1115  on to shallower buckets. */
1116  if (bucket_offset == best_bucket)
1117  bucket_offset++; /* go for deeper buckets */
1118  else
1119  bucket_offset--; /* go for shallower buckets */
1120  }
1121  } /* for applicable buckets (starting at best match) */
1122  if (NULL == chosen)
1123  {
1125  "# Peer selection failed",
1126  1,
1127  GNUNET_NO);
1128  return NULL;
1129  }
1131  "Selected peer `%s' in greedy routing for %s\n",
1132  GNUNET_i2s (&chosen->id),
1133  GNUNET_h2s (key));
1134  return chosen;
1135  } /* end of 'greedy' peer selection */
1136 
1137  /* select "random" peer */
1138  /* count number of peers that are available and not filtered,
1139  but limit to at most #bucket_size peers, starting with
1140  those 'furthest' from us. */
1141  {
1142  unsigned int total = 0;
1143  unsigned int selected;
1144 
1145  for (unsigned int bc = 0; bc < closest_bucket; bc++)
1146  {
1147  struct PeerBucket *bucket = &k_buckets[bc];
1148  unsigned int count = 0;
1149 
1150  for (struct PeerInfo *pos = bucket->head;
1151  NULL != pos;
1152  pos = pos->next)
1153  {
1154  count++;
1155  if (count > bucket_size)
1156  break; /* limits search to #bucket_size peers per bucket */
1157  if ( (NULL != bloom) &&
1158  (GNUNET_YES ==
1160  &pos->phash)) )
1161  {
1163  "Excluded peer `%s' due to BF match in random routing for %s\n",
1164  GNUNET_i2s (&pos->id),
1165  GNUNET_h2s (key));
1166  continue; /* Ignore filtered peers */
1167  }
1168  total++;
1169  } /* for all peers in bucket */
1170  } /* for all buckets */
1171  if (0 == total) /* No peers to select from! */
1172  {
1174  "# Peer selection failed",
1175  1,
1176  GNUNET_NO);
1177  return NULL;
1178  }
1179 
1180  /* Now actually choose a peer */
1182  total);
1183  for (unsigned int bc = 0; bc < closest_bucket; bc++)
1184  {
1185  unsigned int count = 0;
1186 
1187  for (struct PeerInfo *pos = k_buckets[bc].head;
1188  pos != NULL;
1189  pos = pos->next)
1190  {
1191  count++;
1192  if (count > bucket_size)
1193  break; /* limits search to #bucket_size peers per bucket */
1194 
1195  if ( (NULL != bloom) &&
1196  (GNUNET_YES ==
1198  &pos->phash)) )
1199  continue; /* Ignore bloomfiltered peers */
1200  if (0 == selected--)
1201  {
1203  "Selected peer `%s' in random routing for %s\n",
1204  GNUNET_i2s (&pos->id),
1205  GNUNET_h2s (key));
1206  return pos;
1207  }
1208  } /* for peers in bucket */
1209  } /* for all buckets */
1210  } /* random peer selection scope */
1211  GNUNET_break (0);
1212  return NULL;
1213 }
1214 
1215 
1229 static unsigned int
1231  struct GNUNET_CONTAINER_BloomFilter *bloom,
1232  uint16_t hop_count,
1233  uint16_t target_replication,
1234  struct PeerInfo ***targets)
1235 {
1236  unsigned int target;
1237  unsigned int off;
1238  struct PeerInfo **rtargets;
1239 
1240  GNUNET_assert (NULL != bloom);
1241  target = get_forward_count (hop_count,
1242  target_replication);
1243  if (0 == target)
1244  {
1245  *targets = NULL;
1246  return 0;
1247  }
1248  rtargets = GNUNET_new_array (target,
1249  struct PeerInfo *);
1250  for (off = 0; off < target; off++)
1251  {
1252  struct PeerInfo *nxt;
1253 
1254  nxt = select_peer (key,
1255  bloom,
1256  hop_count);
1257  if (NULL == nxt)
1258  break;
1259  rtargets[off] = nxt;
1262  &nxt->phash));
1264  &nxt->phash);
1265  }
1267  "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1268  off,
1270  (unsigned int) hop_count,
1271  GNUNET_h2s (key),
1272  target);
1273  if (0 == off)
1274  {
1275  GNUNET_free (rtargets);
1276  *targets = NULL;
1277  return 0;
1278  }
1279  *targets = rtargets;
1281  "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1282  GNUNET_h2s (key),
1283  off,
1284  target);
1285  return off;
1286 }
1287 
1288 
1294 static void
1296 {
1297  struct GNUNET_PeerIdentity pid;
1298  struct GNUNET_HELLO_Builder *b;
1299 
1301  return;
1302 
1304  bd->data_size);
1307  &pid,
1308  &GDS_try_connect,
1309  &pid);
1311 }
1312 
1313 
1317  uint16_t desired_replication_level,
1318  uint16_t hop_count,
1319  struct GNUNET_CONTAINER_BloomFilter *bf)
1320 {
1321  unsigned int target_count;
1322  struct PeerInfo **targets;
1323  size_t msize;
1324  unsigned int skip_count;
1325  unsigned int put_path_length = bd->put_path_length;
1326 
1327  GNUNET_assert (NULL != bf);
1328 #if SANITY_CHECKS > 1
1329  if (0 !=
1331  bd->data_size,
1332  bd->expiration_time,
1333  bd->put_path,
1334  bd->put_path_length,
1335  NULL, 0, /* get_path */
1336  &GDS_my_identity))
1337  {
1338  GNUNET_break_op (0);
1339  put_path_length = 0;
1340  }
1341 #endif
1343  "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1345  GNUNET_h2s (&bd->key),
1347  (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1348 
1349  /* if we got a HELLO, consider it for our own routing table */
1350  hello_check (bd);
1354  "# PUT requests routed",
1355  1,
1356  GNUNET_NO);
1357  target_count
1358  = get_target_peers (&bd->key,
1359  bf,
1360  hop_count,
1361  desired_replication_level,
1362  &targets);
1363  if (0 == target_count)
1364  {
1366  "Routing PUT for %s terminates after %u hops at %s\n",
1367  GNUNET_h2s (&bd->key),
1368  (unsigned int) hop_count,
1370  return GNUNET_NO;
1371  }
1372  msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1373  + bd->data_size;
1374  if (msize + sizeof(struct PeerPutMessage)
1376  {
1377  put_path_length = 0;
1378  msize = bd->data_size;
1379  }
1380  if (msize + sizeof(struct PeerPutMessage)
1382  {
1383  GNUNET_break (0);
1384  GNUNET_free (targets);
1385  return GNUNET_NO;
1386  }
1387  skip_count = 0;
1388  for (unsigned int i = 0; i < target_count; i++)
1389  {
1390  struct PeerInfo *target = targets[i];
1391  struct PeerPutMessage *ppm;
1392  char buf[sizeof (*ppm) + msize] GNUNET_ALIGN;
1393  struct GNUNET_DHT_PathElement *pp;
1394 
1396  "Routing PUT for %s after %u hops to %s\n",
1397  GNUNET_h2s (&bd->key),
1398  (unsigned int) hop_count,
1399  GNUNET_i2s (&target->id));
1400  ppm = (struct PeerPutMessage *) buf;
1402  ppm->header.size = htons (sizeof (buf));
1403  ppm->type = htonl (bd->type);
1404  ppm->options = htons (options);
1405  ppm->hop_count = htons (hop_count + 1);
1407  ppm->put_path_length = htons (put_path_length);
1411  &target->phash));
1414  ppm->bloomfilter,
1415  DHT_BLOOM_SIZE));
1416  ppm->key = bd->key;
1417  pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1418  GNUNET_memcpy (pp,
1419  bd->put_path,
1420  sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1421  /* 0 == put_path_length means path is not being tracked */
1422  if (0 != put_path_length)
1423  {
1424  /* Note that the signature in 'put_path' was not initialized before,
1425  so this is crucial to avoid sending garbage. */
1426  sign_path (bd->data,
1427  bd->data_size,
1428  bd->expiration_time,
1429  &pp[put_path_length - 1].pred,
1430  &target->id,
1431  &pp[put_path_length - 1].sig);
1433  "Signing PUT PATH %u => %s\n",
1434  put_path_length,
1435  GNUNET_B2S (&pp[put_path_length - 1].sig));
1436  }
1437 
1438  GNUNET_memcpy (&pp[put_path_length],
1439  bd->data,
1440  bd->data_size);
1441  do_send (target,
1442  &ppm->header);
1443  }
1444  GNUNET_free (targets);
1446  "# PUT messages queued for transmission",
1447  target_count - skip_count,
1448  GNUNET_NO);
1449  return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1450 }
1451 
1452 
1456  uint16_t desired_replication_level,
1457  uint16_t hop_count,
1458  const struct GNUNET_HashCode *key,
1459  const void *xquery,
1460  size_t xquery_size,
1461  struct GNUNET_BLOCK_Group *bg,
1462  struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1463 {
1464  unsigned int target_count;
1465  struct PeerInfo **targets;
1466  size_t msize;
1467  size_t reply_bf_size;
1468  void *reply_bf;
1469  unsigned int skip_count;
1470  uint32_t bf_nonce;
1471 
1472  GNUNET_assert (NULL != peer_bf);
1474  "# GET requests routed",
1475  1,
1476  GNUNET_NO);
1477  target_count = get_target_peers (key,
1478  peer_bf,
1479  hop_count,
1480  desired_replication_level,
1481  &targets);
1483  "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1485  GNUNET_h2s (key),
1487  (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1488 
1491  if (0 == target_count)
1492  {
1494  "Routing GET for %s terminates after %u hops at %s\n",
1495  GNUNET_h2s (key),
1496  (unsigned int) hop_count,
1498  return GNUNET_NO;
1499  }
1500  if (GNUNET_OK !=
1502  &bf_nonce,
1503  &reply_bf,
1504  &reply_bf_size))
1505  {
1506  reply_bf = NULL;
1507  reply_bf_size = 0;
1509  UINT32_MAX);
1510  }
1511  msize = xquery_size + reply_bf_size;
1512  if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1513  {
1514  GNUNET_break (0);
1515  GNUNET_free (reply_bf);
1516  GNUNET_free (targets);
1517  return GNUNET_NO;
1518  }
1519  /* forward request */
1520  skip_count = 0;
1521  for (unsigned int i = 0; i < target_count; i++)
1522  {
1523  struct PeerInfo *target = targets[i];
1524  struct PeerGetMessage *pgm;
1525  char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1526  char *xq;
1527 
1529  "Routing GET for %s after %u hops to %s\n",
1530  GNUNET_h2s (key),
1531  (unsigned int) hop_count,
1532  GNUNET_i2s (&target->id));
1533  pgm = (struct PeerGetMessage *) buf;
1535  pgm->header.size = htons (sizeof (buf));
1536  pgm->type = htonl (type);
1537  pgm->options = htons (options);
1538  pgm->hop_count = htons (hop_count + 1);
1540  pgm->xquery_size = htonl (xquery_size);
1541  pgm->bf_mutator = bf_nonce;
1544  &target->phash));
1547  pgm->bloomfilter,
1548  DHT_BLOOM_SIZE));
1549  pgm->key = *key;
1550  xq = (char *) &pgm[1];
1551  GNUNET_memcpy (xq,
1552  xquery,
1553  xquery_size);
1554  GNUNET_memcpy (&xq[xquery_size],
1555  reply_bf,
1556  reply_bf_size);
1557  do_send (target,
1558  &pgm->header);
1559  }
1561  "# GET messages queued for transmission",
1562  target_count - skip_count,
1563  GNUNET_NO);
1564  GNUNET_free (targets);
1565  GNUNET_free (reply_bf);
1566  return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1567 }
1568 
1569 
1570 struct PeerInfo *
1572 {
1574  target);
1575 }
1576 
1577 
1578 bool
1580  const struct GDS_DATACACHE_BlockData *bd,
1581  const struct GNUNET_HashCode *query_hash,
1582  unsigned int get_path_length,
1583  const struct GNUNET_DHT_PathElement *get_path)
1584 {
1585  struct GNUNET_DHT_PathElement *paths;
1586  size_t msize;
1587  unsigned int ppl = bd->put_path_length;
1588 
1589 #if SANITY_CHECKS > 1
1590  if (0 !=
1592  bd->data_size,
1593  bd->expiration_time,
1594  bd->put_path,
1595  bd->put_path_length,
1596  get_path,
1597  get_path_length,
1598  &GDS_my_identity))
1599  {
1600  GNUNET_break_op (0);
1601  return false;
1602  }
1603 #endif
1604  msize = bd->data_size + (get_path_length + ppl)
1605  * sizeof(struct GNUNET_DHT_PathElement);
1606  if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1607  (get_path_length >
1608  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1609  (ppl >
1610  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1612  {
1613  ppl = 0;
1614  get_path_length = 0;
1615  msize = bd->data_size + (get_path_length + ppl)
1616  * sizeof(struct GNUNET_DHT_PathElement);
1617  }
1618  if ( (msize + sizeof(struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1619  (get_path_length >
1620  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1621  (ppl >
1622  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
1624  {
1625  GNUNET_break (0);
1626  return false;
1627  }
1629  "Forwarding reply for key %s to peer %s\n",
1630  GNUNET_h2s (query_hash),
1631  GNUNET_i2s (&pi->id));
1633  "# RESULT messages queued for transmission",
1634  1,
1635  GNUNET_NO);
1636  {
1637  struct PeerResultMessage *prm;
1638  char buf[sizeof (*prm) + msize] GNUNET_ALIGN;
1639 
1640  prm = (struct PeerResultMessage *) buf;
1642  prm->header.size = htons (sizeof (buf));
1643  prm->type = htonl (bd->type);
1644  prm->reserved = htonl (0);
1645  prm->put_path_length = htons (ppl);
1646  prm->get_path_length = htons (get_path_length);
1648  prm->key = *query_hash;
1649  paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1650  if (NULL != bd->put_path)
1651  {
1652  GNUNET_memcpy (paths,
1653  bd->put_path,
1654  ppl * sizeof(struct GNUNET_DHT_PathElement));
1655  }
1656  else
1657  {
1658  GNUNET_assert (0 == ppl);
1659  }
1660  if (NULL != get_path)
1661  {
1662  GNUNET_memcpy (&paths[ppl],
1663  get_path,
1664  get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1665  }
1666  else
1667  {
1668  GNUNET_assert (0 == get_path_length);
1669  }
1670  /* 0 == get_path_length+ppl means path is not being tracked */
1671  if (0 != (get_path_length + ppl))
1672  {
1673  /* Note that the last signature in 'paths' was not initialized before,
1674  so this is crucial to avoid sending garbage. */
1675  sign_path (bd->data,
1676  bd->data_size,
1677  bd->expiration_time,
1678  &paths[ppl + get_path_length - 1].pred,
1679  &pi->id,
1680  &paths[ppl + get_path_length - 1].sig);
1682  "Signing GET PATH %u/%u of %s => %s\n",
1683  ppl,
1684  get_path_length,
1685  GNUNET_h2s (query_hash),
1686  GNUNET_B2S (&paths[ppl + get_path_length - 1].sig));
1687  }
1688  GNUNET_memcpy (&paths[ppl + get_path_length],
1689  bd->data,
1690  bd->data_size);
1691 
1692 #if SANITY_CHECKS > 1
1693  {
1694  struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1695 
1696  memcpy (xpaths,
1697  &paths[ppl],
1698  get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1699  xpaths[get_path_length].pred = GDS_my_identity;
1700  if (0 !=
1702  bd->data_size,
1703  bd->expiration_time,
1704  paths,
1705  ppl,
1706  xpaths,
1707  get_path_length + 1,
1708  &pi->id))
1709  {
1710  GNUNET_break (0);
1711  return false;
1712  }
1713  }
1714 #endif
1715  do_send (pi,
1716  &prm->header);
1717  }
1718  return true;
1719 }
1720 
1721 
1729 static enum GNUNET_GenericReturnValue
1730 check_dht_p2p_put (void *cls,
1731  const struct PeerPutMessage *put)
1732 {
1733  uint16_t msize = ntohs (put->header.size);
1734  uint16_t putlen = ntohs (put->put_path_length);
1735 
1736  (void) cls;
1737  if ( (msize <
1738  sizeof(struct PeerPutMessage)
1739  + putlen * sizeof(struct GNUNET_DHT_PathElement)) ||
1740  (putlen >
1742  {
1743  GNUNET_break_op (0);
1744  return GNUNET_SYSERR;
1745  }
1746  return GNUNET_OK;
1747 }
1748 
1749 
1756 static void
1758  const struct PeerPutMessage *put)
1759 {
1760  struct Target *t = cls;
1761  struct PeerInfo *peer = t->pi;
1762  uint16_t msize = ntohs (put->header.size);
1764  = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1765  const struct GNUNET_DHT_PathElement *put_path
1766  = (const struct GNUNET_DHT_PathElement *) &put[1];
1767  uint16_t putlen
1768  = ntohs (put->put_path_length);
1769  struct GDS_DATACACHE_BlockData bd = {
1770  .key = put->key,
1771  .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1772  .type = ntohl (put->type),
1773  .data_size = msize - (sizeof(*put)
1774  + putlen * sizeof(struct GNUNET_DHT_PathElement)),
1775  .data = &put_path[putlen]
1776  };
1777 
1779  "PUT for `%s' from %s with RO (%s/%s)\n",
1780  GNUNET_h2s (&put->key),
1781  GNUNET_i2s (&peer->id),
1783  (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1785  {
1787  "# Expired PUTs discarded",
1788  1,
1789  GNUNET_NO);
1790  return;
1791  }
1792  if (GNUNET_NO ==
1794  bd.type,
1795  bd.data,
1796  bd.data_size))
1797  {
1798  GNUNET_break_op (0);
1799  return;
1800  }
1801  if (0 == (options & GNUNET_DHT_RO_RECORD_ROUTE))
1802  putlen = 0;
1804  "# P2P PUT requests received",
1805  1,
1806  GNUNET_NO);
1808  "# P2P PUT bytes received",
1809  msize,
1810  GNUNET_NO);
1811  {
1812  struct GNUNET_HashCode test_key;
1814 
1816  bd.type,
1817  bd.data,
1818  bd.data_size,
1819  &test_key);
1820  switch (ret)
1821  {
1822  case GNUNET_YES:
1823  if (0 != GNUNET_memcmp (&test_key,
1824  &bd.key))
1825  {
1826  GNUNET_break_op (0);
1827  return;
1828  }
1829  break;
1830  case GNUNET_NO:
1831  /* cannot verify, good luck */
1832  break;
1833  case GNUNET_SYSERR:
1834  /* block type not supported, good luck */
1835  break;
1836  }
1837  }
1838 
1839  {
1840  struct GNUNET_CONTAINER_BloomFilter *bf;
1841  struct GNUNET_DHT_PathElement pp[putlen + 1];
1842 
1848  &peer->phash));
1849  /* extend 'put path' by sender */
1850  bd.put_path = (const struct GNUNET_DHT_PathElement *) pp;
1851  bd.put_path_length = putlen + 1;
1852  if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
1853  {
1854  unsigned int failure_offset;
1855 
1856  GNUNET_memcpy (pp,
1857  put_path,
1858  putlen * sizeof(struct GNUNET_DHT_PathElement));
1859  pp[putlen].pred = peer->id;
1860  /* zero-out signature, not valid until we actually do forward! */
1861  memset (&pp[putlen].sig,
1862  0,
1863  sizeof (pp[putlen].sig));
1864 #if SANITY_CHECKS
1865  /* TODO: might want to eventually implement probabilistic
1866  load-based path verification, but for now it is all or nothing */
1867  failure_offset
1869  bd.data_size,
1870  bd.expiration_time,
1871  pp,
1872  putlen + 1,
1873  NULL, 0, /* get_path */
1874  &GDS_my_identity);
1875 #else
1876  failure_offset = 0;
1877 #endif
1878  if (0 != failure_offset)
1879  {
1881  "Recorded put path invalid at offset %u, truncating\n",
1882  failure_offset);
1883  GNUNET_assert (failure_offset <= putlen);
1884  bd.put_path = &pp[failure_offset];
1885  bd.put_path_length = putlen - failure_offset;
1886  }
1887  }
1888  else
1889  {
1890  bd.put_path_length = 0;
1891  }
1892 
1893  /* give to local clients */
1895  &bd.key,
1896  0, NULL /* get path */));
1897 
1898  /* store locally */
1900  (GDS_am_closest_peer (&put->key,
1901  bf)) )
1903  {
1904  enum GNUNET_GenericReturnValue forwarded;
1905 
1906  /* route to other peers */
1907  forwarded
1909  options,
1910  ntohs (put->desired_replication_level),
1911  ntohs (put->hop_count),
1912  bf);
1913  /* notify monitoring clients */
1915  | ((GNUNET_OK == forwarded)
1917  : 0),
1918  &bd,
1919  ntohs (put->hop_count),
1920  ntohs (put->desired_replication_level));
1921  }
1923  }
1924 }
1925 
1926 
1935 static void
1937  const struct GNUNET_HashCode *query_hash,
1938  struct GNUNET_BLOCK_Group *bg)
1939 {
1940  size_t block_size = 0;
1941 
1942  /* TODO: consider caching our HELLO block for a bit, to
1943  avoid signing too often here... */
1947  NULL,
1948  &block_size));
1949  {
1950  char block[block_size];
1951 
1952  if (GNUNET_OK !=
1955  block,
1956  &block_size))
1957  {
1959  "# FIND PEER requests ignored due to lack of HELLO",
1960  1,
1961  GNUNET_NO);
1962  }
1963  else if (GNUNET_BLOCK_REPLY_OK_MORE ==
1966  bg,
1968  NULL, 0,
1969  block,
1970  block_size))
1971  {
1972  struct GDS_DATACACHE_BlockData bd = {
1974  .expiration_time
1977  .key = GDS_my_identity_hash,
1978  .data = block,
1979  .data_size = block_size
1980  };
1981 
1983  &bd,
1984  query_hash,
1985  0, NULL /* get path */));
1986  }
1987  else
1988  {
1990  "# FIND PEER requests ignored due to Bloomfilter",
1991  1,
1992  GNUNET_NO);
1993  }
1994  }
1995 }
1996 
1997 
2006 static void
2008  const struct GNUNET_HashCode *query_hash,
2009  struct GNUNET_BLOCK_Group *bg)
2010 {
2011  /* Force non-random selection by hop count */
2012  struct PeerInfo *peer;
2013 
2014  peer = select_peer (query_hash,
2015  NULL,
2016  GDS_NSE_get () + 1);
2017  if ( (NULL != peer->hello) &&
2018  (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
2023  bg,
2024  &peer->phash,
2025  NULL, 0, /* xquery */
2026  peer->hello,
2027  peer->hello_size)) )
2028  {
2029  struct GDS_DATACACHE_BlockData bd = {
2031  .expiration_time = peer->hello_expiration,
2032  .key = peer->phash,
2033  .data = peer->hello,
2034  .data_size = peer->hello_size
2035  };
2036 
2038  &bd,
2039  query_hash,
2040  0, NULL /* get path */));
2041  }
2042 }
2043 
2044 
2051 static void
2053  const struct GDS_DATACACHE_BlockData *bd)
2054 {
2055  struct PeerInfo *peer = cls;
2056 
2058  bd,
2059  &bd->key,
2060  0, NULL /* get path */));
2061 }
2062 
2063 
2071 static enum GNUNET_GenericReturnValue
2072 check_dht_p2p_get (void *cls,
2073  const struct PeerGetMessage *get)
2074 {
2075  uint16_t msize = ntohs (get->header.size);
2076  uint32_t xquery_size = ntohl (get->xquery_size);
2077 
2078  (void) cls;
2079  if (msize < sizeof(*get) + xquery_size)
2080  {
2081  GNUNET_break_op (0);
2082  return GNUNET_SYSERR;
2083  }
2084  return GNUNET_OK;
2085 }
2086 
2087 
2094 static void
2096  const struct PeerGetMessage *get)
2097 {
2098  struct Target *t = cls;
2099  struct PeerInfo *peer = t->pi;
2100  uint16_t msize = ntohs (get->header.size);
2101  uint32_t xquery_size = ntohl (get->xquery_size);
2102  uint32_t hop_count = ntohs (get->hop_count);
2103  size_t reply_bf_size = msize - (sizeof(*get) + xquery_size);
2104  enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2106  get->options);
2108  const void *xquery = (const void *) &get[1];
2109 
2110  /* parse and validate message */
2112  "# P2P GET requests received",
2113  1,
2114  GNUNET_NO);
2116  "# P2P GET bytes received",
2117  msize,
2118  GNUNET_NO);
2119  if (GNUNET_NO ==
2121  type,
2122  &get->key,
2123  xquery,
2124  xquery_size))
2125  {
2126  /* request invalid */
2127  GNUNET_break_op (0);
2128  return;
2129  }
2130 
2131  {
2132  struct GNUNET_BLOCK_Group *bg;
2133  struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2134 
2135  peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2140  &peer->phash));
2142  type,
2143  get->bf_mutator,
2144  xquery + xquery_size,
2145  reply_bf_size,
2146  "filter-size",
2147  reply_bf_size,
2148  NULL);
2150  "GET for %s at %s after %u hops\n",
2151  GNUNET_h2s (&get->key),
2153  (unsigned int) hop_count);
2154  /* local lookup (this may update the bg) */
2156  (GDS_am_closest_peer (&get->key,
2157  peer_bf)) )
2158  {
2160  {
2162  "# P2P HELLO lookup requests processed",
2163  1,
2164  GNUNET_NO);
2166  &get->key,
2167  bg);
2170  &get->key,
2171  bg);
2172  }
2173  else
2174  {
2176  eval = GDS_DATACACHE_get_closest (&get->key,
2177  type,
2178  xquery,
2179  xquery_size,
2180  bg,
2182  peer);
2183  else
2184  eval = GDS_DATACACHE_handle_get (&get->key,
2185  type,
2186  xquery,
2187  xquery_size,
2188  bg,
2190  peer);
2191  }
2192  }
2193  else
2194  {
2196  "# P2P GET requests ONLY routed",
2197  1,
2198  GNUNET_NO);
2199  }
2200 
2201  /* remember request for routing replies
2202  TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2203  */
2204  GDS_ROUTING_add (&peer->id,
2205  type,
2206  bg, /* bg now owned by routing, but valid at least until end of this function! */
2207  options,
2208  &get->key,
2209  xquery,
2210  xquery_size);
2211 
2212  /* P2P forwarding */
2213  {
2214  bool forwarded = false;
2215  uint16_t desired_replication_level = ntohs (
2216  get->desired_replication_level);
2217 
2218  if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2219  forwarded = (GNUNET_OK ==
2221  options,
2222  desired_replication_level,
2223  hop_count,
2224  &get->key,
2225  xquery,
2226  xquery_size,
2227  bg,
2228  peer_bf));
2230  options
2231  | (forwarded
2232  ? 0
2234  type,
2235  hop_count,
2236  desired_replication_level,
2237  0,
2238  NULL,
2239  &get->key);
2240  }
2241  /* clean up; note that 'bg' is owned by routing now! */
2243  }
2244 }
2245 
2246 
2256 static bool
2258  const struct GNUNET_HashCode *query_hash,
2259  unsigned int get_path_length,
2260  const struct GNUNET_DHT_PathElement *get_path)
2261 {
2262  /* forward to local clients */
2264  "Forwarding reply to local clients\n");
2265  if (! GDS_CLIENTS_handle_reply (bd,
2266  query_hash,
2267  get_path_length,
2268  get_path))
2269  {
2270  GNUNET_break (0);
2271  return false;
2272  }
2274  get_path,
2275  get_path_length);
2276  if (GNUNET_YES == cache_results)
2277  {
2278  struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2279  + bd->put_path_length)];
2280  struct GDS_DATACACHE_BlockData bdx = *bd;
2281 
2282  GNUNET_memcpy (xput_path,
2283  bd->put_path,
2284  bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
2285  GNUNET_memcpy (&xput_path[bd->put_path_length],
2286  get_path,
2287  get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2288  bdx.put_path = xput_path;
2289  bdx.put_path_length += get_path_length;
2290  GDS_DATACACHE_handle_put (&bdx);
2291  }
2292  /* forward to other peers */
2293  GDS_ROUTING_process (bd,
2294  query_hash,
2295  get_path_length,
2296  get_path);
2297  return true;
2298 }
2299 
2300 
2308 static enum GNUNET_GenericReturnValue
2309 check_dht_p2p_result (void *cls,
2310  const struct PeerResultMessage *prm)
2311 {
2312  uint16_t get_path_length = ntohs (prm->get_path_length);
2313  uint16_t put_path_length = ntohs (prm->put_path_length);
2314  uint16_t msize = ntohs (prm->header.size);
2315 
2316  (void) cls;
2317  if ( (msize <
2318  sizeof(struct PeerResultMessage)
2319  + (get_path_length + put_path_length)
2320  * sizeof(struct GNUNET_DHT_PathElement)) ||
2321  (get_path_length >
2322  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2323  (put_path_length >
2325  {
2326  GNUNET_break_op (0);
2327  return GNUNET_SYSERR;
2328  }
2329  return GNUNET_OK;
2330 }
2331 
2332 
2339 static void
2341  const struct PeerResultMessage *prm)
2342 {
2343  struct Target *t = cls;
2344  struct PeerInfo *peer = t->pi;
2345  uint16_t msize = ntohs (prm->header.size);
2346  uint16_t get_path_length = ntohs (prm->get_path_length);
2347  struct GDS_DATACACHE_BlockData bd = {
2349  .put_path = (const struct GNUNET_DHT_PathElement *) &prm[1],
2350  .put_path_length = ntohs (prm->put_path_length),
2351  .key = prm->key,
2352  .type = ntohl (prm->type)
2353  };
2354  const struct GNUNET_DHT_PathElement *get_path
2355  = &bd.put_path[bd.put_path_length];
2356 
2357  /* parse and validate message */
2359  {
2361  "# Expired results discarded",
2362  1,
2363  GNUNET_NO);
2364  return;
2365  }
2366  get_path = &bd.put_path[bd.put_path_length];
2367  bd.data = (const void *) &get_path[get_path_length];
2368  bd.data_size = msize - (sizeof(struct PeerResultMessage)
2370  * sizeof(struct GNUNET_DHT_PathElement));
2371  if (GNUNET_OK !=
2373  bd.type,
2374  bd.data,
2375  bd.data_size))
2376  {
2377  GNUNET_break_op (0);
2378  return;
2379  }
2381  "# P2P RESULTS received",
2382  1,
2383  GNUNET_NO);
2385  "# P2P RESULT bytes received",
2386  msize,
2387  GNUNET_NO);
2388  {
2390 
2392  bd.type,
2393  bd.data,
2394  bd.data_size,
2395  &bd.key);
2396  if (GNUNET_NO == ret)
2397  bd.key = prm->key;
2398  }
2399 
2400  /* if we got a HELLO, consider it for our own routing table */
2401  hello_check (&bd);
2402 
2403  /* Need to append 'peer' to 'get_path' */
2404  {
2405  struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2406  struct GNUNET_DHT_PathElement *gp = xget_path;
2407  unsigned int failure_offset;
2408 
2409  GNUNET_memcpy (xget_path,
2410  get_path,
2411  get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2412  xget_path[get_path_length].pred = peer->id;
2413  memset (&xget_path[get_path_length].sig,
2414  0,
2415  sizeof (xget_path[get_path_length].sig));
2416 #if SANITY_CHECKS
2417  /* TODO: might want to eventually implement probabilistic
2418  load-based path verification, but for now it is all or nothing */
2419  failure_offset
2421  bd.data_size,
2422  bd.expiration_time,
2423  bd.put_path,
2424  bd.put_path_length,
2425  xget_path,
2426  get_path_length + 1,
2427  &GDS_my_identity);
2428 #else
2429  failure_offset = 0;
2430 #endif
2431  if (0 != failure_offset)
2432  {
2434  "Recorded path invalid at offset %u, truncating\n",
2435  failure_offset);
2436  GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length);
2437  if (failure_offset >= bd.put_path_length)
2438  {
2439  /* failure on get path */
2440  get_path_length -= (failure_offset - bd.put_path_length);
2441  gp = &xget_path[failure_offset - bd.put_path_length];
2442  bd.put_path_length = 0;
2443  }
2444  else
2445  {
2446  /* failure on put path */
2447  bd.put_path = &bd.put_path[failure_offset];
2448  bd.put_path_length -= failure_offset;
2449  }
2450  }
2452  "Extending GET path of length %u with %s\n",
2453  get_path_length,
2454  GNUNET_i2s (&peer->id));
2456  &prm->key,
2457  get_path_length + 1,
2458  gp));
2459  }
2460 }
2461 
2462 
2470 static enum GNUNET_GenericReturnValue
2471 check_dht_p2p_hello (void *cls,
2472  const struct GNUNET_MessageHeader *hello)
2473 {
2474  struct Target *t = cls;
2475  struct PeerInfo *peer = t->pi;
2477  size_t hellob_size;
2478  void *hellob;
2480 
2482  &peer->id,
2483  &hellob,
2484  &hellob_size,
2485  &expiration);
2486  GNUNET_free (hellob);
2487  return ret;
2488 }
2489 
2490 
2497 static void
2499  const struct GNUNET_MessageHeader *hello)
2500 {
2501  struct Target *t = cls;
2502  struct PeerInfo *peer = t->pi;
2503 
2504  GNUNET_free (peer->hello);
2505  peer->hello_size = 0;
2508  &peer->id,
2509  &peer->hello,
2510  &peer->hello_size,
2511  &peer->hello_expiration));
2512 }
2513 
2514 
2515 void
2516 GDS_u_receive (void *cls,
2517  void **tctx,
2518  void **sctx,
2519  const void *message,
2520  size_t message_size)
2521 {
2522  struct Target *t = *tctx;
2523  struct GNUNET_MQ_MessageHandler core_handlers[] = {
2524  GNUNET_MQ_hd_var_size (dht_p2p_get,
2526  struct PeerGetMessage,
2527  t),
2528  GNUNET_MQ_hd_var_size (dht_p2p_put,
2530  struct PeerPutMessage,
2531  t),
2532  GNUNET_MQ_hd_var_size (dht_p2p_result,
2534  struct PeerResultMessage,
2535  t),
2536  GNUNET_MQ_hd_var_size (dht_p2p_hello,
2538  struct GNUNET_MessageHeader,
2539  t),
2541  };
2542  const struct GNUNET_MessageHeader *mh = message;
2543 
2544  (void) cls; /* the 'struct GDS_Underlay' */
2545  (void) sctx; /* our receiver address */
2546  if (NULL == t)
2547  {
2548  /* Received message claiming to originate from myself?
2549  Ignore! */
2550  GNUNET_break_op (0);
2551  return;
2552  }
2553  if (message_size < sizeof (*mh))
2554  {
2555  GNUNET_break_op (0);
2556  return;
2557  }
2558  if (message_size != ntohs (mh->size))
2559  {
2560  GNUNET_break_op (0);
2561  return;
2562  }
2564  "Handling message of type %u from peer %s\n",
2565  ntohs (mh->type),
2566  GNUNET_i2s (&t->pi->id));
2567  if (GNUNET_OK !=
2568  GNUNET_MQ_handle_message (core_handlers,
2569  mh))
2570  {
2571  GNUNET_break_op (0);
2572  return;
2573  }
2574 }
2575 
2576 
2584 void
2585 GDS_try_connect (void *cls,
2586  const char *uri)
2587 {
2588  const struct GNUNET_PeerIdentity *pid = cls;
2589  struct GNUNET_HashCode phash;
2590  int peer_bucket;
2591  struct PeerBucket *bucket;
2592 
2593  if (0 == GNUNET_memcmp (&GDS_my_identity,
2594  pid))
2595  {
2597  "Got a HELLO for my own PID, ignoring it\n");
2598  return; /* that's us! */
2599  }
2601  sizeof(*pid),
2602  &phash);
2603  peer_bucket = find_bucket (&phash);
2604  GNUNET_assert ( (peer_bucket >= 0) &&
2605  ((unsigned int) peer_bucket < MAX_BUCKETS));
2606  bucket = &k_buckets[peer_bucket];
2607  if (bucket->peers_size >= bucket_size)
2608  return; /* do not care */
2609  for (struct PeerInfo *pi = bucket->head;
2610  NULL != pi;
2611  pi = pi->next)
2612  if (0 ==
2613  GNUNET_memcmp (&pi->id,
2614  pid))
2615  {
2616  /* already connected */
2617  /* TODO: maybe consider 'uri' anyway as an additional
2618  alternative address??? */
2619  return;
2620  }
2622  "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2623  GNUNET_i2s (pid),
2624  uri,
2625  peer_bucket,
2626  bucket->peers_size,
2627  bucket_size);
2628  /* new peer that we like! */
2630  uri);
2631 }
2632 
2633 
2639 void
2641 {
2642  for (unsigned int bc = 0; bc<closest_bucket; bc++)
2643  {
2644  struct PeerBucket *bucket = &k_buckets[bc];
2645  unsigned int count = 0;
2646 
2647  for (struct PeerInfo *pos = bucket->head;
2648  NULL != pos;
2649  pos = pos->next)
2650  {
2651  if (count >= bucket_size)
2652  break; /* we only consider first #bucket_size entries per bucket */
2653  count++;
2654  do_send (pos,
2655  msg);
2656  }
2657  }
2658 }
2659 
2660 
2663 {
2664 
2665  unsigned long long temp_config_num;
2666 
2669  "DHT",
2670  "DISABLE_TRY_CONNECT");
2671  if (GNUNET_OK ==
2673  "DHT",
2674  "bucket_size",
2675  &temp_config_num))
2676  bucket_size = (unsigned int) temp_config_num;
2679  "DHT",
2680  "CACHE_RESULTS");
2682  GNUNET_YES);
2683  return GNUNET_OK;
2684 }
2685 
2686 
2687 void
2689 {
2690  if (NULL == all_connected_peers)
2691  return;
2692  GNUNET_assert (0 ==
2695  all_connected_peers = NULL;
2696  GNUNET_assert (NULL == find_peer_task);
2697 }
2698 
2699 
2700 struct GNUNET_PeerIdentity *
2702 {
2703  return &GDS_my_identity;
2704 }
2705 
2706 
2707 /* end of gnunet-service-dht_neighbours.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
#define DHT_BLOOM_SIZE
Size of the bloom filter the DHT uses to filter peers.
Definition: dht.h:34
static char * expiration
Credential TTL.
Definition: gnunet-abd.c:96
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
static struct PendingResolutions * head
Head of list of pending resolution requests.
Definition: gnunet-ats.c:230
static struct GNUNET_CADET_Handle * mh
Cadet handle.
Definition: gnunet-cadet.c:92
static struct GNUNET_PEERINFO_Handle * pi
Handle to peerinfo service.
struct GNUNET_HashCode key
The key used in the DHT.
static int get
Get DID Documement for DID Flag.
Definition: gnunet-did.c:64
uint32_t data
The data value.
static char * value
Value of the record to add/remove.
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_DHTU_PreferenceHandle * GDS_u_hold(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target)
Create a hold on target at underlay u.
struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key
Our private key.
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, unsigned int path_length, const struct GNUNET_DHT_PathElement *path, const struct GNUNET_HashCode *key)
Check if some client is monitoring GET messages and notify them in that case.
struct GNUNET_STATISTICS_Handle * GDS_stats
Handle for the statistics service.
void GDS_CLIENTS_process_put(enum GNUNET_DHT_RouteOption options, const struct GDS_DATACACHE_BlockData *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 GDS_DATACACHE_BlockData *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.
struct GNUNET_BLOCK_Context * GDS_block_context
Our handle to the BLOCK library.
void GDS_CLIENTS_process_get_resp(const struct GDS_DATACACHE_BlockData *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.
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 GDS_DATACACHE_BlockData *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 GDS_DATACACHE_BlockData *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.
#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.
static void handle_local_result(void *cls, const struct GDS_DATACACHE_BlockData *bd)
Handle an exact result from local datacache for a GET operation.
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.
#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 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...
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.
struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id()
Get the ID of the local node.
#define DHT_MINIMUM_FIND_PEER_INTERVAL
How long at least to wait before sending another find peer request.
void GDS_try_connect(void *cls, const char *uri)
Callback function used to extract URIs from a builder.
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.
#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 bool process_reply_with_path(const struct GDS_DATACACHE_BlockData *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.
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 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_NEIGHBOURS_handle_put(const struct GDS_DATACACHE_BlockData *bd, enum GNUNET_DHT_RouteOption options, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
Perform a PUT operation.
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 void hello_check(const struct GDS_DATACACHE_BlockData *bd)
If we got a HELLO, consider it for our own routing table.
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.
struct PeerInfo * GDS_NEIGHBOURS_lookup_peer(const struct GNUNET_PeerIdentity *target)
Lookup peer by peer's identity.
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_process(const struct GDS_DATACACHE_BlockData *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).
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.
GNUnet DHT tracking of requests for routing replies.
static char buf[2048]
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static struct GNUNET_SCHEDULER_Task * t
Main task.
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32.
#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.
Definition: gnunet_common.h:92
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_NO
Definition: gnunet_common.h:94
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
#define GNUNET_MIN(a, b)
#define GNUNET_PACKED
gcc-ism to get packed structs.
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:176
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
@ GNUNET_BLOCK_TYPE_DHT_URL_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.
#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:343
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:317
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:299
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:279
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:173
struct GNUNET_BLOCK_Group * GNUNET_BLOCK_group_create(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, uint32_t nonce, const void *raw_data, size_t raw_data_size,...)
Create a new block group.
Definition: block.c:228
enum GNUNET_GenericReturnValue GNUNET_BLOCK_group_serialize(struct GNUNET_BLOCK_Group *bg, uint32_t *nonce, void **raw_data, size_t *raw_data_size)
Serialize state of a block group.
Definition: block.c:153
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:259
@ GNUNET_BLOCK_REPLY_OK_MORE
Valid result, and there may be more.
@ GNUNET_BLOCK_REPLY_OK_LAST
Last possible valid result.
int 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_add(struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Add an element to the filter.
int GNUNET_CONTAINER_bloomfilter_test(const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Test if an element is in the filter.
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_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)
Random on unsigned 64-bit values.
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).
unsigned int GNUNET_DHT_verify_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, 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:1303
GNUNET_DHT_RouteOption
Options for routing.
#define GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL
Maximum allowed replication level for all requests.
@ 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:242
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).
int 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.
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.
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.
@ 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...
struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_block(const void *block, size_t block_size)
Parse block into builder.
Definition: hello-uri.c:353
void GNUNET_HELLO_builder_free(struct GNUNET_HELLO_Builder *builder)
Release resources of a builder.
Definition: hello-uri.c:312
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:837
void GNUNET_HELLO_builder_iterate(const struct GNUNET_HELLO_Builder *builder, struct GNUNET_PeerIdentity *pid, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a builder.
Definition: hello-uri.c:815
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
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)
Generate DHT block from a builder.
Definition: hello-uri.c:692
#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)
int 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:203
#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.
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:1296
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972
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:1269
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_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition: time.c:736
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:315
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:483
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:637
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition: time.c:668
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:35
Information about a block stored in the datacache.
const void * data
Actual block data.
size_t data_size
Number of bytes in data.
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.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_HashCode key
Key of the block.
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.
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:184
A 512-bit hashcode.
uint32_t bits[512/8/sizeof(uint32_t)]
Message handler for a specific message type.
Header for all communications.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition: scheduler.c:135
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:139
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.
uint32_t bf_mutator
Bloomfilter mutator.
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 xquery_size
Size of the extended query.
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.
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).
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?
struct PendingResolutions * next
Kept in a DLL.
Definition: gnunet-ats.c:159
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.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.