aboutsummaryrefslogtreecommitdiff
path: root/src/dht/gnunet-service-dht_neighbours.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dht/gnunet-service-dht_neighbours.c')
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c2955
1 files changed, 0 insertions, 2955 deletions
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
deleted file mode 100644
index cc7333a9c..000000000
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ /dev/null
@@ -1,2955 +0,0 @@
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_lib.h"
32#include "gnunet_hello_uri_lib.h"
33#include "gnunet-service-dht.h"
34#include "gnunet-service-dht_neighbours.h"
35#include "gnunet-service-dht_routing.h"
36#include "dht.h"
37
38#define LOG_TRAFFIC(kind, ...) GNUNET_log_from (kind, "dht-traffic", \
39 __VA_ARGS__)
40
41/**
42 * Enable slow sanity checks to debug issues.
43 *
44 * TODO: might want to eventually implement probabilistic
45 * load-based path verification, but for now it is all or nothing
46 * based on this define.
47 *
48 * 0: do not check -- if signatures become performance critical
49 * 1: check all external inputs -- normal production for now
50 * 2: check internal computations as well -- for debugging
51 */
52#define SANITY_CHECKS 2
53
54/**
55 * How many buckets will we allow in total.
56 */
57#define MAX_BUCKETS sizeof(struct GNUNET_HashCode) * 8
58
59/**
60 * What is the maximum number of peers in a given bucket.
61 */
62#define DEFAULT_BUCKET_SIZE 8
63
64/**
65 * Desired replication level for FIND PEER requests
66 */
67#define FIND_PEER_REPLICATION_LEVEL 4
68
69/**
70 * Maximum allowed number of pending messages per peer.
71 */
72#define MAXIMUM_PENDING_PER_PEER 64
73
74/**
75 * How long at least to wait before sending another find peer request.
76 * This is basically the frequency at which we will usually send out
77 * requests when we are 'perfectly' connected.
78 */
79#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
80 GNUNET_TIME_UNIT_MINUTES, 2)
81
82
83/**
84 * How long to additionally wait on average per #bucket_size to send out the
85 * FIND PEER requests if we did successfully connect (!) to a a new peer and
86 * added it to a bucket (as counted in #newly_found_peers). This time is
87 * Multiplied by 100 * newly_found_peers / bucket_size to get the new delay
88 * for finding peers (the #DHT_MINIMUM_FIND_PEER_INTERVAL is still added on
89 * top). Also the range in which we randomize, so the effective value
90 * is half of the number given here.
91 */
92#define DHT_AVG_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply ( \
93 GNUNET_TIME_UNIT_SECONDS, 6)
94
95/**
96 * How long at most to wait for transmission of a GET request to another peer?
97 */
98#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
99
100
101GNUNET_NETWORK_STRUCT_BEGIN
102
103/**
104 * P2P PUT message
105 */
106struct PeerPutMessage
107{
108 /**
109 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
110 */
111 struct GNUNET_MessageHeader header;
112
113 /**
114 * Content type.
115 */
116 uint32_t type GNUNET_PACKED;
117
118 /**
119 * Processing options
120 */
121 uint16_t options GNUNET_PACKED;
122
123 /**
124 * Hop count
125 */
126 uint16_t hop_count GNUNET_PACKED;
127
128 /**
129 * Replication level for this message
130 */
131 uint16_t desired_replication_level GNUNET_PACKED;
132
133 /**
134 * Length of the PUT path that follows (if tracked).
135 */
136 uint16_t put_path_length GNUNET_PACKED;
137
138 /**
139 * When does the content expire?
140 */
141 struct GNUNET_TIME_AbsoluteNBO expiration_time;
142
143 /**
144 * Bloomfilter (for peer identities) to stop circular routes
145 */
146 char bloomfilter[DHT_BLOOM_SIZE];
147
148 /**
149 * The key we are storing under.
150 */
151 struct GNUNET_HashCode key;
152
153 /* trunc_peer (if truncated) */
154
155 /* put path (if tracked) */
156
157 /* sender_sig (if path tracking is on) */
158
159 /* Payload */
160};
161
162
163/**
164 * P2P Result message
165 */
166struct PeerResultMessage
167{
168 /**
169 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
170 */
171 struct GNUNET_MessageHeader header;
172
173 /**
174 * Content type.
175 */
176 uint32_t type GNUNET_PACKED;
177
178 /**
179 * Message options, actually an 'enum GNUNET_DHT_RouteOption' value in NBO.
180 */
181 uint32_t options GNUNET_PACKED;
182
183 /**
184 * Length of the PUT path that follows (if tracked).
185 */
186 uint16_t put_path_length GNUNET_PACKED;
187
188 /**
189 * Length of the GET path that follows (if tracked).
190 */
191 uint16_t get_path_length GNUNET_PACKED;
192
193 /**
194 * When does the content expire?
195 */
196 struct GNUNET_TIME_AbsoluteNBO expiration_time;
197
198 /**
199 * The key of the corresponding GET request.
200 */
201 struct GNUNET_HashCode key;
202
203 /* trunc_peer (if truncated) */
204
205 /* put path (if tracked) */
206
207 /* get path (if tracked) */
208
209 /* sender_sig (if path tracking is on) */
210
211 /* Payload */
212};
213
214
215/**
216 * P2P GET message
217 */
218struct PeerGetMessage
219{
220 /**
221 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
222 */
223 struct GNUNET_MessageHeader header;
224
225 /**
226 * Desired content type.
227 */
228 uint32_t type GNUNET_PACKED;
229
230 /**
231 * Processing options
232 */
233 uint16_t options GNUNET_PACKED;
234
235 /**
236 * Hop count
237 */
238 uint16_t hop_count GNUNET_PACKED;
239
240 /**
241 * Desired replication level for this request.
242 */
243 uint16_t desired_replication_level GNUNET_PACKED;
244
245 /**
246 * Size of the result filter.
247 */
248 uint16_t result_filter_size GNUNET_PACKED;
249
250 /**
251 * Bloomfilter (for peer identities) to stop circular routes
252 */
253 char bloomfilter[DHT_BLOOM_SIZE];
254
255 /**
256 * The key we are looking for.
257 */
258 struct GNUNET_HashCode key;
259
260 /* result bloomfilter */
261
262 /* xquery */
263
264};
265GNUNET_NETWORK_STRUCT_END
266
267
268/**
269 * Entry for a peer in a bucket.
270 */
271struct PeerInfo;
272
273
274/**
275 * List of targets that we can use to reach this peer.
276 */
277struct Target
278{
279 /**
280 * Kept in a DLL.
281 */
282 struct Target *next;
283
284 /**
285 * Kept in a DLL.
286 */
287 struct Target *prev;
288
289 /**
290 * Handle for sending messages to this peer.
291 */
292 struct GNUNET_DHTU_Target *utarget;
293
294 /**
295 * Underlay providing this target.
296 */
297 struct GDS_Underlay *u;
298
299 /**
300 * Peer this is a target for.
301 */
302 struct PeerInfo *pi;
303
304 /**
305 * Handle used to 'hold' the connection to this peer.
306 */
307 struct GNUNET_DHTU_PreferenceHandle *ph;
308
309 /**
310 * Set to number of messages are waiting for the transmission to finish.
311 */
312 unsigned int load;
313
314 /**
315 * Set to @a true if the target was dropped, but we could not clean
316 * up yet because @e busy was also true.
317 */
318 bool dropped;
319
320};
321
322
323/**
324 * Entry for a peer in a bucket.
325 */
326struct PeerInfo
327{
328 /**
329 * What is the identity of the peer?
330 */
331 struct GNUNET_PeerIdentity id;
332
333 /**
334 * Hash of @e id.
335 */
336 struct GNUNET_HashCode phash;
337
338 /**
339 * When does our HELLO from this peer expire?
340 */
341 struct GNUNET_TIME_Absolute hello_expiration;
342
343 /**
344 * Next peer entry (DLL)
345 */
346 struct PeerInfo *next;
347
348 /**
349 * Prev peer entry (DLL)
350 */
351 struct PeerInfo *prev;
352
353 /**
354 * Head of DLL of targets for this peer.
355 */
356 struct Target *t_head;
357
358 /**
359 * Tail of DLL of targets for this peer.
360 */
361 struct Target *t_tail;
362
363 /**
364 * Block with a HELLO of this peer.
365 */
366 void *hello;
367
368 /**
369 * Number of bytes in @e hello.
370 */
371 size_t hello_size;
372
373 /**
374 * Which bucket is this peer in?
375 */
376 int peer_bucket;
377};
378
379
380/**
381 * Peers are grouped into buckets.
382 */
383struct PeerBucket
384{
385 /**
386 * Head of DLL
387 */
388 struct PeerInfo *head;
389
390 /**
391 * Tail of DLL
392 */
393 struct PeerInfo *tail;
394
395 /**
396 * Number of peers in the bucket.
397 */
398 unsigned int peers_size;
399};
400
401
402/**
403 * Do we cache all results that we are routing in the local datacache?
404 */
405static int cache_results;
406
407/**
408 * The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
409 */
410static unsigned int closest_bucket;
411
412/**
413 * How many peers have we added since we sent out our last
414 * find peer request?
415 */
416static unsigned int newly_found_peers;
417
418/**
419 * Option for testing that disables the 'connect' function of the DHT.
420 */
421static int disable_try_connect;
422
423/**
424 * The buckets. Array of size #MAX_BUCKETS. Offset 0 means 0 bits matching.
425 */
426static struct PeerBucket k_buckets[MAX_BUCKETS];
427
428/**
429 * Hash map of all CORE-connected peers, for easy removal from
430 * #k_buckets on disconnect. Values are of type `struct PeerInfo`.
431 */
432static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
433
434/**
435 * Maximum size for each bucket.
436 */
437static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
438
439/**
440 * Task that sends FIND PEER requests.
441 */
442static struct GNUNET_SCHEDULER_Task *find_peer_task;
443
444
445/**
446 * Function called whenever we finished sending to a target.
447 * Marks the transmission as finished (and the target as ready
448 * for the next message).
449 *
450 * @param cls a `struct Target *`
451 */
452static void
453send_done_cb (void *cls)
454{
455 struct Target *t = cls;
456 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
457
458 GNUNET_assert (t->load > 0);
459 t->load--;
460 if (0 < t->load)
461 return;
462 if (t->dropped)
463 {
464 GNUNET_free (t);
465 return;
466 }
467 /* move target back to the front */
468 GNUNET_CONTAINER_DLL_remove (pi->t_head,
469 pi->t_tail,
470 t);
471 GNUNET_CONTAINER_DLL_insert (pi->t_head,
472 pi->t_tail,
473 t);
474}
475
476
477/**
478 * Send @a msg to @a pi.
479 *
480 * @param pi where to send the message
481 * @param msg message to send
482 */
483static void
484do_send (struct PeerInfo *pi,
485 const struct GNUNET_MessageHeader *msg)
486{
487 struct Target *t;
488
489 for (t = pi->t_head;
490 NULL != t;
491 t = t->next)
492 if (t->load < MAXIMUM_PENDING_PER_PEER)
493 break;
494 if (NULL == t)
495 {
496 /* all targets busy, drop message */
497 GNUNET_STATISTICS_update (GDS_stats,
498 "# messages dropped (underlays busy)",
499 1,
500 GNUNET_NO);
501 return;
502 }
503 t->load++;
504 /* rotate busy targets to the end */
505 if (MAXIMUM_PENDING_PER_PEER == t->load)
506 {
507 GNUNET_CONTAINER_DLL_remove (pi->t_head,
508 pi->t_tail,
509 t);
510 GNUNET_CONTAINER_DLL_insert_tail (pi->t_head,
511 pi->t_tail,
512 t);
513 }
514 GDS_u_send (t->u,
515 t->utarget,
516 msg,
517 ntohs (msg->size),
518 &send_done_cb,
519 t);
520}
521
522
523/**
524 * Sign that we are routing a message from @a pred to @a succ.
525 * (So the route is $PRED->us->$SUCC).
526 *
527 * @param key key of the data (not necessarily the query hash)
528 * @param data payload (the block)
529 * @param data_size number of bytes in @a data
530 * @param exp_time expiration time of @a data
531 * @param pred predecessor peer ID
532 * @param succ successor peer ID
533 * @param[out] sig where to write the signature
534 * (of purpose #GNUNET_SIGNATURE_PURPOSE_DHT_PUT_HOP)
535 */
536static void
537sign_path (const void *data,
538 size_t data_size,
539 struct GNUNET_TIME_Absolute exp_time,
540 const struct GNUNET_PeerIdentity *pred,
541 const struct GNUNET_PeerIdentity *succ,
542 struct GNUNET_CRYPTO_EddsaSignature *sig)
543{
544 struct GNUNET_DHT_HopSignature hs = {
545 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
546 .purpose.size = htonl (sizeof (hs)),
547 .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
548 .succ = *succ
549 };
550
551 if (NULL != pred)
552 hs.pred = *pred;
553 GNUNET_CRYPTO_hash (data,
554 data_size,
555 &hs.h_data);
556 GNUNET_CRYPTO_eddsa_sign (&GDS_my_private_key,
557 &hs,
558 sig);
559}
560
561
562/**
563 * Find the optimal bucket for this key.
564 *
565 * @param hc the hashcode to compare our identity to
566 * @return the proper bucket index, or -1
567 * on error (same hashcode)
568 */
569static int
570find_bucket (const struct GNUNET_HashCode *hc)
571{
572 struct GNUNET_HashCode xor;
573 unsigned int bits;
574
575 GNUNET_CRYPTO_hash_xor (hc,
576 &GDS_my_identity_hash,
577 &xor);
578 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
579 if (bits == MAX_BUCKETS)
580 {
581 /* How can all bits match? Got my own ID? */
582 GNUNET_break (0);
583 return -1;
584 }
585 return MAX_BUCKETS - bits - 1;
586}
587
588
589/**
590 * Add each of the peers we already know to the Bloom filter of
591 * the request so that we don't get duplicate HELLOs.
592 *
593 * @param cls the `struct GNUNET_BLOCK_Group`
594 * @param key peer identity to add to the bloom filter
595 * @param value the peer information
596 * @return #GNUNET_YES (we should continue to iterate)
597 */
598static enum GNUNET_GenericReturnValue
599add_known_to_bloom (void *cls,
600 const struct GNUNET_PeerIdentity *key,
601 void *value)
602{
603 struct GNUNET_BLOCK_Group *bg = cls;
604 struct PeerInfo *pi = value;
605
606 GNUNET_BLOCK_group_set_seen (bg,
607 &pi->phash,
608 1);
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
611 GNUNET_i2s (key));
612 return GNUNET_YES;
613}
614
615
616/**
617 * Task to send a find peer message for our own peer identifier
618 * so that we can find the closest peers in the network to ourselves
619 * and attempt to connect to them.
620 *
621 * @param cls closure for this task, NULL
622 */
623static void
624send_find_peer_message (void *cls)
625{
626 (void) cls;
627
628 /* Compute when to do this again (and if we should
629 even send a message right now) */
630 {
631 struct GNUNET_TIME_Relative next_send_time;
632 bool done_early;
633
634 find_peer_task = NULL;
635 done_early = (newly_found_peers > bucket_size);
636 /* schedule next round, taking longer if we found more peers
637 in the last round. */
638 next_send_time.rel_value_us =
639 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
640 + GNUNET_CRYPTO_random_u64 (
641 GNUNET_CRYPTO_QUALITY_WEAK,
642 GNUNET_TIME_relative_multiply (
643 DHT_AVG_FIND_PEER_INTERVAL,
644 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
645 newly_found_peers = 0;
646 GNUNET_assert (NULL == find_peer_task);
647 find_peer_task =
648 GNUNET_SCHEDULER_add_delayed (next_send_time,
649 &send_find_peer_message,
650 NULL);
651 if (done_early)
652 return;
653 }
654
655 /* actually send 'find peer' request */
656 {
657 struct GNUNET_BLOCK_Group *bg;
658 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
659
660 bg = GNUNET_BLOCK_group_create (GDS_block_context,
661 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
662 NULL,
663 0,
664 "filter-size",
665 DHT_BLOOM_SIZE,
666 NULL);
667 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
668 &add_known_to_bloom,
669 bg);
670 peer_bf
671 = GNUNET_CONTAINER_bloomfilter_init (NULL,
672 DHT_BLOOM_SIZE,
673 GNUNET_CONSTANTS_BLOOMFILTER_K);
674 if (GNUNET_OK !=
675 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
676 GNUNET_DHT_RO_FIND_APPROXIMATE
677 | GNUNET_DHT_RO_RECORD_ROUTE,
678 FIND_PEER_REPLICATION_LEVEL,
679 0, /* hop count */
680 &GDS_my_identity_hash,
681 NULL, 0, /* xquery */
682 bg,
683 peer_bf))
684 {
685 GNUNET_STATISTICS_update (GDS_stats,
686 "# Failed to initiate FIND PEER lookup",
687 1,
688 GNUNET_NO);
689 }
690 else
691 {
692 GNUNET_STATISTICS_update (GDS_stats,
693 "# FIND PEER messages initiated",
694 1,
695 GNUNET_NO);
696 }
697 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
698 GNUNET_BLOCK_group_destroy (bg);
699 }
700}
701
702
703/**
704 * The list of the first #bucket_size peers of @a bucket
705 * changed. We should thus make sure we have called 'hold'
706 * all of the first bucket_size peers!
707 *
708 * @param[in,out] bucket the bucket where the peer set changed
709 */
710static void
711update_hold (struct PeerBucket *bucket)
712{
713 unsigned int off = 0;
714
715 /* find the peer -- we just go over all of them, should
716 be hardly any more expensive than just finding the 'right'
717 one. */
718 for (struct PeerInfo *pos = bucket->head;
719 NULL != pos;
720 pos = pos->next)
721 {
722 if (off > bucket_size)
723 break; /* We only hold up to #bucket_size peers per bucket */
724 off++;
725 for (struct Target *tp = pos->t_head;
726 NULL != tp;
727 tp = tp->next)
728 if (NULL == tp->ph)
729 tp->ph = GDS_u_hold (tp->u,
730 tp->utarget);
731 }
732}
733
734
735void
736GDS_u_connect (void *cls,
737 struct GNUNET_DHTU_Target *target,
738 const struct GNUNET_PeerIdentity *pid,
739 void **ctx)
740{
741 struct GDS_Underlay *u = cls;
742 struct PeerInfo *pi;
743 struct PeerBucket *bucket;
744 bool do_hold = false;
745
746 /* Check for connect to self message */
747 if (0 == GNUNET_memcmp (&GDS_my_identity,
748 pid))
749 return;
750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
751 "Connected to peer %s\n",
752 GNUNET_i2s (pid));
753 pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
754 pid);
755 if (NULL == pi)
756 {
757 GNUNET_STATISTICS_update (GDS_stats,
758 "# peers connected",
759 1,
760 GNUNET_NO);
761 pi = GNUNET_new (struct PeerInfo);
762 pi->id = *pid;
763 GNUNET_CRYPTO_hash (pid,
764 sizeof(*pid),
765 &pi->phash);
766 pi->peer_bucket = find_bucket (&pi->phash);
767 GNUNET_assert ( (pi->peer_bucket >= 0) &&
768 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
769 bucket = &k_buckets[pi->peer_bucket];
770 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
771 bucket->tail,
772 pi);
773 bucket->peers_size++;
774 closest_bucket = GNUNET_MAX (closest_bucket,
775 (unsigned int) pi->peer_bucket + 1);
776 GNUNET_assert (GNUNET_OK ==
777 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
778 &pi->id,
779 pi,
780 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
781 if (bucket->peers_size <= bucket_size)
782 {
783 newly_found_peers++;
784 do_hold = true;
785 }
786 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
787 (GNUNET_YES != disable_try_connect) )
788 {
789 /* got a first connection, good time to start with FIND PEER requests... */
790 GNUNET_assert (NULL == find_peer_task);
791 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
792 NULL);
793 }
794 }
795 {
796 struct Target *t;
797
798 t = GNUNET_new (struct Target);
799 t->u = u;
800 t->utarget = target;
801 t->pi = pi;
802 GNUNET_CONTAINER_DLL_insert (pi->t_head,
803 pi->t_tail,
804 t);
805 *ctx = t;
806
807 }
808 if (do_hold)
809 update_hold (bucket);
810}
811
812
813void
814GDS_u_disconnect (void *ctx)
815{
816 struct Target *t = ctx;
817 struct PeerInfo *pi;
818 struct PeerBucket *bucket;
819 bool was_held = false;
820
821 /* Check for disconnect from self message (on shutdown) */
822 if (NULL == t)
823 return;
824 pi = t->pi;
825 GNUNET_CONTAINER_DLL_remove (pi->t_head,
826 pi->t_tail,
827 t);
828 if (NULL != t->ph)
829 {
830 GDS_u_drop (t->u,
831 t->ph);
832 t->ph = NULL;
833 was_held = true;
834 }
835 if (t->load > 0)
836 {
837 t->dropped = true;
838 t->pi = NULL;
839 }
840 else
841 {
842 GNUNET_free (t);
843 }
844 if (NULL != pi->t_head)
845 return; /* got other connections still */
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847 "Disconnected from peer %s\n",
848 GNUNET_i2s (&pi->id));
849 GNUNET_STATISTICS_update (GDS_stats,
850 "# peers connected",
851 -1,
852 GNUNET_NO);
853 GNUNET_assert (GNUNET_YES ==
854 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
855 &pi->id,
856 pi));
857 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
858 (GNUNET_YES != disable_try_connect))
859 {
860 GNUNET_SCHEDULER_cancel (find_peer_task);
861 find_peer_task = NULL;
862 }
863 GNUNET_assert (pi->peer_bucket >= 0);
864 bucket = &k_buckets[pi->peer_bucket];
865 GNUNET_CONTAINER_DLL_remove (bucket->head,
866 bucket->tail,
867 pi);
868 GNUNET_assert (bucket->peers_size > 0);
869 bucket->peers_size--;
870 if ( (was_held) &&
871 (bucket->peers_size >= bucket_size - 1) )
872 update_hold (bucket);
873 while ( (closest_bucket > 0) &&
874 (0 == k_buckets[closest_bucket - 1].peers_size))
875 closest_bucket--;
876 GNUNET_free (pi->hello);
877 GNUNET_free (pi);
878}
879
880
881/**
882 * To how many peers should we (on average) forward the request to
883 * obtain the desired target_replication count (on average).
884 *
885 * @param hop_count number of hops the message has traversed
886 * @param target_replication the number of total paths desired
887 * @return Some number of peers to forward the message to
888 */
889static unsigned int
890get_forward_count (uint16_t hop_count,
891 uint16_t target_replication)
892{
893 uint32_t random_value;
894 uint32_t forward_count;
895 float target_value;
896 float rm1;
897
898 if (hop_count > GDS_NSE_get () * 4.0)
899 {
900 /* forcefully terminate */
901 GNUNET_STATISTICS_update (GDS_stats,
902 "# requests TTL-dropped",
903 1,
904 GNUNET_NO);
905 return 0;
906 }
907 if (hop_count > GDS_NSE_get () * 2.0)
908 {
909 /* Once we have reached our ideal number of hops, only forward to 1 peer */
910 return 1;
911 }
912 /* bound by system-wide maximum and minimum */
913 if (0 == target_replication)
914 target_replication = 1; /* 0 is verboten */
915 target_replication =
916 GNUNET_MIN (GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL,
917 target_replication);
918 rm1 = target_replication - 1.0;
919 target_value =
920 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
921
922 /* Set forward count to floor of target_value */
923 forward_count = (uint32_t) target_value;
924 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
925 target_value = target_value - forward_count;
926 random_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
927 UINT32_MAX);
928 if (random_value < (target_value * UINT32_MAX))
929 forward_count++;
930 return GNUNET_MIN (forward_count,
931 GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL);
932}
933
934
935/**
936 * Check whether my identity is closer than any known peers. If a
937 * non-null bloomfilter is given, check if this is the closest peer
938 * that hasn't already been routed to.
939 *
940 * @param key hash code to check closeness to
941 * @param bloom bloomfilter, exclude these entries from the decision
942 * @return #GNUNET_YES if node location is closest,
943 * #GNUNET_NO otherwise.
944 */
945enum GNUNET_GenericReturnValue
946GDS_am_closest_peer (const struct GNUNET_HashCode *key,
947 const struct GNUNET_CONTAINER_BloomFilter *bloom)
948{
949 if (0 == GNUNET_memcmp (&GDS_my_identity_hash,
950 key))
951 return GNUNET_YES;
952 for (int bucket_num = find_bucket (key);
953 bucket_num < closest_bucket;
954 bucket_num++)
955 {
956 unsigned int count = 0;
957
958 GNUNET_assert (bucket_num >= 0);
959 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
960 NULL != pos;
961 pos = pos->next)
962 {
963 if (count >= bucket_size)
964 break; /* we only consider first #bucket_size entries per bucket */
965 count++;
966 if ( (NULL != bloom) &&
967 (GNUNET_YES ==
968 GNUNET_CONTAINER_bloomfilter_test (bloom,
969 &pos->phash)) )
970 continue; /* Ignore filtered peers */
971 /* All peers in this bucket must be closer than us, as
972 they mismatch with our PID on the pivotal bit. So
973 because an unfiltered peer exists, we are not the
974 closest. */
975 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
976 &GDS_my_identity_hash,
977 key);
978 switch (delta)
979 {
980 case -1: /* pos closer */
981 return GNUNET_NO;
982 case 0: /* identical, impossible! */
983 GNUNET_assert (0);
984 break;
985 case 1: /* I am closer */
986 break;
987 }
988 }
989 }
990 /* No closer (unfiltered) peers found; we must be the closest! */
991 return GNUNET_YES;
992}
993
994
995/**
996 * Select a peer from the routing table that would be a good routing
997 * destination for sending a message for @a key. The resulting peer
998 * must not be in the set of @a bloom blocked peers.
999 *
1000 * Note that we should not ALWAYS select the closest peer to the
1001 * target, we do a "random" peer selection if the number of @a hops
1002 * is below the logarithm of the network size estimate.
1003 *
1004 * In all cases, we only consider at most the first #bucket_size peers of any
1005 * #k_buckets. The other peers in the bucket are there because GNUnet doesn't
1006 * really allow the DHT to "reject" connections, but we only use the first
1007 * #bucket_size, even if more exist. (The idea is to ensure that those
1008 * connections are frequently used, and for others to be not used by the DHT,
1009 * and thus possibly dropped by transport due to disuse).
1010 *
1011 * @param key the key we are selecting a peer to route to
1012 * @param bloom a Bloom filter containing entries this request has seen already
1013 * @param hops how many hops has this message traversed thus far
1014 * @return Peer to route to, or NULL on error
1015 */
1016static struct PeerInfo *
1017select_peer (const struct GNUNET_HashCode *key,
1018 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1019 uint32_t hops)
1020{
1021 if (0 == closest_bucket)
1022 {
1023 GNUNET_STATISTICS_update (GDS_stats,
1024 "# Peer selection failed",
1025 1,
1026 GNUNET_NO);
1027 return NULL; /* we have zero connections */
1028 }
1029 if (hops >= GDS_NSE_get ())
1030 {
1031 /* greedy selection (closest peer that is not in Bloom filter) */
1032 struct PeerInfo *chosen = NULL;
1033 int best_bucket;
1034 int bucket_offset;
1035
1036 {
1037 struct GNUNET_HashCode xor;
1038
1039 GNUNET_CRYPTO_hash_xor (key,
1040 &GDS_my_identity_hash,
1041 &xor);
1042 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1043 }
1044 if (best_bucket >= closest_bucket)
1045 bucket_offset = closest_bucket - 1;
1046 else
1047 bucket_offset = best_bucket;
1048 while (-1 != bucket_offset)
1049 {
1050 struct PeerBucket *bucket = &k_buckets[bucket_offset];
1051 unsigned int count = 0;
1052
1053 for (struct PeerInfo *pos = bucket->head;
1054 NULL != pos;
1055 pos = pos->next)
1056 {
1057 if (count >= bucket_size)
1058 break; /* we only consider first #bucket_size entries per bucket */
1059 count++;
1060 if ( (NULL != bloom) &&
1061 (GNUNET_YES ==
1062 GNUNET_CONTAINER_bloomfilter_test (bloom,
1063 &pos->phash)) )
1064 {
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1067 GNUNET_i2s (&pos->id),
1068 GNUNET_h2s (key));
1069 continue;
1070 }
1071 if (NULL == chosen)
1072 {
1073 /* First candidate */
1074 chosen = pos;
1075 }
1076 else
1077 {
1078 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1079 &chosen->phash,
1080 key);
1081 switch (delta)
1082 {
1083 case -1: /* pos closer */
1084 chosen = pos;
1085 break;
1086 case 0: /* identical, impossible! */
1087 GNUNET_assert (0);
1088 break;
1089 case 1: /* chosen closer */
1090 break;
1091 }
1092 }
1093 count++;
1094 } /* for all (#bucket_size) peers in bucket */
1095 if (NULL != chosen)
1096 break;
1097
1098 /* If we chose nothing in first iteration, first go through deeper
1099 buckets (best chance to find a good match), and if we still found
1100 nothing, then to shallower buckets. Terminate on any match in the
1101 current bucket, as this search order guarantees that it can only get
1102 worse as we keep going. */
1103 if (bucket_offset > best_bucket)
1104 {
1105 /* Go through more deeper buckets */
1106 bucket_offset++;
1107 if (bucket_offset == closest_bucket)
1108 {
1109 /* Can't go any deeper, if nothing selected,
1110 go for shallower buckets */
1111 bucket_offset = best_bucket - 1;
1112 }
1113 }
1114 else
1115 {
1116 /* We're either at the 'best_bucket' or already moving
1117 on to shallower buckets. */
1118 if (bucket_offset == best_bucket)
1119 bucket_offset++; /* go for deeper buckets */
1120 else
1121 bucket_offset--; /* go for shallower buckets */
1122 }
1123 } /* for applicable buckets (starting at best match) */
1124 if (NULL == chosen)
1125 {
1126 GNUNET_STATISTICS_update (GDS_stats,
1127 "# Peer selection failed",
1128 1,
1129 GNUNET_NO);
1130 return NULL;
1131 }
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Selected peer `%s' in greedy routing for %s\n",
1134 GNUNET_i2s (&chosen->id),
1135 GNUNET_h2s (key));
1136 return chosen;
1137 } /* end of 'greedy' peer selection */
1138
1139 /* select "random" peer */
1140 /* count number of peers that are available and not filtered,
1141 but limit to at most #bucket_size peers, starting with
1142 those 'furthest' from us. */
1143 {
1144 unsigned int total = 0;
1145 unsigned int selected;
1146
1147 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1148 {
1149 struct PeerBucket *bucket = &k_buckets[bc];
1150 unsigned int count = 0;
1151
1152 for (struct PeerInfo *pos = bucket->head;
1153 NULL != pos;
1154 pos = pos->next)
1155 {
1156 count++;
1157 if (count > bucket_size)
1158 break; /* limits search to #bucket_size peers per bucket */
1159 if ( (NULL != bloom) &&
1160 (GNUNET_YES ==
1161 GNUNET_CONTAINER_bloomfilter_test (bloom,
1162 &pos->phash)) )
1163 {
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 "Excluded peer `%s' due to BF match in random routing for %s\n",
1166 GNUNET_i2s (&pos->id),
1167 GNUNET_h2s (key));
1168 continue; /* Ignore filtered peers */
1169 }
1170 total++;
1171 } /* for all peers in bucket */
1172 } /* for all buckets */
1173 if (0 == total) /* No peers to select from! */
1174 {
1175 GNUNET_STATISTICS_update (GDS_stats,
1176 "# Peer selection failed",
1177 1,
1178 GNUNET_NO);
1179 return NULL;
1180 }
1181
1182 /* Now actually choose a peer */
1183 selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1184 total);
1185 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1186 {
1187 unsigned int count = 0;
1188
1189 for (struct PeerInfo *pos = k_buckets[bc].head;
1190 pos != NULL;
1191 pos = pos->next)
1192 {
1193 count++;
1194 if (count > bucket_size)
1195 break; /* limits search to #bucket_size peers per bucket */
1196
1197 if ( (NULL != bloom) &&
1198 (GNUNET_YES ==
1199 GNUNET_CONTAINER_bloomfilter_test (bloom,
1200 &pos->phash)) )
1201 continue; /* Ignore bloomfiltered peers */
1202 if (0 == selected--)
1203 {
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "Selected peer `%s' in random routing for %s\n",
1206 GNUNET_i2s (&pos->id),
1207 GNUNET_h2s (key));
1208 return pos;
1209 }
1210 } /* for peers in bucket */
1211 } /* for all buckets */
1212 } /* random peer selection scope */
1213 GNUNET_break (0);
1214 return NULL;
1215}
1216
1217
1218/**
1219 * Compute the set of peers that the given request should be
1220 * forwarded to.
1221 *
1222 * @param key routing key
1223 * @param[in,out] bloom Bloom filter excluding peers as targets,
1224 * all selected peers will be added to the Bloom filter
1225 * @param hop_count number of hops the request has traversed so far
1226 * @param target_replication desired number of replicas
1227 * @param[out] targets where to store an array of target peers (to be
1228 * free()ed by the caller)
1229 * @return number of peers returned in @a targets.
1230 */
1231static unsigned int
1232get_target_peers (const struct GNUNET_HashCode *key,
1233 struct GNUNET_CONTAINER_BloomFilter *bloom,
1234 uint16_t hop_count,
1235 uint16_t target_replication,
1236 struct PeerInfo ***targets)
1237{
1238 unsigned int target;
1239 unsigned int off;
1240 struct PeerInfo **rtargets;
1241
1242 GNUNET_assert (NULL != bloom);
1243 target = get_forward_count (hop_count,
1244 target_replication);
1245 if (0 == target)
1246 {
1247 *targets = NULL;
1248 return 0;
1249 }
1250 rtargets = GNUNET_new_array (target,
1251 struct PeerInfo *);
1252 for (off = 0; off < target; off++)
1253 {
1254 struct PeerInfo *nxt;
1255
1256 nxt = select_peer (key,
1257 bloom,
1258 hop_count);
1259 if (NULL == nxt)
1260 break;
1261 rtargets[off] = nxt;
1262 GNUNET_break (GNUNET_NO ==
1263 GNUNET_CONTAINER_bloomfilter_test (bloom,
1264 &nxt->phash));
1265 GNUNET_CONTAINER_bloomfilter_add (bloom,
1266 &nxt->phash);
1267 }
1268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1269 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1270 off,
1271 GNUNET_CONTAINER_multipeermap_size (all_connected_peers),
1272 (unsigned int) hop_count,
1273 GNUNET_h2s (key),
1274 target);
1275 if (0 == off)
1276 {
1277 GNUNET_free (rtargets);
1278 *targets = NULL;
1279 return 0;
1280 }
1281 *targets = rtargets;
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1284 GNUNET_h2s (key),
1285 off,
1286 target);
1287 return off;
1288}
1289
1290
1291/**
1292 * If we got a HELLO, consider it for our own routing table
1293 *
1294 * @param bd block data we got
1295 */
1296static void
1297hello_check (const struct GNUNET_DATACACHE_Block *bd)
1298{
1299 struct GNUNET_PeerIdentity pid;
1300 struct GNUNET_HELLO_Builder *b;
1301
1302 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO != bd->type)
1303 return;
1304
1305 b = GNUNET_HELLO_builder_from_block (bd->data,
1306 bd->data_size);
1307 if (GNUNET_YES != disable_try_connect)
1308 GNUNET_HELLO_builder_iterate (b,
1309 &pid,
1310 &GDS_try_connect,
1311 &pid);
1312 GNUNET_HELLO_builder_free (b);
1313}
1314
1315
1316enum GNUNET_GenericReturnValue
1317GDS_NEIGHBOURS_handle_put (const struct GNUNET_DATACACHE_Block *bd,
1318 uint16_t desired_replication_level,
1319 uint16_t hop_count,
1320 struct GNUNET_CONTAINER_BloomFilter *bf)
1321{
1322 unsigned int target_count;
1323 struct PeerInfo **targets;
1324 size_t msize;
1325 unsigned int skip_count;
1326 enum GNUNET_DHT_RouteOption ro = bd->ro;
1327 unsigned int put_path_length = bd->put_path_length;
1328 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1329 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1330 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1331 const struct GNUNET_PeerIdentity *trunc_peer
1332 = truncated
1333 ? &bd->trunc_peer
1334 : NULL;
1335
1336#if SANITY_CHECKS > 1
1337 unsigned int failure_offset;
1338
1339 failure_offset
1340 = GNUNET_DHT_verify_path (bd->data,
1341 bd->data_size,
1342 bd->expiration_time,
1343 trunc_peer,
1344 put_path,
1345 put_path_length,
1346 NULL, 0, /* get_path */
1347 &GDS_my_identity);
1348 if (0 != failure_offset)
1349 {
1350 GNUNET_break_op (0);
1351 truncated = true;
1352 trunc_peer = &put_path[failure_offset - 1].pred;
1353 put_path = &put_path[failure_offset];
1354 put_path_length = put_path_length - failure_offset;
1355 ro |= GNUNET_DHT_RO_TRUNCATED;
1356 }
1357#endif
1358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1360 GNUNET_i2s (&GDS_my_identity),
1361 GNUNET_h2s (&bd->key),
1362 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1363 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1364
1365 /* if we got a HELLO, consider it for our own routing table */
1366 hello_check (bd);
1367 GNUNET_assert (NULL != bf);
1368 GNUNET_CONTAINER_bloomfilter_add (bf,
1369 &GDS_my_identity_hash);
1370 GNUNET_STATISTICS_update (GDS_stats,
1371 "# PUT requests routed",
1372 1,
1373 GNUNET_NO);
1374 if (bd->data_size
1375 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
1376 - sizeof(struct PeerPutMessage))
1377 {
1378 GNUNET_break (0);
1379 return GNUNET_SYSERR;
1380 }
1381 msize = bd->data_size + sizeof(struct PeerPutMessage);
1382 if (tracking)
1383 {
1384 if (msize + sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1385 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1386 {
1387 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1388 "Discarding message that is too large due to tracking\n");
1389 return GNUNET_NO;
1390 }
1391 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1392 }
1393 else
1394 {
1395 /* If tracking is disabled, also discard any path we might have
1396 gotten from some broken peer */
1397 GNUNET_break_op (0 == put_path_length);
1398 put_path_length = 0;
1399 }
1400 if (truncated)
1401 msize += sizeof (struct GNUNET_PeerIdentity);
1402 if (msize + put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1403 > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1404 {
1405 unsigned int mlen;
1406 unsigned int ppl;
1407
1408 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1409 "Truncating path that is too large due\n");
1410 mlen = GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE - msize;
1411 if (! truncated)
1412 {
1413 /* We need extra space for the truncation, consider that,
1414 too! */
1415 truncated = true;
1416 mlen -= sizeof (struct GNUNET_PeerIdentity);
1417 msize += sizeof (struct GNUNET_PeerIdentity);
1418 }
1419 /* compute maximum length of path we can keep */
1420 ppl = mlen / sizeof (struct GNUNET_DHT_PathElement);
1421 GNUNET_assert (put_path_length - ppl > 0);
1422 trunc_peer = &put_path[put_path_length - ppl - 1].pred;
1423 put_path = &put_path[put_path_length - ppl];
1424 put_path_length = ppl;
1425 ro |= GNUNET_DHT_RO_TRUNCATED;
1426 }
1427 else
1428 {
1429 msize += bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement);
1430 }
1431 target_count
1432 = get_target_peers (&bd->key,
1433 bf,
1434 hop_count,
1435 desired_replication_level,
1436 &targets);
1437 if (0 == target_count)
1438 {
1439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1440 "Routing PUT for %s terminates after %u hops at %s\n",
1441 GNUNET_h2s (&bd->key),
1442 (unsigned int) hop_count,
1443 GNUNET_i2s (&GDS_my_identity));
1444 return GNUNET_NO;
1445 }
1446 skip_count = 0;
1447 for (unsigned int i = 0; i < target_count; i++)
1448 {
1449 struct PeerInfo *target = targets[i];
1450 struct PeerPutMessage *ppm;
1451 char buf[msize] GNUNET_ALIGN;
1452 struct GNUNET_DHT_PathElement *pp;
1453 void *data;
1454
1455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1456 "Routing PUT for %s after %u hops to %s\n",
1457 GNUNET_h2s (&bd->key),
1458 (unsigned int) hop_count,
1459 GNUNET_i2s (&target->id));
1460 ppm = (struct PeerPutMessage *) buf;
1461 ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
1462 ppm->header.size = htons (sizeof (buf));
1463 ppm->type = htonl (bd->type);
1464 ppm->options = htons (ro);
1465 ppm->hop_count = htons (hop_count + 1);
1466 ppm->desired_replication_level = htons (desired_replication_level);
1467 ppm->put_path_length = htons (put_path_length);
1468 ppm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1469 GNUNET_break (GNUNET_YES ==
1470 GNUNET_CONTAINER_bloomfilter_test (bf,
1471 &target->phash));
1472 GNUNET_assert (GNUNET_OK ==
1473 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
1474 ppm->bloomfilter,
1475 DHT_BLOOM_SIZE));
1476 ppm->key = bd->key;
1477 if (truncated)
1478 {
1479 void *tgt = &ppm[1];
1480
1481 GNUNET_memcpy (tgt,
1482 trunc_peer,
1483 sizeof (struct GNUNET_PeerIdentity));
1484 pp = (struct GNUNET_DHT_PathElement *)
1485 (tgt + sizeof (struct GNUNET_PeerIdentity));
1486 }
1487 else
1488 {
1489 pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1490 }
1491 GNUNET_memcpy (pp,
1492 put_path,
1493 sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1494 if (tracking)
1495 {
1496 void *tgt = &pp[put_path_length];
1497 struct GNUNET_CRYPTO_EddsaSignature last_sig;
1498
1499 if (0 == put_path_length)
1500 {
1501 /* Note that the signature in 'put_path' was not initialized before,
1502 so this is crucial to avoid sending garbage. */
1503 sign_path (bd->data,
1504 bd->data_size,
1505 bd->expiration_time,
1506 trunc_peer,
1507 &target->id,
1508 &last_sig);
1509 }
1510 else
1511 {
1512 sign_path (bd->data,
1513 bd->data_size,
1514 bd->expiration_time,
1515 &pp[put_path_length - 1].pred,
1516 &target->id,
1517 &last_sig);
1518 }
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "Signing PUT PATH %u => %s\n",
1521 put_path_length,
1522 GNUNET_B2S (&last_sig));
1523 memcpy (tgt,
1524 &last_sig,
1525 sizeof (last_sig));
1526 data = tgt + sizeof (last_sig);
1527 }
1528 else /* ! tracking */
1529 {
1530 data = &ppm[1];
1531 }
1532 GNUNET_memcpy (data,
1533 bd->data,
1534 bd->data_size);
1535 do_send (target,
1536 &ppm->header);
1537 }
1538 GNUNET_free (targets);
1539 GNUNET_STATISTICS_update (GDS_stats,
1540 "# PUT messages queued for transmission",
1541 target_count - skip_count,
1542 GNUNET_NO);
1543 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1544}
1545
1546
1547enum GNUNET_GenericReturnValue
1548GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1549 enum GNUNET_DHT_RouteOption options,
1550 uint16_t desired_replication_level,
1551 uint16_t hop_count,
1552 const struct GNUNET_HashCode *key,
1553 const void *xquery,
1554 size_t xquery_size,
1555 struct GNUNET_BLOCK_Group *bg,
1556 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1557{
1558 unsigned int target_count;
1559 struct PeerInfo **targets;
1560 size_t msize;
1561 size_t result_filter_size;
1562 void *result_filter;
1563 unsigned int skip_count;
1564
1565 GNUNET_assert (NULL != peer_bf);
1566 GNUNET_STATISTICS_update (GDS_stats,
1567 "# GET requests routed",
1568 1,
1569 GNUNET_NO);
1570 target_count = get_target_peers (key,
1571 peer_bf,
1572 hop_count,
1573 desired_replication_level,
1574 &targets);
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1576 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1577 GNUNET_i2s (&GDS_my_identity),
1578 GNUNET_h2s (key),
1579 (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1580 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1581
1582 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1583 &GDS_my_identity_hash);
1584 if (0 == target_count)
1585 {
1586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1587 "Routing GET for %s terminates after %u hops at %s\n",
1588 GNUNET_h2s (key),
1589 (unsigned int) hop_count,
1590 GNUNET_i2s (&GDS_my_identity));
1591 return GNUNET_NO;
1592 }
1593 if (GNUNET_OK !=
1594 GNUNET_BLOCK_group_serialize (bg,
1595 &result_filter,
1596 &result_filter_size))
1597 {
1598 result_filter = NULL;
1599 result_filter_size = 0;
1600 }
1601 msize = xquery_size + result_filter_size;
1602 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1603 {
1604 GNUNET_break (0);
1605 GNUNET_free (result_filter);
1606 GNUNET_free (targets);
1607 return GNUNET_NO;
1608 }
1609 /* forward request */
1610 skip_count = 0;
1611 for (unsigned int i = 0; i < target_count; i++)
1612 {
1613 struct PeerInfo *target = targets[i];
1614 struct PeerGetMessage *pgm;
1615 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1616 char *rf;
1617
1618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1619 "Routing GET for %s after %u hops to %s\n",
1620 GNUNET_h2s (key),
1621 (unsigned int) hop_count,
1622 GNUNET_i2s (&target->id));
1623 pgm = (struct PeerGetMessage *) buf;
1624 pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
1625 pgm->header.size = htons (sizeof (buf));
1626 pgm->type = htonl (type);
1627 pgm->options = htons (options);
1628 pgm->hop_count = htons (hop_count + 1);
1629 pgm->desired_replication_level = htons (desired_replication_level);
1630 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1631 GNUNET_break (GNUNET_YES ==
1632 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1633 &target->phash));
1634 GNUNET_assert (GNUNET_OK ==
1635 GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf,
1636 pgm->bloomfilter,
1637 DHT_BLOOM_SIZE));
1638 pgm->key = *key;
1639 rf = (char *) &pgm[1];
1640 GNUNET_memcpy (rf,
1641 result_filter,
1642 result_filter_size);
1643 GNUNET_memcpy (&rf[result_filter_size],
1644 xquery,
1645 xquery_size);
1646 do_send (target,
1647 &pgm->header);
1648 }
1649 GNUNET_STATISTICS_update (GDS_stats,
1650 "# GET messages queued for transmission",
1651 target_count - skip_count,
1652 GNUNET_NO);
1653 GNUNET_free (targets);
1654 GNUNET_free (result_filter);
1655 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1656}
1657
1658
1659struct PeerInfo *
1660GDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
1661{
1662 return GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
1663 target);
1664}
1665
1666
1667bool
1668GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1669 const struct GNUNET_DATACACHE_Block *bd,
1670 const struct GNUNET_HashCode *query_hash,
1671 unsigned int get_path_length,
1672 const struct GNUNET_DHT_PathElement *get_path)
1673{
1674 struct GNUNET_DHT_PathElement *paths;
1675 size_t msize;
1676 unsigned int ppl = bd->put_path_length;
1677 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1678 enum GNUNET_DHT_RouteOption ro = bd->ro;
1679 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1680 const struct GNUNET_PeerIdentity *trunc_peer
1681 = truncated
1682 ? &bd->trunc_peer
1683 : NULL;
1684 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1685#if SANITY_CHECKS > 1
1686 unsigned int failure_offset;
1687
1688 failure_offset
1689 = GNUNET_DHT_verify_path (bd->data,
1690 bd->data_size,
1691 bd->expiration_time,
1692 trunc_peer,
1693 put_path,
1694 ppl,
1695 get_path,
1696 get_path_length,
1697 &GDS_my_identity);
1698 if (0 != failure_offset)
1699 {
1700 GNUNET_assert (failure_offset <= ppl + get_path_length);
1701 GNUNET_break_op (0);
1702 if (failure_offset < ppl)
1703 {
1704 trunc_peer = &put_path[failure_offset - 1].pred;
1705 put_path += failure_offset;
1706 ppl -= failure_offset;
1707 truncated = true;
1708 ro |= GNUNET_DHT_RO_TRUNCATED;
1709 }
1710 else
1711 {
1712 failure_offset -= ppl;
1713 if (0 == failure_offset)
1714 trunc_peer = &put_path[ppl - 1].pred;
1715 else
1716 trunc_peer = &get_path[failure_offset - 1].pred;
1717 ppl = 0;
1718 put_path = NULL;
1719 truncated = true;
1720 ro |= GNUNET_DHT_RO_TRUNCATED;
1721 get_path += failure_offset;
1722 get_path_length -= failure_offset;
1723 }
1724 }
1725#endif
1726 msize = bd->data_size + sizeof (struct PeerResultMessage);
1727 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1728 {
1729 GNUNET_break_op (0);
1730 return false;
1731 }
1732 if (truncated)
1733 msize += sizeof (struct GNUNET_PeerIdentity);
1734 if (tracking)
1735 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1736 if (msize < bd->data_size)
1737 {
1738 GNUNET_break_op (0);
1739 return false;
1740 }
1741 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1742 / sizeof(struct GNUNET_DHT_PathElement)
1743 < (get_path_length + ppl) )
1744 {
1745 get_path_length = 0;
1746 ppl = 0;
1747 }
1748 if ( (get_path_length > UINT16_MAX) ||
1749 (ppl > UINT16_MAX) )
1750 {
1751 GNUNET_break (0);
1752 get_path_length = 0;
1753 ppl = 0;
1754 }
1755 msize += (get_path_length + ppl)
1756 * sizeof(struct GNUNET_DHT_PathElement);
1757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1758 "Forwarding reply for key %s to peer %s\n",
1759 GNUNET_h2s (query_hash),
1760 GNUNET_i2s (&pi->id));
1761 GNUNET_STATISTICS_update (GDS_stats,
1762 "# RESULT messages queued for transmission",
1763 1,
1764 GNUNET_NO);
1765 {
1766 struct PeerResultMessage *prm;
1767 char buf[msize] GNUNET_ALIGN;
1768 void *data;
1769
1770 prm = (struct PeerResultMessage *) buf;
1771 prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1772 prm->header.size = htons (sizeof (buf));
1773 prm->type = htonl ((uint32_t) bd->type);
1774 prm->options = htonl ((uint32_t) ro);
1775 prm->put_path_length = htons ((uint16_t) ppl);
1776 prm->get_path_length = htons ((uint16_t) get_path_length);
1777 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1778 prm->key = *query_hash;
1779 if (truncated)
1780 {
1781 void *tgt = &prm[1];
1782
1783 GNUNET_memcpy (tgt,
1784 trunc_peer,
1785 sizeof (struct GNUNET_PeerIdentity));
1786 paths = (struct GNUNET_DHT_PathElement *)
1787 (tgt + sizeof (struct GNUNET_PeerIdentity));
1788 }
1789 else
1790 {
1791 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1792 }
1793 if (NULL != put_path)
1794 {
1795 GNUNET_memcpy (paths,
1796 put_path,
1797 ppl * sizeof(struct GNUNET_DHT_PathElement));
1798 }
1799 else
1800 {
1801 GNUNET_assert (0 == ppl);
1802 }
1803 if (NULL != get_path)
1804 {
1805 GNUNET_memcpy (&paths[ppl],
1806 get_path,
1807 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1808 }
1809 else
1810 {
1811 GNUNET_assert (0 == get_path_length);
1812 }
1813 if (tracking)
1814 {
1815 struct GNUNET_CRYPTO_EddsaSignature sig;
1816 void *tgt = &paths[get_path_length + ppl];
1817 const struct GNUNET_PeerIdentity *pred;
1818
1819 if (ppl + get_path_length > 0)
1820 pred = &paths[ppl + get_path_length - 1].pred;
1821 else if (truncated)
1822 pred = trunc_peer;
1823 else
1824 pred = NULL; /* we are first! */
1825 /* Note that the last signature in 'paths' was not initialized before,
1826 so this is crucial to avoid sending garbage. */
1827 sign_path (bd->data,
1828 bd->data_size,
1829 bd->expiration_time,
1830 pred,
1831 &pi->id,
1832 &sig);
1833 memcpy (tgt,
1834 &sig,
1835 sizeof (sig));
1836 data = tgt + sizeof (sig);
1837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838 "Signing GET PATH %u/%u of %s => %s\n",
1839 ppl,
1840 get_path_length,
1841 GNUNET_h2s (query_hash),
1842 GNUNET_B2S (&sig));
1843#if SANITY_CHECKS > 1
1844 {
1845 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1846
1847 memcpy (xpaths,
1848 &paths[ppl],
1849 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1850 xpaths[get_path_length].sig = sig;
1851 xpaths[get_path_length].pred = GDS_my_identity;
1852 if (0 !=
1853 GNUNET_DHT_verify_path (bd->data,
1854 bd->data_size,
1855 bd->expiration_time,
1856 trunc_peer,
1857 paths,
1858 ppl,
1859 xpaths,
1860 get_path_length + 1,
1861 &pi->id))
1862 {
1863 GNUNET_break (0);
1864 return false;
1865 }
1866 }
1867#endif
1868 }
1869 else
1870 {
1871 data = &prm[1];
1872 }
1873 GNUNET_memcpy (data,
1874 bd->data,
1875 bd->data_size);
1876 do_send (pi,
1877 &prm->header);
1878 }
1879 return true;
1880}
1881
1882
1883/**
1884 * Check validity of a p2p put request.
1885 *
1886 * @param cls closure with the `struct PeerInfo` of the sender
1887 * @param message message
1888 * @return #GNUNET_OK if the message is valid
1889 */
1890static enum GNUNET_GenericReturnValue
1891check_dht_p2p_put (void *cls,
1892 const struct PeerPutMessage *put)
1893{
1894 enum GNUNET_DHT_RouteOption ro
1895 = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1896 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1897 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1898 uint16_t msize = ntohs (put->header.size);
1899 uint16_t putlen = ntohs (put->put_path_length);
1900 size_t xsize = (has_path
1901 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1902 : 0)
1903 + (truncated
1904 ? sizeof (struct GNUNET_PeerIdentity)
1905 : 0);
1906 size_t var_meta_size
1907 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1908 + xsize;
1909
1910 (void) cls;
1911 if ( (msize <
1912 sizeof (struct PeerPutMessage) + var_meta_size) ||
1913 (putlen >
1914 (GNUNET_MAX_MESSAGE_SIZE
1915 - sizeof (struct PeerPutMessage)
1916 - xsize)
1917 / sizeof(struct GNUNET_DHT_PathElement)) )
1918 {
1919 GNUNET_break_op (0);
1920 return GNUNET_SYSERR;
1921 }
1922 return GNUNET_OK;
1923}
1924
1925
1926/**
1927 * Core handler for p2p put requests.
1928 *
1929 * @param cls closure with the `struct Target` of the sender
1930 * @param message message
1931 */
1932static void
1933handle_dht_p2p_put (void *cls,
1934 const struct PeerPutMessage *put)
1935{
1936 struct Target *t = cls;
1937 struct PeerInfo *peer = t->pi;
1938 enum GNUNET_DHT_RouteOption ro
1939 = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1940 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1941 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1942 uint16_t msize = ntohs (put->header.size);
1943 uint16_t putlen = ntohs (put->put_path_length);
1944 const struct GNUNET_PeerIdentity *trunc_peer
1945 = truncated
1946 ? (const struct GNUNET_PeerIdentity *) &put[1]
1947 : NULL;
1948 const struct GNUNET_DHT_PathElement *put_path
1949 = truncated
1950 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1951 : (const struct GNUNET_DHT_PathElement *) &put[1];
1952 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1953 = has_path
1954 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1955 : NULL;
1956 const char *data
1957 = has_path
1958 ? (const char *) &last_sig[1]
1959 : (const char *) &put_path[putlen];
1960 size_t var_meta_size
1961 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1962 + has_path ? sizeof (*last_sig) : 0
1963 + truncated ? sizeof (*trunc_peer) : 0;
1964 struct GNUNET_DATACACHE_Block bd = {
1965 .key = put->key,
1966 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1967 .type = ntohl (put->type),
1968 .ro = ro,
1969 .data_size = msize - sizeof(*put) - var_meta_size,
1970 .data = data
1971 };
1972
1973 if (NULL != trunc_peer)
1974 bd.trunc_peer = *trunc_peer;
1975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1976 "PUT for `%s' from %s with RO (%s/%s)\n",
1977 GNUNET_h2s (&put->key),
1978 GNUNET_i2s (&peer->id),
1979 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1980 has_path ? "R" : "-");
1981 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
1982 {
1983 GNUNET_STATISTICS_update (GDS_stats,
1984 "# Expired PUTs discarded",
1985 1,
1986 GNUNET_NO);
1987 return;
1988 }
1989 if (GNUNET_NO ==
1990 GNUNET_BLOCK_check_block (GDS_block_context,
1991 bd.type,
1992 bd.data,
1993 bd.data_size))
1994 {
1995 GNUNET_break_op (0);
1996 return;
1997 }
1998 if (! has_path)
1999 putlen = 0;
2000 GNUNET_STATISTICS_update (GDS_stats,
2001 "# P2P PUT requests received",
2002 1,
2003 GNUNET_NO);
2004 GNUNET_STATISTICS_update (GDS_stats,
2005 "# P2P PUT bytes received",
2006 msize,
2007 GNUNET_NO);
2008 {
2009 struct GNUNET_HashCode test_key;
2010 enum GNUNET_GenericReturnValue ret;
2011
2012 ret = GNUNET_BLOCK_get_key (GDS_block_context,
2013 bd.type,
2014 bd.data,
2015 bd.data_size,
2016 &test_key);
2017 switch (ret)
2018 {
2019 case GNUNET_YES:
2020 if (0 != GNUNET_memcmp (&test_key,
2021 &bd.key))
2022 {
2023 GNUNET_break_op (0);
2024 return;
2025 }
2026 break;
2027 case GNUNET_NO:
2028 /* cannot verify, good luck */
2029 break;
2030 case GNUNET_SYSERR:
2031 /* block type not supported, good luck */
2032 break;
2033 }
2034 }
2035
2036 {
2037 struct GNUNET_CONTAINER_BloomFilter *bf;
2038 struct GNUNET_DHT_PathElement pp[putlen + 1];
2039
2040 bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter,
2041 DHT_BLOOM_SIZE,
2042 GNUNET_CONSTANTS_BLOOMFILTER_K);
2043 GNUNET_break_op (GNUNET_YES ==
2044 GNUNET_CONTAINER_bloomfilter_test (bf,
2045 &peer->phash));
2046 /* extend 'put path' by sender */
2047 bd.put_path = (const struct GNUNET_DHT_PathElement *) pp;
2048 bd.put_path_length = putlen + 1;
2049 if (has_path)
2050 {
2051 unsigned int failure_offset;
2052
2053 GNUNET_memcpy (pp,
2054 put_path,
2055 putlen * sizeof(struct GNUNET_DHT_PathElement));
2056 pp[putlen].pred = peer->id;
2057 pp[putlen].sig = *last_sig;
2058#if SANITY_CHECKS
2059 /* TODO: might want to eventually implement probabilistic
2060 load-based path verification, but for now it is all or nothing */
2061 failure_offset
2062 = GNUNET_DHT_verify_path (bd.data,
2063 bd.data_size,
2064 bd.expiration_time,
2065 trunc_peer,
2066 pp,
2067 putlen + 1,
2068 NULL, 0, /* get_path */
2069 &GDS_my_identity);
2070#else
2071 failure_offset = 0;
2072#endif
2073 if (0 != failure_offset)
2074 {
2075 GNUNET_break_op (0);
2076 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2077 "Recorded put path invalid at offset %u, truncating\n",
2078 failure_offset);
2079 GNUNET_assert (failure_offset <= putlen + 1);
2080 bd.put_path = &pp[failure_offset];
2081 bd.put_path_length = putlen - failure_offset;
2082 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2083 bd.trunc_peer = pp[failure_offset - 1].pred;
2084 }
2085 }
2086 else
2087 {
2088 bd.put_path_length = 0;
2089 }
2090
2091 /* give to local clients */
2092 GNUNET_break (GDS_CLIENTS_handle_reply (&bd,
2093 &bd.key,
2094 0, NULL /* get path */));
2095
2096 /* store locally */
2097 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2098 (GDS_am_closest_peer (&put->key,
2099 bf)) )
2100 GDS_DATACACHE_handle_put (&bd);
2101 {
2102 enum GNUNET_GenericReturnValue forwarded;
2103
2104 /* route to other peers */
2105 forwarded
2106 = GDS_NEIGHBOURS_handle_put (&bd,
2107 ntohs (put->desired_replication_level),
2108 ntohs (put->hop_count),
2109 bf);
2110 /* notify monitoring clients */
2111 bd.ro |= ((GNUNET_OK == forwarded)
2112 ? GNUNET_DHT_RO_LAST_HOP
2113 : 0);
2114 GDS_CLIENTS_process_put (&bd,
2115 ntohs (put->hop_count),
2116 ntohs (put->desired_replication_level));
2117 }
2118 GNUNET_CONTAINER_bloomfilter_free (bf);
2119 }
2120}
2121
2122
2123/**
2124 * We have received a request for a HELLO. Sends our
2125 * HELLO back.
2126 *
2127 * @param pi sender of the request
2128 * @param key peers close to this key are desired
2129 * @param bg group for filtering peers
2130 */
2131static void
2132handle_find_my_hello (struct PeerInfo *pi,
2133 const struct GNUNET_HashCode *query_hash,
2134 struct GNUNET_BLOCK_Group *bg)
2135{
2136 size_t block_size = 0;
2137
2138 /* TODO: consider caching our HELLO block for a bit, to
2139 avoid signing too often here... */
2140 GNUNET_break (GNUNET_NO ==
2141 GNUNET_HELLO_builder_to_block (GDS_my_hello,
2142 &GDS_my_private_key,
2143 NULL,
2144 &block_size));
2145 {
2146 char block[block_size];
2147
2148 if (GNUNET_OK !=
2149 GNUNET_HELLO_builder_to_block (GDS_my_hello,
2150 &GDS_my_private_key,
2151 block,
2152 &block_size))
2153 {
2154 GNUNET_STATISTICS_update (GDS_stats,
2155 "# FIND PEER requests ignored due to lack of HELLO",
2156 1,
2157 GNUNET_NO);
2158 }
2159 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
2160 GNUNET_BLOCK_check_reply (GDS_block_context,
2161 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2162 bg,
2163 &GDS_my_identity_hash,
2164 NULL, 0,
2165 block,
2166 block_size))
2167 {
2168 struct GNUNET_DATACACHE_Block bd = {
2169 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2170 .expiration_time
2171 = GNUNET_TIME_relative_to_absolute (
2172 GNUNET_HELLO_ADDRESS_EXPIRATION),
2173 .key = GDS_my_identity_hash,
2174 .data = block,
2175 .data_size = block_size
2176 };
2177
2178 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
2179 &bd,
2180 query_hash,
2181 0, NULL /* get path */));
2182 }
2183 else
2184 {
2185 GNUNET_STATISTICS_update (GDS_stats,
2186 "# FIND PEER requests ignored due to Bloomfilter",
2187 1,
2188 GNUNET_NO);
2189 }
2190 }
2191}
2192
2193
2194/**
2195 * We have received a request for nearby HELLOs. Sends matching
2196 * HELLOs back.
2197 *
2198 * @param pi sender of the request
2199 * @param key peers close to this key are desired
2200 * @param bg group for filtering peers
2201 */
2202static void
2203handle_find_local_hello (struct PeerInfo *pi,
2204 const struct GNUNET_HashCode *query_hash,
2205 struct GNUNET_BLOCK_Group *bg)
2206{
2207 /* Force non-random selection by hop count */
2208 struct PeerInfo *peer;
2209
2210 peer = select_peer (query_hash,
2211 NULL,
2212 GDS_NSE_get () + 1);
2213 if ( (NULL != peer->hello) &&
2214 (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
2215 (GNUNET_BLOCK_REPLY_OK_MORE ==
2216 GNUNET_BLOCK_check_reply (
2217 GDS_block_context,
2218 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2219 bg,
2220 &peer->phash,
2221 NULL, 0, /* xquery */
2222 peer->hello,
2223 peer->hello_size)) )
2224 {
2225 struct GNUNET_DATACACHE_Block bd = {
2226 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
2227 .expiration_time = peer->hello_expiration,
2228 .key = peer->phash,
2229 .data = peer->hello,
2230 .data_size = peer->hello_size
2231 };
2232
2233 GNUNET_break (GDS_NEIGHBOURS_handle_reply (pi,
2234 &bd,
2235 query_hash,
2236 0, NULL /* get path */));
2237 }
2238}
2239
2240
2241/**
2242 * Handle an exact result from local datacache for a GET operation.
2243 *
2244 * @param cls the `struct PeerInfo` for which this is a reply
2245 * @param bd details about the block we found locally
2246 */
2247static void
2248handle_local_result (void *cls,
2249 const struct GNUNET_DATACACHE_Block *bd)
2250{
2251 struct PeerInfo *peer = cls;
2252
2253 GNUNET_break (GDS_NEIGHBOURS_handle_reply (peer,
2254 bd,
2255 &bd->key,
2256 0, NULL /* get path */));
2257}
2258
2259
2260/**
2261 * Check validity of p2p get request.
2262 *
2263 * @param cls closure with the `struct Target` of the sender
2264 * @param get the message
2265 * @return #GNUNET_OK if the message is well-formed
2266 */
2267static enum GNUNET_GenericReturnValue
2268check_dht_p2p_get (void *cls,
2269 const struct PeerGetMessage *get)
2270{
2271 uint16_t msize = ntohs (get->header.size);
2272 uint16_t result_filter_size = ntohs (get->result_filter_size);
2273
2274 (void) cls;
2275 if (msize < sizeof(*get) + result_filter_size)
2276 {
2277 GNUNET_break_op (0);
2278 return GNUNET_SYSERR;
2279 }
2280 return GNUNET_OK;
2281}
2282
2283
2284/**
2285 * Core handler for p2p get requests.
2286 *
2287 * @param cls closure with the `struct Target` of the sender
2288 * @param get the message
2289 */
2290static void
2291handle_dht_p2p_get (void *cls,
2292 const struct PeerGetMessage *get)
2293{
2294 struct Target *t = cls;
2295 struct PeerInfo *peer = t->pi;
2296 uint16_t msize = ntohs (get->header.size);
2297 uint16_t result_filter_size = ntohs (get->result_filter_size);
2298 uint16_t hop_count = ntohs (get->hop_count);
2299 enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2300 enum GNUNET_DHT_RouteOption options = (enum GNUNET_DHT_RouteOption) ntohs (
2301 get->options);
2302 enum GNUNET_BLOCK_ReplyEvaluationResult eval = GNUNET_BLOCK_REPLY_OK_MORE;
2303 const void *result_filter = (const void *) &get[1];
2304 const void *xquery = result_filter + result_filter_size;
2305 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2306
2307 /* parse and validate message */
2308 GNUNET_STATISTICS_update (GDS_stats,
2309 "# P2P GET requests received",
2310 1,
2311 GNUNET_NO);
2312 GNUNET_STATISTICS_update (GDS_stats,
2313 "# P2P GET bytes received",
2314 msize,
2315 GNUNET_NO);
2316 if (GNUNET_NO ==
2317 GNUNET_BLOCK_check_query (GDS_block_context,
2318 type,
2319 &get->key,
2320 xquery,
2321 xquery_size))
2322 {
2323 /* request invalid */
2324 GNUNET_break_op (0);
2325 return;
2326 }
2327
2328 {
2329 struct GNUNET_BLOCK_Group *bg;
2330 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2331
2332 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2333 DHT_BLOOM_SIZE,
2334 GNUNET_CONSTANTS_BLOOMFILTER_K);
2335 GNUNET_break_op (GNUNET_YES ==
2336 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2337 &peer->phash));
2338 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2339 type,
2340 result_filter,
2341 result_filter_size,
2342 "filter-size",
2343 result_filter_size,
2344 NULL);
2345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2346 "GET for %s at %s after %u hops\n",
2347 GNUNET_h2s (&get->key),
2348 GNUNET_i2s (&GDS_my_identity),
2349 (unsigned int) hop_count);
2350 /* local lookup (this may update the bg) */
2351 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2352 (GDS_am_closest_peer (&get->key,
2353 peer_bf)) )
2354 {
2355 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == type)
2356 {
2357 GNUNET_STATISTICS_update (GDS_stats,
2358 "# P2P HELLO lookup requests processed",
2359 1,
2360 GNUNET_NO);
2361 handle_find_my_hello (peer,
2362 &get->key,
2363 bg);
2364 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2365 handle_find_local_hello (peer,
2366 &get->key,
2367 bg);
2368 }
2369 else
2370 {
2371 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2372 eval = GDS_DATACACHE_get_closest (&get->key,
2373 type,
2374 xquery,
2375 xquery_size,
2376 bg,
2377 &handle_local_result,
2378 peer);
2379 else
2380 eval = GDS_DATACACHE_handle_get (&get->key,
2381 type,
2382 xquery,
2383 xquery_size,
2384 bg,
2385 &handle_local_result,
2386 peer);
2387 }
2388 }
2389 else
2390 {
2391 GNUNET_STATISTICS_update (GDS_stats,
2392 "# P2P GET requests ONLY routed",
2393 1,
2394 GNUNET_NO);
2395 }
2396
2397 /* remember request for routing replies
2398 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2399 */
2400 GDS_ROUTING_add (&peer->id,
2401 type,
2402 bg, /* bg now owned by routing, but valid at least until end of this function! */
2403 options,
2404 &get->key,
2405 xquery,
2406 xquery_size);
2407
2408 /* P2P forwarding */
2409 {
2410 bool forwarded = false;
2411 uint16_t desired_replication_level = ntohs (
2412 get->desired_replication_level);
2413
2414 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2415 forwarded = (GNUNET_OK ==
2416 GDS_NEIGHBOURS_handle_get (type,
2417 options,
2418 desired_replication_level,
2419 hop_count,
2420 &get->key,
2421 xquery,
2422 xquery_size,
2423 bg,
2424 peer_bf));
2425 GDS_CLIENTS_process_get (
2426 options
2427 | (forwarded
2428 ? 0
2429 : GNUNET_DHT_RO_LAST_HOP),
2430 type,
2431 hop_count,
2432 desired_replication_level,
2433 &get->key);
2434 }
2435 /* clean up; note that 'bg' is owned by routing now! */
2436 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2437 }
2438}
2439
2440
2441/**
2442 * Process a reply, after the @a get_path has been updated.
2443 *
2444 * @param bd block details
2445 * @param query_hash hash of the original query, might not match key in @a bd
2446 * @param get_path_length number of entries in @a get_path
2447 * @param get_path path the reply has taken
2448 * @return true on success
2449 */
2450static bool
2451process_reply_with_path (const struct GNUNET_DATACACHE_Block *bd,
2452 const struct GNUNET_HashCode *query_hash,
2453 unsigned int get_path_length,
2454 const struct GNUNET_DHT_PathElement *get_path)
2455{
2456 /* forward to local clients */
2457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2458 "Forwarding reply to local clients\n");
2459 if (! GDS_CLIENTS_handle_reply (bd,
2460 query_hash,
2461 get_path_length,
2462 get_path))
2463 {
2464 GNUNET_break (0);
2465 return false;
2466 }
2467 GDS_CLIENTS_process_get_resp (bd,
2468 get_path,
2469 get_path_length);
2470 if (GNUNET_YES == cache_results)
2471 {
2472 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2473 + bd->put_path_length)];
2474 struct GNUNET_DATACACHE_Block bdx = *bd;
2475
2476 GNUNET_memcpy (xput_path,
2477 bd->put_path,
2478 bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement));
2479 GNUNET_memcpy (&xput_path[bd->put_path_length],
2480 get_path,
2481 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2482 bdx.put_path = xput_path;
2483 bdx.put_path_length += get_path_length;
2484 GDS_DATACACHE_handle_put (&bdx);
2485 }
2486 /* forward to other peers */
2487 GDS_ROUTING_process (bd,
2488 query_hash,
2489 get_path_length,
2490 get_path);
2491 return true;
2492}
2493
2494
2495/**
2496 * Check validity of p2p result message.
2497 *
2498 * @param cls closure
2499 * @param message message
2500 * @return #GNUNET_YES if the message is well-formed
2501 */
2502static enum GNUNET_GenericReturnValue
2503check_dht_p2p_result (void *cls,
2504 const struct PeerResultMessage *prm)
2505{
2506 uint16_t get_path_length = ntohs (prm->get_path_length);
2507 uint16_t put_path_length = ntohs (prm->put_path_length);
2508 uint16_t msize = ntohs (prm->header.size);
2509
2510 (void) cls;
2511 if ( (msize <
2512 sizeof(struct PeerResultMessage)
2513 + (get_path_length + put_path_length)
2514 * sizeof(struct GNUNET_DHT_PathElement)) ||
2515 (get_path_length >
2516 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2517 (put_path_length >
2518 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2519 {
2520 GNUNET_break_op (0);
2521 return GNUNET_SYSERR;
2522 }
2523 return GNUNET_OK;
2524}
2525
2526
2527/**
2528 * Core handler for p2p result messages.
2529 *
2530 * @param cls closure
2531 * @param message message
2532 */
2533static void
2534handle_dht_p2p_result (void *cls,
2535 const struct PeerResultMessage *prm)
2536{
2537 struct Target *t = cls;
2538 struct PeerInfo *peer = t->pi;
2539 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2540 enum GNUNET_DHT_RouteOption ro
2541 = (enum GNUNET_DHT_RouteOption) ntohl (prm->options);
2542 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2543 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2544 uint16_t get_path_length = ntohs (prm->get_path_length);
2545 uint16_t put_path_length = ntohs (prm->put_path_length);
2546 const struct GNUNET_PeerIdentity *trunc_peer
2547 = truncated
2548 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2549 : NULL;
2550 const struct GNUNET_DHT_PathElement *put_path
2551 = truncated
2552 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2553 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2554 const struct GNUNET_DHT_PathElement *get_path
2555 = &put_path[put_path_length];
2556 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2557 = tracked
2558 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2559 : NULL;
2560 const void *data
2561 = tracked
2562 ? (const void *) &last_sig[1]
2563 : (const void *) &get_path[get_path_length];
2564 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2565 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2566 struct GNUNET_DATACACHE_Block bd = {
2567 .expiration_time = GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2568 .put_path = put_path,
2569 .put_path_length = put_path_length,
2570 .key = prm->key,
2571 .type = ntohl (prm->type),
2572 .ro = ro,
2573 .data = data,
2574 .data_size = msize - vsize - (get_path_length + put_path_length)
2575 * sizeof(struct GNUNET_DHT_PathElement)
2576 };
2577
2578 /* parse and validate message */
2579 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2580 {
2581 GNUNET_STATISTICS_update (GDS_stats,
2582 "# Expired results discarded",
2583 1,
2584 GNUNET_NO);
2585 return;
2586 }
2587 if (GNUNET_OK !=
2588 GNUNET_BLOCK_check_block (GDS_block_context,
2589 bd.type,
2590 bd.data,
2591 bd.data_size))
2592 {
2593 GNUNET_break_op (0);
2594 return;
2595 }
2596 GNUNET_STATISTICS_update (GDS_stats,
2597 "# P2P RESULTS received",
2598 1,
2599 GNUNET_NO);
2600 GNUNET_STATISTICS_update (GDS_stats,
2601 "# P2P RESULT bytes received",
2602 msize,
2603 GNUNET_NO);
2604 {
2605 enum GNUNET_GenericReturnValue ret;
2606
2607 ret = GNUNET_BLOCK_get_key (GDS_block_context,
2608 bd.type,
2609 bd.data,
2610 bd.data_size,
2611 &bd.key);
2612 if (GNUNET_NO == ret)
2613 bd.key = prm->key;
2614 }
2615
2616 /* if we got a HELLO, consider it for our own routing table */
2617 hello_check (&bd);
2618
2619 /* Need to append 'peer' to 'get_path' */
2620 if (tracked)
2621 {
2622 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2623 struct GNUNET_DHT_PathElement *gp = xget_path;
2624 unsigned int failure_offset;
2625
2626 GNUNET_memcpy (xget_path,
2627 get_path,
2628 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2629 xget_path[get_path_length].pred = peer->id;
2630 /* use memcpy(), as last_sig may not be aligned */
2631 memcpy (&xget_path[get_path_length].sig,
2632 last_sig,
2633 sizeof (*last_sig));
2634#if SANITY_CHECKS
2635 /* TODO: might want to eventually implement probabilistic
2636 load-based path verification, but for now it is all or nothing */
2637 failure_offset
2638 = GNUNET_DHT_verify_path (bd.data,
2639 bd.data_size,
2640 bd.expiration_time,
2641 trunc_peer,
2642 put_path,
2643 put_path_length,
2644 gp,
2645 get_path_length + 1,
2646 &GDS_my_identity);
2647#else
2648 failure_offset = 0;
2649#endif
2650 if (0 != failure_offset)
2651 {
2652 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2653 "Recorded path invalid at offset %u, truncating\n",
2654 failure_offset);
2655 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2656 + 1);
2657 if (failure_offset < bd.put_path_length)
2658 {
2659 /* failure on put path */
2660 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2661 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2662 bd.put_path = &bd.put_path[failure_offset];
2663 bd.put_path_length -= failure_offset;
2664 truncated = true;
2665 }
2666 else
2667 {
2668 /* failure on get path */
2669 failure_offset -= bd.put_path_length;
2670 if (0 == failure_offset)
2671 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2672 else
2673 trunc_peer = &gp[failure_offset - 1].pred;
2674 get_path_length -= failure_offset;
2675 gp = &gp[failure_offset];
2676 bd.put_path_length = 0;
2677 bd.put_path = NULL;
2678 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2679 truncated = true;
2680 }
2681 }
2682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2683 "Extending GET path of length %u with %s\n",
2684 get_path_length,
2685 GNUNET_i2s (&peer->id));
2686 if (truncated)
2687 {
2688 GNUNET_assert (NULL != trunc_peer);
2689 bd.trunc_peer = *trunc_peer;
2690 }
2691 GNUNET_break (process_reply_with_path (&bd,
2692 &prm->key,
2693 get_path_length + 1,
2694 gp));
2695 }
2696 else
2697 {
2698 if (truncated)
2699 {
2700 GNUNET_assert (NULL != trunc_peer);
2701 bd.trunc_peer = *trunc_peer;
2702 }
2703 GNUNET_break (process_reply_with_path (&bd,
2704 &prm->key,
2705 0,
2706 NULL));
2707 }
2708}
2709
2710
2711/**
2712 * Check validity of a p2p hello message.
2713 *
2714 * @param cls closure
2715 * @param hello message
2716 * @return #GNUNET_YES if the message is well-formed
2717 */
2718static enum GNUNET_GenericReturnValue
2719check_dht_p2p_hello (void *cls,
2720 const struct GNUNET_MessageHeader *hello)
2721{
2722 struct Target *t = cls;
2723 struct PeerInfo *peer = t->pi;
2724 enum GNUNET_GenericReturnValue ret;
2725 size_t hellob_size;
2726 void *hellob;
2727 struct GNUNET_TIME_Absolute expiration;
2728
2729 ret = GNUNET_HELLO_dht_msg_to_block (hello,
2730 &peer->id,
2731 &hellob,
2732 &hellob_size,
2733 &expiration);
2734 GNUNET_free (hellob);
2735 return ret;
2736}
2737
2738
2739/**
2740 * Core handler for p2p HELLO messages.
2741 *
2742 * @param cls closure
2743 * @param message message
2744 */
2745static void
2746handle_dht_p2p_hello (void *cls,
2747 const struct GNUNET_MessageHeader *hello)
2748{
2749 struct Target *t = cls;
2750 struct PeerInfo *peer = t->pi;
2751
2752 GNUNET_free (peer->hello);
2753 peer->hello_size = 0;
2754 GNUNET_break (GNUNET_OK ==
2755 GNUNET_HELLO_dht_msg_to_block (hello,
2756 &peer->id,
2757 &peer->hello,
2758 &peer->hello_size,
2759 &peer->hello_expiration));
2760}
2761
2762
2763void
2764GDS_u_receive (void *cls,
2765 void **tctx,
2766 void **sctx,
2767 const void *message,
2768 size_t message_size)
2769{
2770 struct Target *t = *tctx;
2771 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2772 GNUNET_MQ_hd_var_size (dht_p2p_get,
2773 GNUNET_MESSAGE_TYPE_DHT_P2P_GET,
2774 struct PeerGetMessage,
2775 t),
2776 GNUNET_MQ_hd_var_size (dht_p2p_put,
2777 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT,
2778 struct PeerPutMessage,
2779 t),
2780 GNUNET_MQ_hd_var_size (dht_p2p_result,
2781 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2782 struct PeerResultMessage,
2783 t),
2784 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2785 GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO,
2786 struct GNUNET_MessageHeader,
2787 t),
2788 GNUNET_MQ_handler_end ()
2789 };
2790 const struct GNUNET_MessageHeader *mh = message;
2791
2792 (void) cls; /* the 'struct GDS_Underlay' */
2793 (void) sctx; /* our receiver address */
2794 if (NULL == t)
2795 {
2796 /* Received message claiming to originate from myself?
2797 Ignore! */
2798 GNUNET_break_op (0);
2799 return;
2800 }
2801 if (message_size < sizeof (*mh))
2802 {
2803 GNUNET_break_op (0);
2804 return;
2805 }
2806 if (message_size != ntohs (mh->size))
2807 {
2808 GNUNET_break_op (0);
2809 return;
2810 }
2811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2812 "Handling message of type %u from peer %s\n",
2813 ntohs (mh->type),
2814 GNUNET_i2s (&t->pi->id));
2815 if (GNUNET_OK !=
2816 GNUNET_MQ_handle_message (core_handlers,
2817 mh))
2818 {
2819 GNUNET_break_op (0);
2820 return;
2821 }
2822}
2823
2824
2825/**
2826 * Callback function used to extract URIs from a builder.
2827 * Called when we should consider connecting to a peer.
2828 *
2829 * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
2830 * @param uri one of the URIs
2831 */
2832void
2833GDS_try_connect (void *cls,
2834 const char *uri)
2835{
2836 const struct GNUNET_PeerIdentity *pid = cls;
2837 struct GNUNET_HashCode phash;
2838 int peer_bucket;
2839 struct PeerBucket *bucket;
2840
2841 if (0 == GNUNET_memcmp (&GDS_my_identity,
2842 pid))
2843 {
2844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2845 "Got a HELLO for my own PID, ignoring it\n");
2846 return; /* that's us! */
2847 }
2848 GNUNET_CRYPTO_hash (pid,
2849 sizeof(*pid),
2850 &phash);
2851 peer_bucket = find_bucket (&phash);
2852 GNUNET_assert ( (peer_bucket >= 0) &&
2853 ((unsigned int) peer_bucket < MAX_BUCKETS));
2854 bucket = &k_buckets[peer_bucket];
2855 if (bucket->peers_size >= bucket_size)
2856 return; /* do not care */
2857 for (struct PeerInfo *pi = bucket->head;
2858 NULL != pi;
2859 pi = pi->next)
2860 if (0 ==
2861 GNUNET_memcmp (&pi->id,
2862 pid))
2863 {
2864 /* already connected */
2865 /* TODO: maybe consider 'uri' anyway as an additional
2866 alternative address??? */
2867 return;
2868 }
2869 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2870 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2871 GNUNET_i2s (pid),
2872 uri,
2873 peer_bucket,
2874 bucket->peers_size,
2875 bucket_size);
2876 /* new peer that we like! */
2877 GDS_u_try_connect (pid,
2878 uri);
2879}
2880
2881
2882/**
2883 * Send @a msg to all peers in our buckets.
2884 *
2885 * @param msg message to broadcast
2886 */
2887void
2888GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
2889{
2890 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2891 {
2892 struct PeerBucket *bucket = &k_buckets[bc];
2893 unsigned int count = 0;
2894
2895 for (struct PeerInfo *pos = bucket->head;
2896 NULL != pos;
2897 pos = pos->next)
2898 {
2899 if (count >= bucket_size)
2900 break; /* we only consider first #bucket_size entries per bucket */
2901 count++;
2902 do_send (pos,
2903 msg);
2904 }
2905 }
2906}
2907
2908
2909enum GNUNET_GenericReturnValue
2910GDS_NEIGHBOURS_init ()
2911{
2912
2913 unsigned long long temp_config_num;
2914
2915 disable_try_connect
2916 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2917 "DHT",
2918 "DISABLE_TRY_CONNECT");
2919 if (GNUNET_OK ==
2920 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
2921 "DHT",
2922 "bucket_size",
2923 &temp_config_num))
2924 bucket_size = (unsigned int) temp_config_num;
2925 cache_results
2926 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2927 "DHT",
2928 "CACHE_RESULTS");
2929 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2930 GNUNET_YES);
2931 return GNUNET_OK;
2932}
2933
2934
2935void
2936GDS_NEIGHBOURS_done ()
2937{
2938 if (NULL == all_connected_peers)
2939 return;
2940 GNUNET_assert (0 ==
2941 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2942 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2943 all_connected_peers = NULL;
2944 GNUNET_assert (NULL == find_peer_task);
2945}
2946
2947
2948struct GNUNET_PeerIdentity *
2949GDS_NEIGHBOURS_get_id ()
2950{
2951 return &GDS_my_identity;
2952}
2953
2954
2955/* end of gnunet-service-dht_neighbours.c */