aboutsummaryrefslogtreecommitdiff
path: root/src/service/dht/gnunet-service-dht_neighbours.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/dht/gnunet-service-dht_neighbours.c')
-rw-r--r--src/service/dht/gnunet-service-dht_neighbours.c3009
1 files changed, 3009 insertions, 0 deletions
diff --git a/src/service/dht/gnunet-service-dht_neighbours.c b/src/service/dht/gnunet-service-dht_neighbours.c
new file mode 100644
index 000000000..15a4b21f7
--- /dev/null
+++ b/src/service/dht/gnunet-service-dht_neighbours.c
@@ -0,0 +1,3009 @@
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
21/**
22 * @file dht/gnunet-service-dht_neighbours.c
23 * @brief GNUnet DHT service's bucket and neighbour management code
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_protocols.h"
30#include "gnunet_signatures.h"
31#include "gnunet_hello_uri_lib.h"
32#include "gnunet-service-dht.h"
33#include "gnunet-service-dht_neighbours.h"
34#include "gnunet-service-dht_routing.h"
35#include "dht.h"
36
37#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
38 __VA_ARGS__)
39
40/**
41 * Enable slow sanity checks to debug issues.
42 *
43 * TODO: might want to eventually implement probabilistic
44 * load-based path verification, but for now it is all or nothing
45 * based on this define.
46 *
47 * 0: do not check -- if signatures become performance critical
48 * 1: check all external inputs -- normal production for now
49 * 2: check internal computations as well -- for debugging
50 */
51#define SANITY_CHECKS 2
52
53/**
54 * How many buckets will we allow in total.
55 */
56#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
57
58/**
59 * What is the maximum number of peers in a given bucket.
60 */
61#define DEFAULT_BUCKET_SIZE 8
62
63/**
64 * Desired replication level for FIND PEER requests
65 */
66#define FIND_PEER_REPLICATION_LEVEL 4
67
68/**
69 * Maximum allowed number of pending messages per peer.
70 */
71#define MAXIMUM_PENDING_PER_PEER 64
72
73/**
74 * How long at least to wait before sending another find peer request.
75 * This is basically the frequency at which we will usually send out
76 * requests when we are 'perfectly' connected.
77 */
78#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
79 GNUNET_TIME_UNIT_MINUTES, 2)
80
81
82/**
83 * How long to additionally wait on average per #bucket_size to send out the
84 * FIND PEER requests if we did successfully connect (!) to a a new peer and
85 * added it to a bucket (as counted in #newly_found_peers). This time is
86 * Multiplied by 100 * newly_found_peers / bucket_size to get the new delay
87 * for finding peers (the #DHT_MINIMUM_FIND_PEER_INTERVAL is still added on
88 * top). Also the range in which we randomize, so the effective value
89 * is half of the number given here.
90 */
91#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
92 GNUNET_TIME_UNIT_SECONDS, 6)
93
94/**
95 * How long at most to wait for transmission of a GET request to another peer?
96 */
97#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
98
99
100GNUNET_NETWORK_STRUCT_BEGIN
101
102/**
103 * P2P PUT message
104 */
105struct PeerPutMessage
106{
107 /**
108 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
109 */
110 struct GNUNET_MessageHeader header;
111
112 /**
113 * Content type, must not be zero.
114 */
115 uint32_t type GNUNET_PACKED;
116
117 /**
118 * Processing options
119 */
120 uint16_t options GNUNET_PACKED;
121
122 /**
123 * Hop count
124 */
125 uint16_t hop_count GNUNET_PACKED;
126
127 /**
128 * Replication level for this message
129 */
130 uint16_t desired_replication_level GNUNET_PACKED;
131
132 /**
133 * Length of the PUT path that follows (if tracked).
134 */
135 uint16_t put_path_length GNUNET_PACKED;
136
137 /**
138 * When does the content expire?
139 */
140 struct GNUNET_TIME_AbsoluteNBO expiration_time;
141
142 /**
143 * Bloomfilter (for peer identities) to stop circular routes
144 */
145 char bloomfilter[DHT_BLOOM_SIZE];
146
147 /**
148 * The key we are storing under.
149 */
150 struct GNUNET_HashCode key;
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
162/**
163 * P2P Result message
164 */
165struct PeerResultMessage
166{
167 /**
168 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
169 */
170 struct GNUNET_MessageHeader header;
171
172 /**
173 * Content type.
174 */
175 uint32_t type GNUNET_PACKED;
176
177 /**
178 * Always 0.
179 */
180 uint16_t reserved GNUNET_PACKED;
181
182 /**
183 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value in NBO.
184 */
185 uint16_t options GNUNET_PACKED;
186
187 /**
188 * Length of the PUT path that follows (if tracked).
189 */
190 uint16_t put_path_length GNUNET_PACKED;
191
192 /**
193 * Length of the GET path that follows (if tracked).
194 */
195 uint16_t get_path_length GNUNET_PACKED;
196
197 /**
198 * When does the content expire?
199 */
200 struct GNUNET_TIME_AbsoluteNBO expiration_time;
201
202 /**
203 * The key of the corresponding GET request.
204 */
205 struct GNUNET_HashCode key;
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
219/**
220 * P2P GET message
221 */
222struct PeerGetMessage
223{
224 /**
225 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
226 */
227 struct GNUNET_MessageHeader header;
228
229 /**
230 * Desired content type.
231 */
232 uint32_t type GNUNET_PACKED;
233
234 /**
235 * Processing options
236 */
237 uint16_t options GNUNET_PACKED;
238
239 /**
240 * Hop count
241 */
242 uint16_t hop_count GNUNET_PACKED;
243
244 /**
245 * Desired replication level for this request.
246 */
247 uint16_t desired_replication_level GNUNET_PACKED;
248
249 /**
250 * Size of the result filter.
251 */
252 uint16_t result_filter_size GNUNET_PACKED;
253
254 /**
255 * Bloomfilter (for peer identities) to stop circular routes
256 */
257 char bloomfilter[DHT_BLOOM_SIZE];
258
259 /**
260 * The key we are looking for.
261 */
262 struct GNUNET_HashCode key;
263
264 /* result bloomfilter */
265
266 /* xquery */
267
268};
269GNUNET_NETWORK_STRUCT_END
270
271
272/**
273 * Entry for a peer in a bucket.
274 */
275struct PeerInfo;
276
277
278/**
279 * List of targets that we can use to reach this peer.
280 */
281struct Target
282{
283 /**
284 * Kept in a DLL.
285 */
286 struct Target *next;
287
288 /**
289 * Kept in a DLL.
290 */
291 struct Target *prev;
292
293 /**
294 * Handle for sending messages to this peer.
295 */
296 struct GNUNET_DHTU_Target *utarget;
297
298 /**
299 * Underlay providing this target.
300 */
301 struct GDS_Underlay *u;
302
303 /**
304 * Peer this is a target for.
305 */
306 struct PeerInfo *pi;
307
308 /**
309 * Handle used to 'hold' the connection to this peer.
310 */
311 struct GNUNET_DHTU_PreferenceHandle *ph;
312
313 /**
314 * Set to number of messages are waiting for the transmission to finish.
315 */
316 unsigned int load;
317
318 /**
319 * Set to @a true if the target was dropped, but we could not clean
320 * up yet because @e busy was also true.
321 */
322 bool dropped;
323
324};
325
326
327/**
328 * Entry for a peer in a bucket.
329 */
330struct PeerInfo
331{
332 /**
333 * What is the identity of the peer?
334 */
335 struct GNUNET_PeerIdentity id;
336
337 /**
338 * Hash of @e id.
339 */
340 struct GNUNET_HashCode phash;
341
342 /**
343 * When does our HELLO from this peer expire?
344 */
345 struct GNUNET_TIME_Absolute hello_expiration;
346
347 /**
348 * Next peer entry (DLL)
349 */
350 struct PeerInfo *next;
351
352 /**
353 * Prev peer entry (DLL)
354 */
355 struct PeerInfo *prev;
356
357 /**
358 * Head of DLL of targets for this peer.
359 */
360 struct Target *t_head;
361
362 /**
363 * Tail of DLL of targets for this peer.
364 */
365 struct Target *t_tail;
366
367 /**
368 * Block with a HELLO of this peer.
369 */
370 void *hello;
371
372 /**
373 * Number of bytes in @e hello.
374 */
375 size_t hello_size;
376
377 /**
378 * Which bucket is this peer in?
379 */
380 int peer_bucket;
381};
382
383
384/**
385 * Peers are grouped into buckets.
386 */
387struct PeerBucket
388{
389 /**
390 * Head of DLL
391 */
392 struct PeerInfo *head;
393
394 /**
395 * Tail of DLL
396 */
397 struct PeerInfo *tail;
398
399 /**
400 * Number of peers in the bucket.
401 */
402 unsigned int peers_size;
403};
404
405
406/**
407 * Do we cache all results that we are routing in the local datacache?
408 */
409static int cache_results;
410
411/**
412 * The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
413 */
414static unsigned int closest_bucket;
415
416/**
417 * How many peers have we added since we sent out our last
418 * find peer request?
419 */
420static unsigned int newly_found_peers;
421
422/**
423 * Option for testing that disables the 'connect' function of the DHT.
424 */
425static int disable_try_connect;
426
427/**
428 * The buckets. Array of size #MAX_BUCKETS. Offset 0 means 0 bits matching.
429 */
430static struct PeerBucket k_buckets[MAX_BUCKETS];
431
432/**
433 * Hash map of all CORE-connected peers, for easy removal from
434 * #k_buckets on disconnect. Values are of type `struct PeerInfo`.
435 */
436static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
437
438/**
439 * Maximum size for each bucket.
440 */
441static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
442
443/**
444 * Task that sends FIND PEER requests.
445 */
446static struct GNUNET_SCHEDULER_Task *find_peer_task;
447
448
449/**
450 * Function called whenever we finished sending to a target.
451 * Marks the transmission as finished (and the target as ready
452 * for the next message).
453 *
454 * @param cls a `struct Target *`
455 */
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 */
472 GNUNET_CONTAINER_DLL_remove (pi->t_head,
473 pi->t_tail,
474 t);
475 GNUNET_CONTAINER_DLL_insert (pi->t_head,
476 pi->t_tail,
477 t);
478}
479
480
481/**
482 * Send @a msg to @a pi.
483 *
484 * @param pi where to send the message
485 * @param msg message to send
486 */
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 */
501 GNUNET_STATISTICS_update (GDS_stats,
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 {
511 GNUNET_CONTAINER_DLL_remove (pi->t_head,
512 pi->t_tail,
513 t);
514 GNUNET_CONTAINER_DLL_insert_tail (pi->t_head,
515 pi->t_tail,
516 t);
517 }
518 GDS_u_send (t->u,
519 t->utarget,
520 msg,
521 ntohs (msg->size),
522 &send_done_cb,
523 t);
524}
525
526
527/**
528 * Sign that we are routing a message from @a pred to @a succ.
529 * (So the route is $PRED->us->$SUCC).
530 *
531 * @param data payload (the block)
532 * @param data_size number of bytes in @a data
533 * @param exp_time expiration time of @a data
534 * @param pred predecessor peer ID
535 * @param succ successor peer ID
536 * @param[out] sig where to write the signature
537 * (of purpose #GNUNET_SIGNATURE_PURPOSE_DHT_PUT_HOP)
538 */
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,
545 struct GNUNET_CRYPTO_EddsaSignature *sig)
546{
547 struct GNUNET_DHT_HopSignature hs = {
548 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
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;
556 GNUNET_CRYPTO_hash (data,
557 data_size,
558 &hs.h_data);
559 GNUNET_CRYPTO_eddsa_sign (&GDS_my_private_key,
560 &hs,
561 sig);
562}
563
564
565/**
566 * Find the optimal bucket for this key.
567 *
568 * @param hc the hashcode to compare our identity to
569 * @return the proper bucket index, or -1
570 * on error (same hashcode)
571 */
572static int
573find_bucket (const struct GNUNET_HashCode *hc)
574{
575 struct GNUNET_HashCode xor;
576 unsigned int bits;
577
578 GNUNET_CRYPTO_hash_xor (hc,
579 &GDS_my_identity_hash,
580 &xor);
581 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&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
592/**
593 * Add each of the peers we already know to the Bloom filter of
594 * the request so that we don't get duplicate HELLOs.
595 *
596 * @param cls the `struct GNUNET_BLOCK_Group`
597 * @param key peer identity to add to the bloom filter
598 * @param value the peer information
599 * @return #GNUNET_YES (we should continue to iterate)
600 */
601static enum GNUNET_GenericReturnValue
602add_known_to_bloom (void *cls,
603 const struct GNUNET_PeerIdentity *key,
604 void *value)
605{
606 struct GNUNET_BLOCK_Group *bg = cls;
607 struct PeerInfo *pi = value;
608
609 GNUNET_BLOCK_group_set_seen (bg,
610 &pi->phash,
611 1);
612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
613 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
614 GNUNET_i2s (key));
615 return GNUNET_YES;
616}
617
618
619/**
620 * Task to send a find peer message for our own peer identifier
621 * so that we can find the closest peers in the network to ourselves
622 * and attempt to connect to them.
623 *
624 * @param cls closure for this task, NULL
625 */
626static void
627send_find_peer_message (void *cls)
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 =
642 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
643 + GNUNET_CRYPTO_random_u64 (
644 GNUNET_CRYPTO_QUALITY_WEAK,
645 GNUNET_TIME_relative_multiply (
646 DHT_AVG_FIND_PEER_INTERVAL,
647 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
648 newly_found_peers = 0;
649 GNUNET_assert (NULL == find_peer_task);
650 find_peer_task =
651 GNUNET_SCHEDULER_add_delayed (next_send_time,
652 &send_find_peer_message,
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
663 bg = GNUNET_BLOCK_group_create (GDS_block_context,
664 GNUNET_BLOCK_TYPE_DHT_HELLO,
665 NULL,
666 0,
667 "seen-set-size",
668 GNUNET_CONTAINER_multipeermap_size (
669 all_connected_peers),
670 NULL);
671 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
672 &add_known_to_bloom,
673 bg);
674 peer_bf
675 = GNUNET_CONTAINER_bloomfilter_init (NULL,
676 DHT_BLOOM_SIZE,
677 GNUNET_CONSTANTS_BLOOMFILTER_K);
678 if (GNUNET_OK !=
679 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO,
680 GNUNET_DHT_RO_FIND_APPROXIMATE
681 | GNUNET_DHT_RO_RECORD_ROUTE,
682 FIND_PEER_REPLICATION_LEVEL,
683 0, /* hop count */
684 &GDS_my_identity_hash,
685 NULL, 0, /* xquery */
686 bg,
687 peer_bf))
688 {
689 GNUNET_STATISTICS_update (GDS_stats,
690 "# Failed to initiate FIND PEER lookup",
691 1,
692 GNUNET_NO);
693 }
694 else
695 {
696 GNUNET_STATISTICS_update (GDS_stats,
697 "# FIND PEER messages initiated",
698 1,
699 GNUNET_NO);
700 }
701 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
702 GNUNET_BLOCK_group_destroy (bg);
703 }
704}
705
706
707/**
708 * The list of the first #bucket_size peers of @a bucket
709 * changed. We should thus make sure we have called 'hold'
710 * all of the first bucket_size peers!
711 *
712 * @param[in,out] bucket the bucket where the peer set changed
713 */
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 */
751 if (0 == GNUNET_memcmp (&GDS_my_identity,
752 pid))
753 return;
754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755 "Connected to peer %s\n",
756 GNUNET_i2s (pid));
757 pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
758 pid);
759 if (NULL == pi)
760 {
761 GNUNET_STATISTICS_update (GDS_stats,
762 "# peers connected",
763 1,
764 GNUNET_NO);
765 pi = GNUNET_new (struct PeerInfo);
766 pi->id = *pid;
767 GNUNET_CRYPTO_hash (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];
774 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
775 bucket->tail,
776 pi);
777 bucket->peers_size++;
778 closest_bucket = GNUNET_MAX (closest_bucket,
779 (unsigned int) pi->peer_bucket + 1);
780 GNUNET_assert (GNUNET_OK ==
781 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
782 &pi->id,
783 pi,
784 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
785 if (bucket->peers_size <= bucket_size)
786 {
787 newly_found_peers++;
788 do_hold = true;
789 }
790 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
791 (GNUNET_YES != disable_try_connect) )
792 {
793 /* got a first connection, good time to start with FIND PEER requests... */
794 GNUNET_assert (NULL == find_peer_task);
795 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
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;
806 GNUNET_CONTAINER_DLL_insert (pi->t_head,
807 pi->t_tail,
808 t);
809 *ctx = t;
810
811 }
812 if (do_hold)
813 update_hold (bucket);
814}
815
816
817void
818GDS_u_disconnect (void *ctx)
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;
829 GNUNET_CONTAINER_DLL_remove (pi->t_head,
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 */
850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
851 "Disconnected from peer %s\n",
852 GNUNET_i2s (&pi->id));
853 GNUNET_STATISTICS_update (GDS_stats,
854 "# peers connected",
855 -1,
856 GNUNET_NO);
857 GNUNET_assert (GNUNET_YES ==
858 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
859 &pi->id,
860 pi));
861 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
862 (GNUNET_YES != disable_try_connect))
863 {
864 GNUNET_SCHEDULER_cancel (find_peer_task);
865 find_peer_task = NULL;
866 }
867 GNUNET_assert (pi->peer_bucket >= 0);
868 bucket = &k_buckets[pi->peer_bucket];
869 GNUNET_CONTAINER_DLL_remove (bucket->head,
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) &&
878 (0 == k_buckets[closest_bucket - 1].peers_size))
879 closest_bucket--;
880 GNUNET_free (pi->hello);
881 GNUNET_free (pi);
882}
883
884
885/**
886 * To how many peers should we (on average) forward the request to
887 * obtain the desired target_replication count (on average).
888 *
889 * @param hop_count number of hops the message has traversed
890 * @param target_replication the number of total paths desired
891 * @return Some number of peers to forward the message to
892 */
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 */
905 GNUNET_STATISTICS_update (GDS_stats,
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 =
920 GNUNET_MIN (GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL,
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;
930 random_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
931 UINT32_MAX);
932 if (random_value < (target_value * UINT32_MAX))
933 forward_count++;
934 return GNUNET_MIN (forward_count,
935 GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL);
936}
937
938
939/**
940 * Check whether my identity is closer than any known peers. If a
941 * non-null bloomfilter is given, check if this is the closest peer
942 * that hasn't already been routed to.
943 *
944 * @param key hash code to check closeness to
945 * @param bloom bloomfilter, exclude these entries from the decision
946 * @return #GNUNET_YES if node location is closest,
947 * #GNUNET_NO otherwise.
948 */
949enum GNUNET_GenericReturnValue
950GDS_am_closest_peer (const struct GNUNET_HashCode *key,
951 const struct GNUNET_CONTAINER_BloomFilter *bloom)
952{
953 if (0 == GNUNET_memcmp (&GDS_my_identity_hash,
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 ==
972 GNUNET_CONTAINER_bloomfilter_test (bloom,
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,
980 &GDS_my_identity_hash,
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
999/**
1000 * Select a peer from the routing table that would be a good routing
1001 * destination for sending a message for @a key. The resulting peer
1002 * must not be in the set of @a bloom blocked peers.
1003 *
1004 * Note that we should not ALWAYS select the closest peer to the
1005 * target, we do a "random" peer selection if the number of @a hops
1006 * is below the logarithm of the network size estimate.
1007 *
1008 * In all cases, we only consider at most the first #bucket_size peers of any
1009 * #k_buckets. The other peers in the bucket are there because GNUnet doesn't
1010 * really allow the DHT to "reject" connections, but we only use the first
1011 * #bucket_size, even if more exist. (The idea is to ensure that those
1012 * connections are frequently used, and for others to be not used by the DHT,
1013 * and thus possibly dropped by transport due to disuse).
1014 *
1015 * @param key the key we are selecting a peer to route to
1016 * @param bloom a Bloom filter containing entries this request has seen already
1017 * @param hops how many hops has this message traversed thus far
1018 * @return Peer to route to, or NULL on error
1019 */
1020static struct PeerInfo *
1021select_peer (const struct GNUNET_HashCode *key,
1022 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1023 uint32_t hops)
1024{
1025 if (0 == closest_bucket)
1026 {
1027 GNUNET_STATISTICS_update (GDS_stats,
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
1043 GNUNET_CRYPTO_hash_xor (key,
1044 &GDS_my_identity_hash,
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 ==
1066 GNUNET_CONTAINER_bloomfilter_test (bloom,
1067 &pos->phash)) )
1068 {
1069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 {
1130 GNUNET_STATISTICS_update (GDS_stats,
1131 "# Peer selection failed",
1132 1,
1133 GNUNET_NO);
1134 return NULL;
1135 }
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 ==
1165 GNUNET_CONTAINER_bloomfilter_test (bloom,
1166 &pos->phash)) )
1167 {
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 {
1179 GNUNET_STATISTICS_update (GDS_stats,
1180 "# Peer selection failed",
1181 1,
1182 GNUNET_NO);
1183 return NULL;
1184 }
1185
1186 /* Now actually choose a peer */
1187 selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
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 ==
1203 GNUNET_CONTAINER_bloomfilter_test (bloom,
1204 &pos->phash)) )
1205 continue; /* Ignore bloomfiltered peers */
1206 if (0 == selected--)
1207 {
1208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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
1222/**
1223 * Compute the set of peers that the given request should be
1224 * forwarded to.
1225 *
1226 * @param key routing key
1227 * @param[in,out] bloom Bloom filter excluding peers as targets,
1228 * all selected peers will be added to the Bloom filter
1229 * @param hop_count number of hops the request has traversed so far
1230 * @param target_replication desired number of replicas
1231 * @param[out] targets where to store an array of target peers (to be
1232 * free()ed by the caller)
1233 * @return number of peers returned in @a targets.
1234 */
1235static unsigned int
1236get_target_peers (const struct GNUNET_HashCode *key,
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;
1266 GNUNET_break (GNUNET_NO ==
1267 GNUNET_CONTAINER_bloomfilter_test (bloom,
1268 &nxt->phash));
1269 GNUNET_CONTAINER_bloomfilter_add (bloom,
1270 &nxt->phash);
1271 }
1272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1273 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1274 off,
1275 GNUNET_CONTAINER_multipeermap_size (all_connected_peers),
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;
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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
1295/**
1296 * If we got a HELLO, consider it for our own routing table
1297 *
1298 * @param bd block data we got
1299 */
1300static void
1301hello_check (const struct GNUNET_DATACACHE_Block *bd)
1302{
1303 struct GNUNET_HELLO_Builder *b;
1304
1305 if (GNUNET_BLOCK_TYPE_DHT_HELLO != bd->type)
1306 return;
1307
1308 b = GNUNET_HELLO_builder_from_block (bd->data,
1309 bd->data_size);
1310 if (GNUNET_YES != disable_try_connect)
1311 {
1312 GNUNET_HELLO_builder_iterate (b,
1313 &GDS_try_connect,
1314 NULL);
1315 }
1316 GNUNET_HELLO_builder_free (b);
1317}
1318
1319
1320enum GNUNET_GenericReturnValue
1321GDS_NEIGHBOURS_handle_put (const struct GNUNET_DATACACHE_Block *bd,
1322 uint16_t desired_replication_level,
1323 uint16_t hop_count,
1324 struct GNUNET_CONTAINER_BloomFilter *bf)
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
1344 = GNUNET_DHT_verify_path (bd->data,
1345 bd->data_size,
1346 bd->expiration_time,
1347 trunc_peer,
1348 put_path,
1349 put_path_length,
1350 NULL, 0, /* get_path */
1351 &GDS_my_identity);
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;
1359 ro |= GNUNET_DHT_RO_TRUNCATED;
1360 }
1361#endif
1362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1363 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1364 GNUNET_i2s (&GDS_my_identity),
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);
1372 GNUNET_CONTAINER_bloomfilter_add (bf,
1373 &GDS_my_identity_hash);
1374 GNUNET_STATISTICS_update (GDS_stats,
1375 "# PUT requests routed",
1376 1,
1377 GNUNET_NO);
1378 if (bd->data_size
1379 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_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)
1389 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1390 {
1391 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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)
1407 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1408 {
1409 unsigned int mlen;
1410 unsigned int ppl;
1411
1412 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1413 "Truncating path that is too large due\n");
1414 mlen = GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE - msize;
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;
1429 ro |= GNUNET_DHT_RO_TRUNCATED;
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 {
1443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1444 "Routing PUT for %s terminates after %u hops at %s\n",
1445 GNUNET_h2s (&bd->key),
1446 (unsigned int) hop_count,
1447 GNUNET_i2s (&GDS_my_identity));
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
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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;
1465 ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
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);
1470 ppm->desired_replication_level = htons (desired_replication_level);
1471 ppm->put_path_length = htons (put_path_length);
1472 ppm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1473 GNUNET_break (GNUNET_YES ==
1474 GNUNET_CONTAINER_bloomfilter_test (bf,
1475 &target->phash));
1476 GNUNET_assert (GNUNET_OK ==
1477 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
1478 ppm->bloomfilter,
1479 DHT_BLOOM_SIZE));
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 }
1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 }
1536 GNUNET_memcpy (data,
1537 bd->data,
1538 bd->data_size);
1539 do_send (target,
1540 &ppm->header);
1541 }
1542 GNUNET_free (targets);
1543 GNUNET_STATISTICS_update (GDS_stats,
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
1551enum GNUNET_GenericReturnValue
1552GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1553 enum GNUNET_DHT_RouteOption options,
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);
1570 GNUNET_STATISTICS_update (GDS_stats,
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);
1579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1580 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1581 GNUNET_i2s (&GDS_my_identity),
1582 GNUNET_h2s (key),
1583 (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1584 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1585
1586 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1587 &GDS_my_identity_hash);
1588 if (0 == target_count)
1589 {
1590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591 "Routing GET for %s terminates after %u hops at %s\n",
1592 GNUNET_h2s (key),
1593 (unsigned int) hop_count,
1594 GNUNET_i2s (&GDS_my_identity));
1595 return GNUNET_NO;
1596 }
1597 if (GNUNET_OK !=
1598 GNUNET_BLOCK_group_serialize (bg,
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
1622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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;
1628 pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
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);
1633 pgm->desired_replication_level = htons (desired_replication_level);
1634 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1635 GNUNET_break (GNUNET_YES ==
1636 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1637 &target->phash));
1638 GNUNET_assert (GNUNET_OK ==
1639 GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf,
1640 pgm->bloomfilter,
1641 DHT_BLOOM_SIZE));
1642 pgm->key = *key;
1643 rf = (char *) &pgm[1];
1644 GNUNET_memcpy (rf,
1645 result_filter,
1646 result_filter_size);
1647 GNUNET_memcpy (&rf[result_filter_size],
1648 xquery,
1649 xquery_size);
1650 do_send (target,
1651 &pgm->header);
1652 }
1653 GNUNET_STATISTICS_update (GDS_stats,
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 *
1664GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
1665{
1666 return GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
1667 target);
1668}
1669
1670
1671bool
1672GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
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
1693 = GNUNET_DHT_verify_path (bd->data,
1694 bd->data_size,
1695 bd->expiration_time,
1696 trunc_peer,
1697 put_path,
1698 ppl,
1699 get_path,
1700 get_path_length,
1701 &GDS_my_identity);
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;
1712 ro |= GNUNET_DHT_RO_TRUNCATED;
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;
1724 ro |= GNUNET_DHT_RO_TRUNCATED;
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);
1761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1762 "Forwarding reply for key %s to peer %s\n",
1763 GNUNET_h2s (query_hash),
1764 GNUNET_i2s (&pi->id));
1765 GNUNET_STATISTICS_update (GDS_stats,
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;
1775 prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
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);
1782 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
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 {
1820 struct GNUNET_CRYPTO_EddsaSignature sig;
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);
1842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 !=
1858 GNUNET_DHT_verify_path (bd->data,
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 }
1878 GNUNET_memcpy (data,
1879 bd->data,
1880 bd->data_size);
1881 do_send (pi,
1882 &prm->header);
1883 }
1884 return true;
1885}
1886
1887
1888/**
1889 * Check validity of a p2p put request.
1890 *
1891 * @param cls closure with the `struct PeerInfo` of the sender
1892 * @param put message
1893 * @return #GNUNET_OK if the message is valid
1894 */
1895static enum GNUNET_GenericReturnValue
1896check_dht_p2p_put (void *cls,
1897 const struct PeerPutMessage *put)
1898{
1899 enum GNUNET_DHT_RouteOption ro
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
1936/**
1937 * Core handler for p2p put requests.
1938 *
1939 * @param cls closure with the `struct Target` of the sender
1940 * @param put message
1941 */
1942static void
1943handle_dht_p2p_put (void *cls,
1944 const struct PeerPutMessage *put)
1945{
1946 struct Target *t = cls;
1947 struct PeerInfo *peer = t->pi;
1948 enum GNUNET_DHT_RouteOption ro
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;
1985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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" : "-");
1991 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
1992 {
1993 GNUNET_STATISTICS_update (GDS_stats,
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
2008 = GNUNET_TIME_absolute_get ();
2009 struct GNUNET_TIME_Relative latency;
2010 struct GNUNET_TIME_Relative delta;
2011
2012 if (GNUNET_NO ==
2013 GNUNET_BLOCK_check_block (GDS_block_context,
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
2024 = GNUNET_TIME_relative_divide (
2025 GNUNET_TIME_relative_add (
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) */
2031 delta.rel_value_us
2032 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
2033 avg_latency.rel_value_us > 0
2034 ? avg_latency.rel_value_us
2035 : 1LLU);
2036 next_time = GNUNET_TIME_relative_to_absolute (delta);
2037 }
2038 }
2039 if (! has_path)
2040 putlen = 0;
2041 GNUNET_STATISTICS_update (GDS_stats,
2042 "# P2P PUT requests received",
2043 1,
2044 GNUNET_NO);
2045 GNUNET_STATISTICS_update (GDS_stats,
2046 "# P2P PUT bytes received",
2047 msize,
2048 GNUNET_NO);
2049 {
2050 struct GNUNET_HashCode test_key;
2051 enum GNUNET_GenericReturnValue ret;
2052
2053 ret = GNUNET_BLOCK_get_key (GDS_block_context,
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 {
2078 struct GNUNET_CONTAINER_BloomFilter *bf;
2079 struct GNUNET_DHT_PathElement pp[putlen + 1];
2080
2081 bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter,
2082 DHT_BLOOM_SIZE,
2083 GNUNET_CONSTANTS_BLOOMFILTER_K);
2084 GNUNET_break_op (GNUNET_YES ==
2085 GNUNET_CONTAINER_bloomfilter_test (bf,
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
2103 = GNUNET_DHT_verify_path (bd.data,
2104 bd.data_size,
2105 bd.expiration_time,
2106 trunc_peer,
2107 pp,
2108 putlen + 1,
2109 NULL, 0, /* get_path */
2110 &GDS_my_identity);
2111#else
2112 failure_offset = 0;
2113#endif
2114 if (0 != failure_offset)
2115 {
2116 GNUNET_break_op (0);
2117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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;
2123 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
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 */
2133 GNUNET_break (GDS_CLIENTS_handle_reply (&bd,
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)) )
2141 GDS_DATACACHE_handle_put (&bd);
2142 {
2143 enum GNUNET_GenericReturnValue forwarded;
2144
2145 /* route to other peers */
2146 forwarded
2147 = GDS_NEIGHBOURS_handle_put (&bd,
2148 ntohs (put->desired_replication_level),
2149 ntohs (put->hop_count),
2150 bf);
2151 /* notify monitoring clients */
2152 bd.ro |= ((GNUNET_OK == forwarded)
2153 ? GNUNET_DHT_RO_LAST_HOP
2154 : 0);
2155 GDS_CLIENTS_process_put (&bd,
2156 ntohs (put->hop_count),
2157 ntohs (put->desired_replication_level));
2158 }
2159 GNUNET_CONTAINER_bloomfilter_free (bf);
2160 }
2161}
2162
2163
2164/**
2165 * We have received a request for a HELLO. Sends our
2166 * HELLO back.
2167 *
2168 * @param pi sender of the request
2169 * @param key peers close to this key are desired
2170 * @param bg group for filtering peers
2171 */
2172static void
2173handle_find_my_hello (struct PeerInfo *pi,
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... */
2181 GNUNET_break (GNUNET_NO ==
2182 GNUNET_HELLO_builder_to_block (GDS_my_hello,
2183 &GDS_my_private_key,
2184 NULL,
2185 &block_size,
2186 GNUNET_TIME_UNIT_ZERO));
2187 {
2188 char block[block_size];
2189
2190 if (GNUNET_OK !=
2191 GNUNET_HELLO_builder_to_block (GDS_my_hello,
2192 &GDS_my_private_key,
2193 block,
2194 &block_size,
2195 GNUNET_TIME_UNIT_ZERO))
2196 {
2197 GNUNET_STATISTICS_update (GDS_stats,
2198 "# FIND PEER requests ignored due to lack of HELLO",
2199 1,
2200 GNUNET_NO);
2201 }
2202 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
2203 GNUNET_BLOCK_check_reply (GDS_block_context,
2204 GNUNET_BLOCK_TYPE_DHT_HELLO,
2205 bg,
2206 &GDS_my_identity_hash,
2207 NULL, 0,
2208 block,
2209 block_size))
2210 {
2211 struct GNUNET_DATACACHE_Block bd = {
2212 .type = GNUNET_BLOCK_TYPE_DHT_HELLO,
2213 .expiration_time
2214 = GNUNET_TIME_relative_to_absolute (
2215 GNUNET_HELLO_ADDRESS_EXPIRATION),
2216 .key = GDS_my_identity_hash,
2217 .data = block,
2218 .data_size = block_size
2219 };
2220
2221 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
2222 &bd,
2223 query_hash,
2224 0, NULL /* get path */));
2225 }
2226 else
2227 {
2228 GNUNET_STATISTICS_update (GDS_stats,
2229 "# FIND PEER requests ignored due to Bloomfilter",
2230 1,
2231 GNUNET_NO);
2232 }
2233 }
2234}
2235
2236
2237/**
2238 * We have received a request for nearby HELLOs. Sends matching
2239 * HELLOs back.
2240 *
2241 * @param pi sender of the request
2242 * @param key peers close to this key are desired
2243 * @param bg group for filtering peers
2244 */
2245static void
2246handle_find_local_hello (struct PeerInfo *pi,
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) &&
2257 (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
2258 (GNUNET_BLOCK_REPLY_OK_MORE ==
2259 GNUNET_BLOCK_check_reply (
2260 GDS_block_context,
2261 GNUNET_BLOCK_TYPE_DHT_HELLO,
2262 bg,
2263 &peer->phash,
2264 NULL, 0, /* xquery */
2265 peer->hello,
2266 peer->hello_size)) )
2267 {
2268 struct GNUNET_DATACACHE_Block bd = {
2269 .type = GNUNET_BLOCK_TYPE_DHT_HELLO,
2270 .expiration_time = peer->hello_expiration,
2271 .key = peer->phash,
2272 .data = peer->hello,
2273 .data_size = peer->hello_size
2274 };
2275
2276 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
2277 &bd,
2278 query_hash,
2279 0, NULL /* get path */));
2280 }
2281}
2282
2283
2284/**
2285 * Handle an exact result from local datacache for a GET operation.
2286 *
2287 * @param cls the `struct PeerInfo` for which this is a reply
2288 * @param bd details about the block we found locally
2289 */
2290static void
2291handle_local_result (void *cls,
2292 const struct GNUNET_DATACACHE_Block *bd)
2293{
2294 struct PeerInfo *peer = cls;
2295
2296 GNUNET_break (GDS_NEIGHBOURS_handle_reply (peer,
2297 bd,
2298 &bd->key,
2299 0, NULL /* get path */));
2300}
2301
2302
2303/**
2304 * Check validity of p2p get request.
2305 *
2306 * @param cls closure with the `struct Target` of the sender
2307 * @param get the message
2308 * @return #GNUNET_OK if the message is well-formed
2309 */
2310static enum GNUNET_GenericReturnValue
2311check_dht_p2p_get (void *cls,
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
2327/**
2328 * Core handler for p2p get requests.
2329 *
2330 * @param cls closure with the `struct Target` of the sender
2331 * @param get the message
2332 */
2333static void
2334handle_dht_p2p_get (void *cls,
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);
2343 enum GNUNET_DHT_RouteOption options = (enum GNUNET_DHT_RouteOption) ntohs (
2344 get->options);
2345 enum GNUNET_BLOCK_ReplyEvaluationResult eval = GNUNET_BLOCK_REPLY_OK_MORE;
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 */
2351 GNUNET_STATISTICS_update (GDS_stats,
2352 "# P2P GET requests received",
2353 1,
2354 GNUNET_NO);
2355 GNUNET_STATISTICS_update (GDS_stats,
2356 "# P2P GET bytes received",
2357 msize,
2358 GNUNET_NO);
2359 if (GNUNET_NO ==
2360 GNUNET_BLOCK_check_query (GDS_block_context,
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,
2376 DHT_BLOOM_SIZE,
2377 GNUNET_CONSTANTS_BLOOMFILTER_K);
2378 GNUNET_break_op (GNUNET_YES ==
2379 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2380 &peer->phash));
2381 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2382 type,
2383 result_filter,
2384 result_filter_size,
2385 "filter-size",
2386 result_filter_size,
2387 NULL);
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2389 "GET for %s at %s after %u hops\n",
2390 GNUNET_h2s (&get->key),
2391 GNUNET_i2s (&GDS_my_identity),
2392 (unsigned int) hop_count);
2393 /* local lookup (this may update the bg) */
2394 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2395 (GDS_am_closest_peer (&get->key,
2396 peer_bf)) )
2397 {
2398 if ( (GNUNET_BLOCK_TYPE_DHT_HELLO == type) ||
2399 (GNUNET_BLOCK_TYPE_ANY == type) )
2400 {
2401 GNUNET_STATISTICS_update (GDS_stats,
2402 "# P2P HELLO lookup requests processed",
2403 1,
2404 GNUNET_NO);
2405 handle_find_my_hello (peer,
2406 &get->key,
2407 bg);
2408 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2409 handle_find_local_hello (peer,
2410 &get->key,
2411 bg);
2412 }
2413 if (GNUNET_BLOCK_TYPE_DHT_HELLO != type)
2414 {
2415 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2416 eval = GDS_DATACACHE_get_closest (&get->key,
2417 type,
2418 xquery,
2419 xquery_size,
2420 bg,
2421 &handle_local_result,
2422 peer);
2423 else
2424 eval = GDS_DATACACHE_handle_get (&get->key,
2425 type,
2426 xquery,
2427 xquery_size,
2428 bg,
2429 &handle_local_result,
2430 peer);
2431 }
2432 }
2433 else
2434 {
2435 GNUNET_STATISTICS_update (GDS_stats,
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 ==
2460 GDS_NEIGHBOURS_handle_get (type,
2461 options,
2462 desired_replication_level,
2463 hop_count,
2464 &get->key,
2465 xquery,
2466 xquery_size,
2467 bg,
2468 peer_bf));
2469 GDS_CLIENTS_process_get (
2470 options
2471 | (forwarded
2472 ? 0
2473 : GNUNET_DHT_RO_LAST_HOP),
2474 type,
2475 hop_count,
2476 desired_replication_level,
2477 &get->key);
2478 }
2479 /* clean up; note that 'bg' is owned by routing now! */
2480 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2481 }
2482}
2483
2484
2485/**
2486 * Process a reply, after the @a get_path has been updated.
2487 *
2488 * @param bd block details
2489 * @param query_hash hash of the original query, might not match key in @a bd
2490 * @param get_path_length number of entries in @a get_path
2491 * @param get_path path the reply has taken
2492 * @return true on success
2493 */
2494static bool
2495process_reply_with_path (const struct GNUNET_DATACACHE_Block *bd,
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 */
2501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 }
2511 GDS_CLIENTS_process_get_resp (bd,
2512 get_path,
2513 get_path_length);
2514 if (GNUNET_YES == cache_results)
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
2524 GNUNET_DHT_PathElement));
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;
2530 GDS_DATACACHE_handle_put (&bdx);
2531 }
2532 /* forward to other peers */
2533 GDS_ROUTING_process (bd,
2534 query_hash,
2535 get_path_length,
2536 get_path);
2537 return true;
2538}
2539
2540
2541/**
2542 * Check validity of p2p result message.
2543 *
2544 * @param cls closure
2545 * @param prm message
2546 * @return #GNUNET_YES if the message is well-formed
2547 */
2548static enum GNUNET_GenericReturnValue
2549check_dht_p2p_result (void *cls,
2550 const struct PeerResultMessage *prm)
2551{
2552 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2553 enum GNUNET_DHT_RouteOption ro
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
2580/**
2581 * Core handler for p2p result messages.
2582 *
2583 * @param cls closure
2584 * @param prm message
2585 */
2586static void
2587handle_dht_p2p_result (void *cls,
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);
2593 enum GNUNET_DHT_RouteOption ro
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 = {
2620 .expiration_time = GNUNET_TIME_absolute_ntoh (prm->expiration_time),
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 {
2634 GNUNET_STATISTICS_update (GDS_stats,
2635 "# Expired results discarded",
2636 1,
2637 GNUNET_NO);
2638 return;
2639 }
2640 if (GNUNET_OK !=
2641 GNUNET_BLOCK_check_block (GDS_block_context,
2642 bd.type,
2643 bd.data,
2644 bd.data_size))
2645 {
2646 GNUNET_break_op (0);
2647 return;
2648 }
2649 GNUNET_STATISTICS_update (GDS_stats,
2650 "# P2P RESULTS received",
2651 1,
2652 GNUNET_NO);
2653 GNUNET_STATISTICS_update (GDS_stats,
2654 "# P2P RESULT bytes received",
2655 msize,
2656 GNUNET_NO);
2657 {
2658 enum GNUNET_GenericReturnValue ret;
2659
2660 ret = GNUNET_BLOCK_get_key (GDS_block_context,
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,
2699 &GDS_my_identity);
2700#else
2701 failure_offset = 0;
2702#endif
2703 if (0 != failure_offset)
2704 {
2705 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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 }
2735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 }
2744 GNUNET_break (process_reply_with_path (&bd,
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 }
2756 GNUNET_break (process_reply_with_path (&bd,
2757 &prm->key,
2758 0,
2759 NULL));
2760 }
2761}
2762
2763
2764/**
2765 * Check validity of a p2p hello message.
2766 *
2767 * @param cls closure
2768 * @param hello message
2769 * @return #GNUNET_YES if the message is well-formed
2770 */
2771static enum GNUNET_GenericReturnValue
2772check_dht_p2p_hello (void *cls,
2773 const struct GNUNET_MessageHeader *hello)
2774{
2775 struct Target *t = cls;
2776 struct PeerInfo *peer = t->pi;
2777 enum GNUNET_GenericReturnValue ret;
2778 size_t hellob_size;
2779 void *hellob;
2780 struct GNUNET_TIME_Absolute expiration;
2781
2782 ret = GNUNET_HELLO_dht_msg_to_block (hello,
2783 &peer->id,
2784 &hellob,
2785 &hellob_size,
2786 &expiration);
2787 GNUNET_free (hellob);
2788 return ret;
2789}
2790
2791
2792/**
2793 * Core handler for p2p HELLO messages.
2794 *
2795 * @param cls closure
2796 * @param hello message
2797 */
2798static void
2799handle_dht_p2p_hello (void *cls,
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;
2807 GNUNET_break (GNUNET_OK ==
2808 GNUNET_HELLO_dht_msg_to_block (hello,
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,
2826 GNUNET_MESSAGE_TYPE_DHT_P2P_GET,
2827 struct PeerGetMessage,
2828 t),
2829 GNUNET_MQ_hd_var_size (dht_p2p_put,
2830 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT,
2831 struct PeerPutMessage,
2832 t),
2833 GNUNET_MQ_hd_var_size (dht_p2p_result,
2834 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2835 struct PeerResultMessage,
2836 t),
2837 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2838 GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO,
2839 struct GNUNET_MessageHeader,
2840 t),
2841 GNUNET_MQ_handler_end ()
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 }
2864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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
2878/**
2879 * Callback function used to extract URIs from a builder.
2880 * Called when we should consider connecting to a peer.
2881 *
2882 * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
2883 * @param uri one of the URIs
2884 */
2885void
2886GDS_try_connect (void *cls,
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 {
2898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2899 "Got a HELLO for my own PID, ignoring it\n");
2900 return; /* that's us! */
2901 }
2902 GNUNET_CRYPTO_hash (pid,
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 */
2917 GDS_u_try_connect (pid,
2918 uri);
2919 return;
2920 }
2921 if (bucket->peers_size >= bucket_size)
2922 return; /* do not care */
2923 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
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! */
2931 GDS_u_try_connect (pid,
2932 uri);
2933}
2934
2935
2936/**
2937 * Send @a msg to all peers in our buckets.
2938 *
2939 * @param msg message to broadcast
2940 */
2941void
2942GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
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
2963enum GNUNET_GenericReturnValue
2964GDS_NEIGHBOURS_init ()
2965{
2966
2967 unsigned long long temp_config_num;
2968
2969 disable_try_connect
2970 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2971 "DHT",
2972 "DISABLE_TRY_CONNECT");
2973 if (GNUNET_OK ==
2974 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
2975 "DHT",
2976 "bucket_size",
2977 &temp_config_num))
2978 bucket_size = (unsigned int) temp_config_num;
2979 cache_results
2980 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2981 "DHT",
2982 "CACHE_RESULTS");
2983 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2984 GNUNET_YES);
2985 return GNUNET_OK;
2986}
2987
2988
2989void
2990GDS_NEIGHBOURS_done ()
2991{
2992 if (NULL == all_connected_peers)
2993 return;
2994 GNUNET_assert (0 ==
2995 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2996 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2997 all_connected_peers = NULL;
2998 GNUNET_assert (NULL == find_peer_task);
2999}
3000
3001
3002struct GNUNET_PeerIdentity *
3003GDS_NEIGHBOURS_get_id ()
3004{
3005 return &GDS_my_identity;
3006}
3007
3008
3009/* end of gnunet-service-dht_neighbours.c */