aboutsummaryrefslogtreecommitdiff
path: root/src/dht/gnunet-service-dht_neighbours.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-01-15 19:24:33 +0100
committerChristian Grothoff <christian@grothoff.org>2022-02-19 12:39:55 +0100
commitb0abdf7127f2403ff583d224e0d9d4e68c1c5bfc (patch)
tree47df762cdbcce501ec5536c8963b5c9ee55da31d /src/dht/gnunet-service-dht_neighbours.c
parent3a71153405e8fc26712807b4bdb5987fb3bf2b9e (diff)
downloadgnunet-b0abdf7127f2403ff583d224e0d9d4e68c1c5bfc.tar.gz
gnunet-b0abdf7127f2403ff583d224e0d9d4e68c1c5bfc.zip
-more work on DHTU integration
Diffstat (limited to 'src/dht/gnunet-service-dht_neighbours.c')
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c1108
1 files changed, 554 insertions, 554 deletions
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
index bc473df69..b7b5e8097 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -29,8 +29,8 @@
29#include "gnunet_protocols.h" 29#include "gnunet_protocols.h"
30#include "gnunet_signatures.h" 30#include "gnunet_signatures.h"
31#include "gnunet_hello_lib.h" 31#include "gnunet_hello_lib.h"
32#include "gnunet_hello_uri_lib.h"
32#include "gnunet-service-dht.h" 33#include "gnunet-service-dht.h"
33#include "gnunet-service-dht_hello.h"
34#include "gnunet-service-dht_neighbours.h" 34#include "gnunet-service-dht_neighbours.h"
35#include "gnunet-service-dht_routing.h" 35#include "gnunet-service-dht_routing.h"
36#include "dht.h" 36#include "dht.h"
@@ -88,11 +88,6 @@
88 */ 88 */
89#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) 89#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
90 90
91/**
92 * Hello address expiration
93 */
94extern struct GNUNET_TIME_Relative hello_expiration;
95
96 91
97GNUNET_NETWORK_STRUCT_BEGIN 92GNUNET_NETWORK_STRUCT_BEGIN
98 93
@@ -260,81 +255,129 @@ GNUNET_NETWORK_STRUCT_END
260/** 255/**
261 * Entry for a peer in a bucket. 256 * Entry for a peer in a bucket.
262 */ 257 */
263struct PeerInfo 258struct PeerInfo;
259
260
261/**
262 * List of targets that we can use to reach this peer.
263 */
264struct Target
264{ 265{
265 /** 266 /**
266 * Next peer entry (DLL) 267 * Kept in a DLL.
267 */ 268 */
268 struct PeerInfo *next; 269 struct Target *next;
269 270
270 /** 271 /**
271 * Prev peer entry (DLL) 272 * Kept in a DLL.
272 */ 273 */
273 struct PeerInfo *prev; 274 struct Target *prev;
274 275
275 /** 276 /**
276 * Handle for sending messages to this peer. 277 * Handle for sending messages to this peer.
277 */ 278 */
278 struct GNUNET_DHTU_Target *target; 279 struct GNUNET_DHTU_Target *utarget;
279 280
280 /** 281 /**
281 * What is the identity of the peer? 282 * Underlay providing this target.
282 */ 283 */
283 struct GNUNET_PeerIdentity id; 284 struct Underlay *u;
284 285
285 /** 286 /**
286 * Hash of @e id. 287 * Peer this is a target for.
287 */ 288 */
288 struct GNUNET_HashCode phash; 289 struct PeerInfo *pi;
289 290
290 /** 291 /**
291 * Which bucket is this peer in? 292 * Set to number of messages are waiting for the transmission to finish.
292 */ 293 */
293 int peer_bucket; 294 unsigned int load;
295
296 /**
297 * Set to @a true if the target was dropped, but we could not clean
298 * up yet because @e busy was also true.
299 */
300 bool dropped;
301
294}; 302};
295 303
296 304
297/** 305/**
298 * Peers are grouped into buckets. 306 * Entry for a peer in a bucket.
299 */ 307 */
300struct PeerBucket 308struct PeerInfo
301{ 309{
302 /** 310 /**
303 * Head of DLL 311 * What is the identity of the peer?
304 */ 312 */
305 struct PeerInfo *head; 313 struct GNUNET_PeerIdentity id;
306 314
307 /** 315 /**
308 * Tail of DLL 316 * Hash of @e id.
309 */ 317 */
310 struct PeerInfo *tail; 318 struct GNUNET_HashCode phash;
311 319
312 /** 320 /**
313 * Number of peers in the bucket. 321 * When does our HELLO from this peer expire?
314 */ 322 */
315 unsigned int peers_size; 323 struct GNUNET_TIME_Absolute hello_expiration;
324
325 /**
326 * Next peer entry (DLL)
327 */
328 struct PeerInfo *next;
329
330 /**
331 * Prev peer entry (DLL)
332 */
333 struct PeerInfo *prev;
334
335 /**
336 * Head of DLL of targets for this peer.
337 */
338 struct Target *t_head;
339
340 /**
341 * Tail of DLL of targets for this peer.
342 */
343 struct Target *t_tail;
344
345 /**
346 * Block with a HELLO of this peer.
347 */
348 void *hello;
349
350 /**
351 * Number of bytes in @e hello.
352 */
353 size_t hello_size;
354
355 /**
356 * Which bucket is this peer in?
357 */
358 int peer_bucket;
316}; 359};
317 360
318 361
319/** 362/**
320 * Information about a peer that we would like to connect to. 363 * Peers are grouped into buckets.
321 */ 364 */
322struct ConnectInfo 365struct PeerBucket
323{ 366{
324 /** 367 /**
325 * Handle to active HELLO offer operation, or NULL. 368 * Head of DLL
326 */ 369 */
327 struct GNUNET_TRANSPORT_OfferHelloHandle *oh; 370 struct PeerInfo *head;
328 371
329 /** 372 /**
330 * Handle to active connectivity suggestion operation, or NULL. 373 * Tail of DLL
331 */ 374 */
332 struct GNUNET_DHTU_PreferenceHandle *ph; 375 struct PeerInfo *tail;
333 376
334 /** 377 /**
335 * How much would we like to connect to this peer? 378 * Number of peers in the bucket.
336 */ 379 */
337 uint32_t strength; 380 unsigned int peers_size;
338}; 381};
339 382
340 383
@@ -371,12 +414,6 @@ static struct PeerBucket k_buckets[MAX_BUCKETS];
371static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers; 414static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
372 415
373/** 416/**
374 * Hash map of all peers we would like to be connected to.
375 * Values are of type `struct ConnectInfo`.
376 */
377static struct GNUNET_CONTAINER_MultiPeerMap *all_desired_peers;
378
379/**
380 * Maximum size for each bucket. 417 * Maximum size for each bucket.
381 */ 418 */
382static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; 419static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
@@ -386,20 +423,83 @@ static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
386 */ 423 */
387static struct GNUNET_SCHEDULER_Task *find_peer_task; 424static struct GNUNET_SCHEDULER_Task *find_peer_task;
388 425
389/**
390 * Identity of this peer.
391 */
392static struct GNUNET_PeerIdentity my_identity;
393 426
394/** 427/**
395 * Hash of the identity of this peer. 428 * Function called whenever we finished sending to a target.
429 * Marks the transmission as finished (and the target as ready
430 * for the next message).
431 *
432 * @param cls a `struct Target *`
396 */ 433 */
397struct GNUNET_HashCode my_identity_hash; 434static void
435send_done_cb (void *cls)
436{
437 struct Target *t = cls;
438 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
439
440 GNUNET_assert (t->load > 0);
441 t->load--;
442 if (0 < t->load)
443 return;
444 if (t->dropped)
445 {
446 GNUNET_free (t);
447 return;
448 }
449 /* move target back to the front */
450 GNUNET_CONTAINER_DLL_remove (pi->t_head,
451 pi->t_tail,
452 t);
453 GNUNET_CONTAINER_DLL_insert (pi->t_head,
454 pi->t_tail,
455 t);
456}
457
398 458
399/** 459/**
400 * Our private key. 460 * Send @a msg to @a pi.
461 *
462 * @param pi where to send the message
463 * @param msg message to send
401 */ 464 */
402static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key; 465static void
466do_send (struct PeerInfo *pi,
467 const struct GNUNET_MessageHeader *msg)
468{
469 struct Target *t;
470
471 for (t = pi->t_head;
472 NULL != t;
473 t = t->next)
474 if (t->load < MAXIMUM_PENDING_PER_PEER)
475 break;
476 if (NULL == t)
477 {
478 /* all targets busy, drop message */
479 GNUNET_STATISTICS_update (GDS_stats,
480 "# messages dropped (underlays busy)",
481 1,
482 GNUNET_NO);
483 return;
484 }
485 t->load++;
486 /* rotate busy targets to the end */
487 if (MAXIMUM_PENDING_PER_PEER == t->load)
488 {
489 GNUNET_CONTAINER_DLL_remove (pi->t_head,
490 pi->t_tail,
491 t);
492 GNUNET_CONTAINER_DLL_insert_tail (pi->t_head,
493 pi->t_tail,
494 t);
495 }
496 GDS_u_send (t->u,
497 t->utarget,
498 msg,
499 ntohs (msg->size),
500 &send_done_cb,
501 t);
502}
403 503
404 504
405/** 505/**
@@ -436,7 +536,7 @@ sign_path (const struct GNUNET_HashCode *key,
436 GNUNET_CRYPTO_hash (data, 536 GNUNET_CRYPTO_hash (data,
437 data_size, 537 data_size,
438 &hs.h_data); 538 &hs.h_data);
439 GNUNET_CRYPTO_eddsa_sign (&my_private_key, 539 GNUNET_CRYPTO_eddsa_sign (&GDS_my_private_key,
440 &hs, 540 &hs,
441 sig); 541 sig);
442} 542}
@@ -456,7 +556,7 @@ find_bucket (const struct GNUNET_HashCode *hc)
456 unsigned int bits; 556 unsigned int bits;
457 557
458 GNUNET_CRYPTO_hash_xor (hc, 558 GNUNET_CRYPTO_hash_xor (hc,
459 &my_identity_hash, 559 &GDS_my_identity_hash,
460 &xor); 560 &xor);
461 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor); 561 bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
462 if (bits == MAX_BUCKETS) 562 if (bits == MAX_BUCKETS)
@@ -470,175 +570,6 @@ find_bucket (const struct GNUNET_HashCode *hc)
470 570
471 571
472/** 572/**
473 * Function called when #GNUNET_TRANSPORT_offer_hello() is done.
474 * Clean up the "oh" field in the @a cls
475 *
476 * @param cls a `struct ConnectInfo`
477 */
478static void
479offer_hello_done (void *cls)
480{
481 struct ConnectInfo *ci = cls;
482
483 ci->oh = NULL;
484}
485
486
487/**
488 * Function called for all entries in #all_desired_peers to clean up.
489 *
490 * @param cls NULL
491 * @param peer peer the entry is for
492 * @param value the value to remove
493 * @return #GNUNET_YES
494 */
495static enum GNUNET_GenericReturnValue
496free_connect_info (void *cls,
497 const struct GNUNET_PeerIdentity *peer,
498 void *value)
499{
500 struct ConnectInfo *ci = value;
501
502 (void) cls;
503 GNUNET_assert (GNUNET_YES ==
504 GNUNET_CONTAINER_multipeermap_remove (all_desired_peers,
505 peer,
506 ci));
507 if (NULL != ci->ph)
508 {
509 // ci->u->drop (ci->ph); // FIXME!
510 ci->ph = NULL;
511 }
512 if (NULL != ci->oh)
513 {
514 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
515 ci->oh = NULL;
516 }
517 GNUNET_free (ci);
518 return GNUNET_YES;
519}
520
521
522/**
523 * Consider if we want to connect to a given peer, and if so
524 * let ATS know. If applicable, the HELLO is offered to the
525 * TRANSPORT service.
526 *
527 * @param pid peer to consider connectivity requirements for
528 * @param h a HELLO message, or NULL
529 */
530static void
531try_connect (const struct GNUNET_PeerIdentity *pid,
532 const struct GNUNET_MessageHeader *h)
533{
534 int bucket_idx;
535 struct GNUNET_HashCode pid_hash;
536 struct ConnectInfo *ci;
537 uint32_t strength;
538 struct PeerBucket *bucket;
539
540 GNUNET_CRYPTO_hash (pid,
541 sizeof(struct GNUNET_PeerIdentity),
542 &pid_hash);
543 bucket_idx = find_bucket (&pid_hash);
544 if (bucket_idx < 0)
545 {
546 GNUNET_break (0);
547 return; /* self!? */
548 }
549 bucket = &k_buckets[bucket_idx];
550 ci = GNUNET_CONTAINER_multipeermap_get (all_desired_peers,
551 pid);
552 if (bucket->peers_size < bucket_size)
553 strength = (bucket_size - bucket->peers_size) * bucket_idx;
554 else
555 strength = 0;
556 if (GNUNET_YES ==
557 GNUNET_CONTAINER_multipeermap_contains (all_connected_peers,
558 pid))
559 strength *= 2; /* double for connected peers */
560 if ( (0 == strength) &&
561 (NULL != ci) )
562 {
563 /* release request */
564 GNUNET_assert (GNUNET_YES ==
565 free_connect_info (NULL,
566 pid,
567 ci));
568 return;
569 }
570 if (NULL == ci)
571 {
572 ci = GNUNET_new (struct ConnectInfo);
573 GNUNET_assert (GNUNET_OK ==
574 GNUNET_CONTAINER_multipeermap_put (all_desired_peers,
575 pid,
576 ci,
577 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
578 }
579 if ( (NULL != ci->oh) &&
580 (NULL != h) )
581 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
582 if (NULL != h)
583 ci->oh = GNUNET_TRANSPORT_offer_hello (GDS_cfg,
584 h,
585 &offer_hello_done,
586 ci);
587 if ( (NULL != ci->ph) &&
588 (ci->strength != strength) )
589 {
590 // ci->u_api->drop (ci->ph);
591 ci->ph = NULL;
592 }
593 if (ci->strength != strength)
594 {
595#if FIXME
596 ci->ph = ci->u_api->hold (ci->u_api->cls,
597 TARGET);
598#endif
599 ci->strength = strength;
600 }
601}
602
603
604/**
605 * Function called for each peer in #all_desired_peers during
606 * #update_connect_preferences() if we have reason to adjust
607 * the strength of our desire to keep connections to certain
608 * peers. Calls #try_connect() to update the calculations for
609 * the given @a pid.
610 *
611 * @param cls NULL
612 * @param pid peer to update
613 * @param value unused
614 * @return #GNUNET_YES (continue to iterate)
615 */
616static enum GNUNET_GenericReturnValue
617update_desire_strength (void *cls,
618 const struct GNUNET_PeerIdentity *pid,
619 void *value)
620{
621 (void) cls;
622 (void) value;
623 try_connect (pid,
624 NULL);
625 return GNUNET_YES;
626}
627
628
629/**
630 * Update our preferences for connectivity as given to ATS.
631 */
632static void
633update_connect_preferences (void)
634{
635 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
636 &update_desire_strength,
637 NULL);
638}
639
640
641/**
642 * Add each of the peers we already know to the Bloom filter of 573 * Add each of the peers we already know to the Bloom filter of
643 * the request so that we don't get duplicate HELLOs. 574 * the request so that we don't get duplicate HELLOs.
644 * 575 *
@@ -728,11 +659,11 @@ send_find_peer_message (void *cls)
728 GNUNET_CONSTANTS_BLOOMFILTER_K); 659 GNUNET_CONSTANTS_BLOOMFILTER_K);
729 if (GNUNET_OK != 660 if (GNUNET_OK !=
730 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_URL_HELLO, 661 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
731 GNUNET_DHT_RO_FIND_PEER 662 GNUNET_DHT_RO_FIND_APPROXIMATE
732 | GNUNET_DHT_RO_RECORD_ROUTE, 663 | GNUNET_DHT_RO_RECORD_ROUTE,
733 FIND_PEER_REPLICATION_LEVEL, 664 FIND_PEER_REPLICATION_LEVEL,
734 0, /* hop count */ 665 0, /* hop count */
735 &my_identity_hash, 666 &GDS_my_identity_hash,
736 NULL, 0, /* xquery */ 667 NULL, 0, /* xquery */
737 bg, 668 bg,
738 peer_bf)) 669 peer_bf))
@@ -761,106 +692,131 @@ GDS_u_connect (void *cls,
761 const struct GNUNET_PeerIdentity *pid, 692 const struct GNUNET_PeerIdentity *pid,
762 void **ctx) 693 void **ctx)
763{ 694{
695 struct Underlay *u = cls;
764 struct PeerInfo *pi; 696 struct PeerInfo *pi;
765 struct PeerBucket *bucket; 697 struct PeerBucket *bucket;
766 698
767 (void) cls;
768 /* Check for connect to self message */ 699 /* Check for connect to self message */
769 if (0 == GNUNET_memcmp (&my_identity, 700 if (0 == GNUNET_memcmp (&GDS_my_identity,
770 pid)) 701 pid))
771 return; 702 return;
772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
773 "Connected to peer %s\n", 704 "Connected to peer %s\n",
774 GNUNET_i2s (pid)); 705 GNUNET_i2s (pid));
775 GNUNET_assert (NULL == 706 pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
776 GNUNET_CONTAINER_multipeermap_get (all_connected_peers, 707 pid);
777 pid)); 708 if (NULL == pi)
778 GNUNET_STATISTICS_update (GDS_stats,
779 "# peers connected",
780 1,
781 GNUNET_NO);
782 pi = GNUNET_new (struct PeerInfo);
783 pi->id = *pid;
784 pi->target = target;
785 GNUNET_CRYPTO_hash (pid,
786 sizeof(*pid),
787 &pi->phash);
788 pi->peer_bucket = find_bucket (&pi->phash);
789 GNUNET_assert ( (pi->peer_bucket >= 0) &&
790 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
791 bucket = &k_buckets[pi->peer_bucket];
792 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
793 bucket->tail,
794 pi);
795 bucket->peers_size++;
796 closest_bucket = GNUNET_MAX (closest_bucket,
797 (unsigned int) pi->peer_bucket + 1);
798 GNUNET_assert (GNUNET_OK ==
799 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
800 &pi->id,
801 pi,
802 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
803 if (bucket->peers_size <= bucket_size)
804 { 709 {
805 update_connect_preferences (); 710 GNUNET_STATISTICS_update (GDS_stats,
806 newly_found_peers++; 711 "# peers connected",
712 1,
713 GNUNET_NO);
714 pi = GNUNET_new (struct PeerInfo);
715 pi->id = *pid;
716 GNUNET_CRYPTO_hash (pid,
717 sizeof(*pid),
718 &pi->phash);
719 pi->peer_bucket = find_bucket (&pi->phash);
720 GNUNET_assert ( (pi->peer_bucket >= 0) &&
721 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
722 bucket = &k_buckets[pi->peer_bucket];
723 GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
724 bucket->tail,
725 pi);
726 bucket->peers_size++;
727 closest_bucket = GNUNET_MAX (closest_bucket,
728 (unsigned int) pi->peer_bucket + 1);
729 GNUNET_assert (GNUNET_OK ==
730 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
731 &pi->id,
732 pi,
733 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
734 if (bucket->peers_size <= bucket_size)
735 {
736 newly_found_peers++;
737 // FIXME: call 'hold'!
738 }
739 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
740 (GNUNET_YES != disable_try_connect) )
741 {
742 /* got a first connection, good time to start with FIND PEER requests... */
743 GNUNET_assert (NULL == find_peer_task);
744 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
745 NULL);
746 }
807 } 747 }
808 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
809 (GNUNET_YES != disable_try_connect) )
810 { 748 {
811 /* got a first connection, good time to start with FIND PEER requests... */ 749 struct Target *t;
812 GNUNET_assert (NULL == find_peer_task); 750
813 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message, 751 t = GNUNET_new (struct Target);
814 NULL); 752 t->u = u;
753 t->utarget = target;
754 t->pi = pi;
755 GNUNET_CONTAINER_DLL_insert (pi->t_head,
756 pi->t_tail,
757 t);
758 *ctx = t;
759
815 } 760 }
816 *ctx = pi;
817} 761}
818 762
819 763
820/**
821 * Method called whenever a peer disconnects.
822 *
823 * @param ctx context
824 */
825void 764void
826GDS_u_disconnect (void *ctx) 765GDS_u_disconnect (void *ctx)
827{ 766{
828 struct PeerInfo *to_remove = ctx; 767 struct Target *t = ctx;
768 struct PeerInfo *pi;
829 struct PeerBucket *bucket; 769 struct PeerBucket *bucket;
830 770
831 /* Check for disconnect from self message (on shutdown) */ 771 /* Check for disconnect from self message (on shutdown) */
832 if (NULL == to_remove) 772 if (NULL == t)
833 return; 773 return;
774 pi = t->pi;
775 GNUNET_CONTAINER_DLL_remove (pi->t_head,
776 pi->t_tail,
777 t);
778 if (t->load > 0)
779 {
780 t->dropped = true;
781 t->pi = NULL;
782 }
783 else
784 {
785 GNUNET_free (t);
786 }
787 if (NULL != pi->t_head)
788 return; /* got other connections still */
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "Disconnected from peer %s\n", 790 "Disconnected from peer %s\n",
836 GNUNET_i2s (&to_remove->id)); 791 GNUNET_i2s (&pi->id));
837 GNUNET_STATISTICS_update (GDS_stats, 792 GNUNET_STATISTICS_update (GDS_stats,
838 "# peers connected", 793 "# peers connected",
839 -1, 794 -1,
840 GNUNET_NO); 795 GNUNET_NO);
841 GNUNET_assert (GNUNET_YES == 796 GNUNET_assert (GNUNET_YES ==
842 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers, 797 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
843 &to_remove->id, 798 &pi->id,
844 to_remove)); 799 pi));
845 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) && 800 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
846 (GNUNET_YES != disable_try_connect)) 801 (GNUNET_YES != disable_try_connect))
847 { 802 {
848 GNUNET_SCHEDULER_cancel (find_peer_task); 803 GNUNET_SCHEDULER_cancel (find_peer_task);
849 find_peer_task = NULL; 804 find_peer_task = NULL;
850 } 805 }
851 GNUNET_assert (to_remove->peer_bucket >= 0); 806 GNUNET_assert (pi->peer_bucket >= 0);
852 bucket = &k_buckets[to_remove->peer_bucket]; 807 bucket = &k_buckets[pi->peer_bucket];
853 GNUNET_CONTAINER_DLL_remove (bucket->head, 808 GNUNET_CONTAINER_DLL_remove (bucket->head,
854 bucket->tail, 809 bucket->tail,
855 to_remove); 810 pi);
856 GNUNET_assert (bucket->peers_size > 0); 811 GNUNET_assert (bucket->peers_size > 0);
857 bucket->peers_size--; 812 bucket->peers_size--;
813 // FIXME: check if this peer was in one of the first 'bucket_size'
814 // peers, and call 'hold' on the next peer if there is any!
858 while ( (closest_bucket > 0) && 815 while ( (closest_bucket > 0) &&
859 (0 == k_buckets[closest_bucket - 1].peers_size)) 816 (0 == k_buckets[closest_bucket - 1].peers_size))
860 closest_bucket--; 817 closest_bucket--;
861 if (bucket->peers_size < bucket_size) 818 GNUNET_free (pi->hello);
862 update_connect_preferences (); 819 GNUNET_free (pi);
863 GNUNET_free (to_remove);
864} 820}
865 821
866 822
@@ -935,7 +891,7 @@ enum GNUNET_GenericReturnValue
935GDS_am_closest_peer (const struct GNUNET_HashCode *key, 891GDS_am_closest_peer (const struct GNUNET_HashCode *key,
936 const struct GNUNET_CONTAINER_BloomFilter *bloom) 892 const struct GNUNET_CONTAINER_BloomFilter *bloom)
937{ 893{
938 if (0 == GNUNET_memcmp (&my_identity_hash, 894 if (0 == GNUNET_memcmp (&GDS_my_identity_hash,
939 key)) 895 key))
940 return GNUNET_YES; 896 return GNUNET_YES;
941 for (int bucket_num = find_bucket (key); 897 for (int bucket_num = find_bucket (key);
@@ -962,7 +918,7 @@ GDS_am_closest_peer (const struct GNUNET_HashCode *key,
962 because an unfiltered peer exists, we are not the 918 because an unfiltered peer exists, we are not the
963 closest. */ 919 closest. */
964 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash, 920 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
965 &my_identity_hash, 921 &GDS_my_identity_hash,
966 key); 922 key);
967 switch (delta) 923 switch (delta)
968 { 924 {
@@ -1026,7 +982,7 @@ select_peer (const struct GNUNET_HashCode *key,
1026 struct GNUNET_HashCode xor; 982 struct GNUNET_HashCode xor;
1027 983
1028 GNUNET_CRYPTO_hash_xor (key, 984 GNUNET_CRYPTO_hash_xor (key,
1029 &my_identity_hash, 985 &GDS_my_identity_hash,
1030 &xor); 986 &xor);
1031 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor); 987 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1032 } 988 }
@@ -1046,9 +1002,10 @@ select_peer (const struct GNUNET_HashCode *key,
1046 if (count >= bucket_size) 1002 if (count >= bucket_size)
1047 break; /* we only consider first #bucket_size entries per bucket */ 1003 break; /* we only consider first #bucket_size entries per bucket */
1048 count++; 1004 count++;
1049 if (GNUNET_YES == 1005 if ( (NULL != bloom) &&
1050 GNUNET_CONTAINER_bloomfilter_test (bloom, 1006 (GNUNET_YES ==
1051 &pos->phash)) 1007 GNUNET_CONTAINER_bloomfilter_test (bloom,
1008 &pos->phash)) )
1052 { 1009 {
1053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1054 "Excluded peer `%s' due to BF match in greedy routing for %s\n", 1011 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
@@ -1134,18 +1091,20 @@ select_peer (const struct GNUNET_HashCode *key,
1134 1091
1135 for (unsigned int bc = 0; bc < closest_bucket; bc++) 1092 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1136 { 1093 {
1094 struct PeerBucket *bucket = &k_buckets[bc];
1137 unsigned int count = 0; 1095 unsigned int count = 0;
1138 1096
1139 for (struct PeerInfo *pos = k_buckets[bc].head; 1097 for (struct PeerInfo *pos = bucket->head;
1140 NULL != pos; 1098 NULL != pos;
1141 pos = pos->next) 1099 pos = pos->next)
1142 { 1100 {
1143 count++; 1101 count++;
1144 if (count > bucket_size) 1102 if (count > bucket_size)
1145 break; /* limits search to #bucket_size peers per bucket */ 1103 break; /* limits search to #bucket_size peers per bucket */
1146 if (GNUNET_YES == 1104 if ( (NULL != bloom) &&
1147 GNUNET_CONTAINER_bloomfilter_test (bloom, 1105 (GNUNET_YES ==
1148 &pos->phash)) 1106 GNUNET_CONTAINER_bloomfilter_test (bloom,
1107 &pos->phash)) )
1149 { 1108 {
1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1151 "Excluded peer `%s' due to BF match in random routing for %s\n", 1110 "Excluded peer `%s' due to BF match in random routing for %s\n",
@@ -1180,9 +1139,10 @@ select_peer (const struct GNUNET_HashCode *key,
1180 if (count > bucket_size) 1139 if (count > bucket_size)
1181 break; /* limits search to #bucket_size peers per bucket */ 1140 break; /* limits search to #bucket_size peers per bucket */
1182 1141
1183 if (GNUNET_YES == 1142 if ( (NULL != bloom) &&
1184 GNUNET_CONTAINER_bloomfilter_test (bloom, 1143 (GNUNET_YES ==
1185 &pos->phash)) 1144 GNUNET_CONTAINER_bloomfilter_test (bloom,
1145 &pos->phash)) )
1186 continue; /* Ignore bloomfiltered peers */ 1146 continue; /* Ignore bloomfiltered peers */
1187 if (0 == selected--) 1147 if (0 == selected--)
1188 { 1148 {
@@ -1296,7 +1256,7 @@ GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1296 bd->put_path, 1256 bd->put_path,
1297 bd->put_path_length, 1257 bd->put_path_length,
1298 NULL, 0, /* get_path */ 1258 NULL, 0, /* get_path */
1299 &my_identity)) 1259 &GDS_my_identity))
1300 { 1260 {
1301 GNUNET_break_op (0); 1261 GNUNET_break_op (0);
1302 put_path_length = 0; 1262 put_path_length = 0;
@@ -1304,10 +1264,10 @@ GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1304#endif 1264#endif
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 "Adding myself (%s) to PUT bloomfilter for %s\n", 1266 "Adding myself (%s) to PUT bloomfilter for %s\n",
1307 GNUNET_i2s (&my_identity), 1267 GNUNET_i2s (&GDS_my_identity),
1308 GNUNET_h2s (&bd->key)); 1268 GNUNET_h2s (&bd->key));
1309 GNUNET_CONTAINER_bloomfilter_add (bf, 1269 GNUNET_CONTAINER_bloomfilter_add (bf,
1310 &my_identity_hash); 1270 &GDS_my_identity_hash);
1311 GNUNET_STATISTICS_update (GDS_stats, 1271 GNUNET_STATISTICS_update (GDS_stats,
1312 "# PUT requests routed", 1272 "# PUT requests routed",
1313 1, 1273 1,
@@ -1324,7 +1284,7 @@ GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1324 "Routing PUT for %s terminates after %u hops at %s\n", 1284 "Routing PUT for %s terminates after %u hops at %s\n",
1325 GNUNET_h2s (&bd->key), 1285 GNUNET_h2s (&bd->key),
1326 (unsigned int) hop_count, 1286 (unsigned int) hop_count,
1327 GNUNET_i2s (&my_identity)); 1287 GNUNET_i2s (&GDS_my_identity));
1328 return GNUNET_NO; 1288 return GNUNET_NO;
1329 } 1289 }
1330 msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement) 1290 msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
@@ -1346,30 +1306,18 @@ GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1346 for (unsigned int i = 0; i < target_count; i++) 1306 for (unsigned int i = 0; i < target_count; i++)
1347 { 1307 {
1348 struct PeerInfo *target = targets[i]; 1308 struct PeerInfo *target = targets[i];
1349 struct GNUNET_MQ_Envelope *env;
1350 struct PeerPutMessage *ppm; 1309 struct PeerPutMessage *ppm;
1310 char buf[sizeof (*ppm) + msize] GNUNET_ALIGN;
1351 struct GNUNET_DHT_PathElement *pp; 1311 struct GNUNET_DHT_PathElement *pp;
1352 1312
1353#if FIXME_LEGACY
1354 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1355 {
1356 /* skip */
1357 GNUNET_STATISTICS_update (GDS_stats,
1358 "# P2P messages dropped due to full queue",
1359 1,
1360 GNUNET_NO);
1361 skip_count++;
1362 continue;
1363 }
1364#endif
1365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1366 "Routing PUT for %s after %u hops to %s\n", 1314 "Routing PUT for %s after %u hops to %s\n",
1367 GNUNET_h2s (&bd->key), 1315 GNUNET_h2s (&bd->key),
1368 (unsigned int) hop_count, 1316 (unsigned int) hop_count,
1369 GNUNET_i2s (&target->id)); 1317 GNUNET_i2s (&target->id));
1370 env = GNUNET_MQ_msg_extra (ppm, 1318 ppm = (struct PeerPutMessage *) buf;
1371 msize, 1319 ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
1372 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT); 1320 ppm->header.size = htons (sizeof (buf));
1373 ppm->options = htonl (options); 1321 ppm->options = htonl (options);
1374 ppm->type = htonl (bd->type); 1322 ppm->type = htonl (bd->type);
1375 ppm->hop_count = htonl (hop_count + 1); 1323 ppm->hop_count = htonl (hop_count + 1);
@@ -1405,10 +1353,8 @@ GDS_NEIGHBOURS_handle_put (const struct GDS_DATACACHE_BlockData *bd,
1405 GNUNET_memcpy (&pp[put_path_length], 1353 GNUNET_memcpy (&pp[put_path_length],
1406 bd->data, 1354 bd->data,
1407 bd->data_size); 1355 bd->data_size);
1408#if FIXME 1356 do_send (target,
1409 GNUNET_MQ_send (target->mq, 1357 &ppm->header);
1410 env);
1411#endif
1412 } 1358 }
1413 GNUNET_free (targets); 1359 GNUNET_free (targets);
1414 GNUNET_STATISTICS_update (GDS_stats, 1360 GNUNET_STATISTICS_update (GDS_stats,
@@ -1450,17 +1396,17 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1450 &targets); 1396 &targets);
1451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1452 "Adding myself (%s) to GET bloomfilter for %s\n", 1398 "Adding myself (%s) to GET bloomfilter for %s\n",
1453 GNUNET_i2s (&my_identity), 1399 GNUNET_i2s (&GDS_my_identity),
1454 GNUNET_h2s (key)); 1400 GNUNET_h2s (key));
1455 GNUNET_CONTAINER_bloomfilter_add (peer_bf, 1401 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1456 &my_identity_hash); 1402 &GDS_my_identity_hash);
1457 if (0 == target_count) 1403 if (0 == target_count)
1458 { 1404 {
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 "Routing GET for %s terminates after %u hops at %s\n", 1406 "Routing GET for %s terminates after %u hops at %s\n",
1461 GNUNET_h2s (key), 1407 GNUNET_h2s (key),
1462 (unsigned int) hop_count, 1408 (unsigned int) hop_count,
1463 GNUNET_i2s (&my_identity)); 1409 GNUNET_i2s (&GDS_my_identity));
1464 return GNUNET_NO; 1410 return GNUNET_NO;
1465 } 1411 }
1466 if (GNUNET_OK != 1412 if (GNUNET_OK !=
@@ -1487,30 +1433,18 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1487 for (unsigned int i = 0; i < target_count; i++) 1433 for (unsigned int i = 0; i < target_count; i++)
1488 { 1434 {
1489 struct PeerInfo *target = targets[i]; 1435 struct PeerInfo *target = targets[i];
1490 struct GNUNET_MQ_Envelope *env;
1491 struct PeerGetMessage *pgm; 1436 struct PeerGetMessage *pgm;
1437 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1492 char *xq; 1438 char *xq;
1493 1439
1494#if FIXME
1495 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1496 {
1497 /* skip */
1498 GNUNET_STATISTICS_update (GDS_stats,
1499 "# P2P messages dropped due to full queue",
1500 1,
1501 GNUNET_NO);
1502 skip_count++;
1503 continue;
1504 }
1505#endif
1506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1507 "Routing GET for %s after %u hops to %s\n", 1441 "Routing GET for %s after %u hops to %s\n",
1508 GNUNET_h2s (key), 1442 GNUNET_h2s (key),
1509 (unsigned int) hop_count, 1443 (unsigned int) hop_count,
1510 GNUNET_i2s (&target->id)); 1444 GNUNET_i2s (&target->id));
1511 env = GNUNET_MQ_msg_extra (pgm, 1445 pgm = (struct PeerGetMessage *) buf;
1512 msize, 1446 pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
1513 GNUNET_MESSAGE_TYPE_DHT_P2P_GET); 1447 pgm->header.size = htons (sizeof (buf));
1514 pgm->options = htonl (options); 1448 pgm->options = htonl (options);
1515 pgm->type = htonl (type); 1449 pgm->type = htonl (type);
1516 pgm->hop_count = htonl (hop_count + 1); 1450 pgm->hop_count = htonl (hop_count + 1);
@@ -1532,10 +1466,8 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1532 GNUNET_memcpy (&xq[xquery_size], 1466 GNUNET_memcpy (&xq[xquery_size],
1533 reply_bf, 1467 reply_bf,
1534 reply_bf_size); 1468 reply_bf_size);
1535#if FIXME 1469 do_send (target,
1536 GNUNET_MQ_send (target->mq, 1470 &pgm->header);
1537 env);
1538#endif
1539 } 1471 }
1540 GNUNET_STATISTICS_update (GDS_stats, 1472 GNUNET_STATISTICS_update (GDS_stats,
1541 "# GET messages queued for transmission", 1473 "# GET messages queued for transmission",
@@ -1562,8 +1494,6 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1562 unsigned int get_path_length, 1494 unsigned int get_path_length,
1563 const struct GNUNET_DHT_PathElement *get_path) 1495 const struct GNUNET_DHT_PathElement *get_path)
1564{ 1496{
1565 struct GNUNET_MQ_Envelope *env;
1566 struct PeerResultMessage *prm;
1567 struct GNUNET_DHT_PathElement *paths; 1497 struct GNUNET_DHT_PathElement *paths;
1568 size_t msize; 1498 size_t msize;
1569 unsigned int ppl = bd->put_path_length; 1499 unsigned int ppl = bd->put_path_length;
@@ -1578,7 +1508,7 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1578 bd->put_path_length, 1508 bd->put_path_length,
1579 get_path, 1509 get_path,
1580 get_path_length, 1510 get_path_length,
1581 &my_identity)) 1511 &GDS_my_identity))
1582 { 1512 {
1583 GNUNET_break_op (0); 1513 GNUNET_break_op (0);
1584 get_path_length = 0; 1514 get_path_length = 0;
@@ -1609,20 +1539,6 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1609 GNUNET_break (0); 1539 GNUNET_break (0);
1610 return; 1540 return;
1611 } 1541 }
1612#if FIXME
1613 if (GNUNET_MQ_get_length (pi->mq) >= MAXIMUM_PENDING_PER_PEER)
1614 {
1615 /* skip */
1616 GNUNET_STATISTICS_update (GDS_stats,
1617 "# P2P messages dropped due to full queue",
1618 1,
1619 GNUNET_NO);
1620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621 "Peer queue full, ignoring reply for key %s\n",
1622 GNUNET_h2s (&bd->key));
1623 return;
1624 }
1625#endif
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Forwarding reply for key %s to peer %s\n", 1543 "Forwarding reply for key %s to peer %s\n",
1628 GNUNET_h2s (query_hash), 1544 GNUNET_h2s (query_hash),
@@ -1631,41 +1547,44 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
1631 "# RESULT messages queued for transmission", 1547 "# RESULT messages queued for transmission",
1632 1, 1548 1,
1633 GNUNET_NO); 1549 GNUNET_NO);
1634 env = GNUNET_MQ_msg_extra (prm,
1635 msize,
1636 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1637 prm->type = htonl (bd->type);
1638 prm->put_path_length = htonl (ppl);
1639 prm->get_path_length = htonl (get_path_length);
1640 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1641 prm->key = *query_hash;
1642 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1643 GNUNET_memcpy (paths,
1644 bd->put_path,
1645 ppl * sizeof(struct GNUNET_DHT_PathElement));
1646 GNUNET_memcpy (&paths[ppl],
1647 get_path,
1648 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1649 /* 0 == get_path_length means path is not being tracked */
1650 if (0 != get_path_length)
1651 { 1550 {
1652 /* Note that the signature in 'get_path' was not initialized before, 1551 struct PeerResultMessage *prm;
1653 so this is crucial to avoid sending garbage. */ 1552 char buf[sizeof (*prm) + msize] GNUNET_ALIGN;
1654 sign_path (&bd->key, 1553
1655 bd->data, 1554 prm = (struct PeerResultMessage *) buf;
1656 bd->data_size, 1555 prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1657 bd->expiration_time, 1556 prm->header.size = htons (sizeof (buf));
1658 &paths[ppl + get_path_length - 1].pred, 1557 prm->type = htonl (bd->type);
1659 &pi->id, 1558 prm->put_path_length = htonl (ppl);
1660 &paths[ppl + get_path_length - 1].sig); 1559 prm->get_path_length = htonl (get_path_length);
1661 } 1560 prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
1662 GNUNET_memcpy (&paths[ppl + get_path_length], 1561 prm->key = *query_hash;
1562 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1563 GNUNET_memcpy (paths,
1564 bd->put_path,
1565 ppl * sizeof(struct GNUNET_DHT_PathElement));
1566 GNUNET_memcpy (&paths[ppl],
1567 get_path,
1568 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1569 /* 0 == get_path_length means path is not being tracked */
1570 if (0 != get_path_length)
1571 {
1572 /* Note that the signature in 'get_path' was not initialized before,
1573 so this is crucial to avoid sending garbage. */
1574 sign_path (&bd->key,
1663 bd->data, 1575 bd->data,
1664 bd->data_size); 1576 bd->data_size,
1665#if FIXME 1577 bd->expiration_time,
1666 GNUNET_MQ_send (pi->mq, 1578 &paths[ppl + get_path_length - 1].pred,
1667 env); 1579 &pi->id,
1668#endif 1580 &paths[ppl + get_path_length - 1].sig);
1581 }
1582 GNUNET_memcpy (&paths[ppl + get_path_length],
1583 bd->data,
1584 bd->data_size);
1585 do_send (pi,
1586 &prm->header);
1587 }
1669} 1588}
1670 1589
1671 1590
@@ -1819,7 +1738,7 @@ handle_dht_p2p_put (void *cls,
1819 bd.put_path, 1738 bd.put_path,
1820 putlen, 1739 putlen,
1821 NULL, 0, /* get_path */ 1740 NULL, 0, /* get_path */
1822 &my_identity)) 1741 &GDS_my_identity))
1823 { 1742 {
1824 GNUNET_break_op (0); 1743 GNUNET_break_op (0);
1825 putlen = 0; 1744 putlen = 0;
@@ -1875,45 +1794,60 @@ handle_dht_p2p_put (void *cls,
1875 1794
1876 1795
1877/** 1796/**
1878 * We have received a FIND PEER request. Send matching 1797 * We have received a request for a HELLO. Sends our
1879 * HELLOs back. 1798 * HELLO back.
1880 * 1799 *
1881 * @param pi sender of the FIND PEER request 1800 * @param pi sender of the request
1882 * @param key peers close to this key are desired 1801 * @param key peers close to this key are desired
1883 * @param bg group for filtering peers 1802 * @param bg group for filtering peers
1884 */ 1803 */
1885static void 1804static void
1886handle_find_peer (struct PeerInfo *pi, 1805handle_find_my_hello (struct PeerInfo *pi,
1887 const struct GNUNET_HashCode *query_hash, 1806 const struct GNUNET_HashCode *query_hash,
1888 struct GNUNET_BLOCK_Group *bg) 1807 struct GNUNET_BLOCK_Group *bg)
1889{ 1808{
1890 int bucket_idx; 1809 size_t block_size = 0;
1891 struct PeerBucket *bucket; 1810
1892 struct PeerInfo *peer; 1811 /* TODO: consider caching our HELLO block for a bit, to
1893 unsigned int choice; 1812 avoid signing too often here... */
1894 struct GDS_DATACACHE_BlockData bd = { 1813 GNUNET_break (GNUNET_NO ==
1895 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO 1814 GNUNET_HELLO_builder_to_block (GDS_my_hello,
1896 }; 1815 &GDS_my_private_key,
1897 1816 NULL,
1898 /* first, check about our own HELLO */ 1817 &block_size));
1899 if (NULL != GDS_my_hello)
1900 { 1818 {
1901 bd.expiration_time = GNUNET_TIME_relative_to_absolute ( 1819 char block[block_size];
1902 hello_expiration), 1820
1903 bd.key = my_identity_hash, 1821 if (GNUNET_OK !=
1904 bd.data = GDS_my_hello; 1822 GNUNET_HELLO_builder_to_block (GDS_my_hello,
1905 bd.data_size = GNUNET_HELLO_size ( 1823 &GDS_my_private_key,
1906 (const struct GNUNET_HELLO_Message *) GDS_my_hello); 1824 block,
1907 GNUNET_break (bd.data_size >= sizeof(struct GNUNET_MessageHeader)); 1825 &block_size))
1908 if (GNUNET_BLOCK_REPLY_OK_MORE ==
1909 GNUNET_BLOCK_check_reply (GDS_block_context,
1910 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1911 bg,
1912 &my_identity_hash,
1913 NULL, 0,
1914 bd.data,
1915 bd.data_size))
1916 { 1826 {
1827 GNUNET_STATISTICS_update (GDS_stats,
1828 "# FIND PEER requests ignored due to lack of HELLO",
1829 1,
1830 GNUNET_NO);
1831 }
1832 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
1833 GNUNET_BLOCK_check_reply (GDS_block_context,
1834 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1835 bg,
1836 &GDS_my_identity_hash,
1837 NULL, 0,
1838 block,
1839 block_size))
1840 {
1841 struct GDS_DATACACHE_BlockData bd = {
1842 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1843 .expiration_time
1844 = GNUNET_TIME_relative_to_absolute (
1845 GNUNET_HELLO_ADDRESS_EXPIRATION),
1846 .key = GDS_my_identity_hash,
1847 .data = block,
1848 .data_size = block_size
1849 };
1850
1917 GDS_NEIGHBOURS_handle_reply (pi, 1851 GDS_NEIGHBOURS_handle_reply (pi,
1918 &bd, 1852 &bd,
1919 query_hash, 1853 query_hash,
@@ -1927,66 +1861,48 @@ handle_find_peer (struct PeerInfo *pi,
1927 GNUNET_NO); 1861 GNUNET_NO);
1928 } 1862 }
1929 } 1863 }
1930 else 1864}
1931 {
1932 GNUNET_STATISTICS_update (GDS_stats,
1933 "# FIND PEER requests ignored due to lack of HELLO",
1934 1,
1935 GNUNET_NO);
1936 }
1937 1865
1938 /* then, also consider sending a random HELLO from the closest bucket */
1939 /* FIXME: How can this be true? Shouldnt we just do find_bucket() ? */
1940 if (0 ==
1941 GNUNET_memcmp (&my_identity_hash,
1942 query_hash))
1943 bucket_idx = closest_bucket - 1;
1944 else
1945 bucket_idx = GNUNET_MIN ((int) closest_bucket - 1,
1946 find_bucket (query_hash));
1947 if (bucket_idx < 0)
1948 return;
1949 bucket = &k_buckets[bucket_idx];
1950 if (bucket->peers_size == 0)
1951 return;
1952 choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1953 bucket->peers_size);
1954 peer = bucket->head;
1955 while (choice > 0)
1956 {
1957 GNUNET_assert (NULL != peer);
1958 peer = peer->next;
1959 choice--;
1960 }
1961 choice = bucket->peers_size;
1962 1866
1867/**
1868 * We have received a request for nearby HELLOs. Sends matching
1869 * HELLOs back.
1870 *
1871 * @param pi sender of the request
1872 * @param key peers close to this key are desired
1873 * @param bg group for filtering peers
1874 */
1875static void
1876handle_find_local_hello (struct PeerInfo *pi,
1877 const struct GNUNET_HashCode *query_hash,
1878 struct GNUNET_BLOCK_Group *bg)
1879{
1880 /* Force non-random selection by hop count */
1881 struct PeerInfo *peer;
1882
1883 peer = select_peer (query_hash,
1884 NULL,
1885 GDS_NSE_get () + 1);
1886 if ( (NULL != peer->hello) &&
1887 (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
1888 (GNUNET_BLOCK_REPLY_OK_MORE ==
1889 GNUNET_BLOCK_check_reply (
1890 GDS_block_context,
1891 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1892 bg,
1893 &peer->phash,
1894 NULL, 0, /* xquery */
1895 peer->hello,
1896 peer->hello_size)) )
1963 { 1897 {
1964 const struct GNUNET_HELLO_Message *hello; 1898 struct GDS_DATACACHE_BlockData bd = {
1965 size_t hello_size; 1899 .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1900 .expiration_time = peer->hello_expiration,
1901 .key = peer->phash,
1902 .data = peer->hello,
1903 .data_size = peer->hello_size
1904 };
1966 1905
1967 do
1968 {
1969 peer = peer->next;
1970 if (0 == choice--)
1971 return; /* no non-masked peer available */
1972 if (NULL == peer)
1973 peer = bucket->head;
1974 hello = GDS_HELLO_get (&peer->id);
1975 } while ( (NULL == hello) ||
1976 (GNUNET_BLOCK_REPLY_OK_MORE !=
1977 GNUNET_BLOCK_check_reply (
1978 GDS_block_context,
1979 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
1980 bg,
1981 &peer->phash,
1982 NULL, 0, /* xquery */
1983 hello,
1984 (hello_size = GNUNET_HELLO_size (hello)))));
1985 bd.expiration_time = GNUNET_TIME_relative_to_absolute (
1986 GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION);
1987 bd.key = peer->phash;
1988 bd.data = hello;
1989 bd.data_size = hello_size;
1990 GDS_NEIGHBOURS_handle_reply (pi, 1906 GDS_NEIGHBOURS_handle_reply (pi,
1991 &bd, 1907 &bd,
1992 query_hash, 1908 query_hash,
@@ -2101,32 +2017,45 @@ handle_dht_p2p_get (void *cls,
2101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2102 "GET for %s at %s after %u hops\n", 2018 "GET for %s at %s after %u hops\n",
2103 GNUNET_h2s (&get->key), 2019 GNUNET_h2s (&get->key),
2104 GNUNET_i2s (&my_identity), 2020 GNUNET_i2s (&GDS_my_identity),
2105 (unsigned int) hop_count); 2021 (unsigned int) hop_count);
2106 /* local lookup (this may update the reply_bf) */ 2022 /* local lookup (this may update the bg) */
2107 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || 2023 if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2108 (GDS_am_closest_peer (&get->key, 2024 (GDS_am_closest_peer (&get->key,
2109 peer_bf)) ) 2025 peer_bf)) )
2110 { 2026 {
2111 if ((0 != (options & GNUNET_DHT_RO_FIND_PEER))) 2027 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == type)
2112 { 2028 {
2113 GNUNET_STATISTICS_update (GDS_stats, 2029 GNUNET_STATISTICS_update (GDS_stats,
2114 "# P2P FIND PEER requests processed", 2030 "# P2P HELLO lookup requests processed",
2115 1, 2031 1,
2116 GNUNET_NO); 2032 GNUNET_NO);
2117 handle_find_peer (peer, 2033 handle_find_my_hello (peer,
2118 &get->key, 2034 &get->key,
2119 bg); 2035 bg);
2036 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2037 handle_find_local_hello (peer,
2038 &get->key,
2039 bg);
2120 } 2040 }
2121 else 2041 else
2122 { 2042 {
2123 eval = GDS_DATACACHE_handle_get (&get->key, 2043 if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
2124 type, 2044 eval = GDS_DATACACHE_get_closest (&get->key,
2125 xquery, 2045 type,
2126 xquery_size, 2046 xquery,
2127 bg, 2047 xquery_size,
2128 &handle_local_result, 2048 bg,
2129 peer); 2049 &handle_local_result,
2050 peer);
2051 else
2052 eval = GDS_DATACACHE_handle_get (&get->key,
2053 type,
2054 xquery,
2055 xquery_size,
2056 bg,
2057 &handle_local_result,
2058 peer);
2130 } 2059 }
2131 } 2060 }
2132 else 2061 else
@@ -2137,7 +2066,9 @@ handle_dht_p2p_get (void *cls,
2137 GNUNET_NO); 2066 GNUNET_NO);
2138 } 2067 }
2139 2068
2140 /* remember request for routing replies */ 2069 /* remember request for routing replies
2070 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2071 */
2141 GDS_ROUTING_add (&peer->id, 2072 GDS_ROUTING_add (&peer->id,
2142 type, 2073 type,
2143 bg, /* bg now owned by routing, but valid at least until end of this function! */ 2074 bg, /* bg now owned by routing, but valid at least until end of this function! */
@@ -2260,6 +2191,52 @@ check_dht_p2p_result (void *cls,
2260 2191
2261 2192
2262/** 2193/**
2194 * Callback function used to extract URIs from a builder.
2195 * Called when we should consider connecting to a peer.
2196 *
2197 * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
2198 * @param uri one of the URIs
2199 */
2200static void
2201try_connect (void *cls,
2202 const char *uri)
2203{
2204 const struct GNUNET_PeerIdentity *pid = cls;
2205 struct GNUNET_HashCode phash;
2206 int peer_bucket;
2207 struct PeerBucket *bucket;
2208
2209 if (0 == GNUNET_memcmp (&GDS_my_identity,
2210 pid))
2211 return; /* that's us! */
2212 GNUNET_CRYPTO_hash (pid,
2213 sizeof(*pid),
2214 &phash);
2215 peer_bucket = find_bucket (&phash);
2216 GNUNET_assert ( (peer_bucket >= 0) &&
2217 ((unsigned int) peer_bucket < MAX_BUCKETS));
2218 bucket = &k_buckets[peer_bucket];
2219 if (bucket->peers_size >= bucket_size)
2220 return; /* do not care */
2221 for (struct PeerInfo *pi = bucket->head;
2222 NULL != pi;
2223 pi = pi->next)
2224 if (0 ==
2225 GNUNET_memcmp (&pi->id,
2226 pid))
2227 {
2228 /* already connected */
2229 /* TODO: maybe consider 'uri' anyway as an additional
2230 alternative address??? */
2231 return;
2232 }
2233 /* new peer that we like! */
2234 GDS_u_try_connect (pid,
2235 uri);
2236}
2237
2238
2239/**
2263 * Core handler for p2p result messages. 2240 * Core handler for p2p result messages.
2264 * 2241 *
2265 * @param cls closure 2242 * @param cls closure
@@ -2333,32 +2310,17 @@ handle_dht_p2p_result (void *cls,
2333 /* if we got a HELLO, consider it for our own routing table */ 2310 /* if we got a HELLO, consider it for our own routing table */
2334 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == bd.type) 2311 if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == bd.type)
2335 { 2312 {
2336 const struct GNUNET_MessageHeader *h = bd.data;
2337 struct GNUNET_PeerIdentity pid; 2313 struct GNUNET_PeerIdentity pid;
2338 2314 struct GNUNET_HELLO_Builder *b;
2339 /* Should be a HELLO, validate and consider using it! */ 2315
2340 if (bd.data_size < sizeof(struct GNUNET_HELLO_Message)) 2316 b = GNUNET_HELLO_builder_from_block (bd.data,
2341 { 2317 bd.data_size);
2342 GNUNET_break (0); 2318 if (GNUNET_YES != disable_try_connect)
2343 return; 2319 GNUNET_HELLO_builder_iterate (b,
2344 } 2320 &pid,
2345 if (bd.data_size != ntohs (h->size)) 2321 &try_connect,
2346 { 2322 &pid);
2347 GNUNET_break (0); 2323 GNUNET_HELLO_builder_free (b);
2348 return;
2349 }
2350 if (GNUNET_OK !=
2351 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h,
2352 &pid))
2353 {
2354 GNUNET_break_op (0);
2355 return;
2356 }
2357 if ( (GNUNET_YES != disable_try_connect) &&
2358 (0 != GNUNET_memcmp (&my_identity,
2359 &pid)) )
2360 try_connect (&pid,
2361 h);
2362 } 2324 }
2363 2325
2364 /* First, check if 'peer' is already on the path, and if 2326 /* First, check if 'peer' is already on the path, and if
@@ -2391,6 +2353,50 @@ handle_dht_p2p_result (void *cls,
2391} 2353}
2392 2354
2393 2355
2356/**
2357 * Check validity of a p2p hello message.
2358 *
2359 * @param cls closure
2360 * @param hello message
2361 * @return #GNUNET_YES if the message is well-formed
2362 */
2363static enum GNUNET_GenericReturnValue
2364check_dht_p2p_hello (void *cls,
2365 const struct GNUNET_MessageHeader *hello)
2366{
2367 struct GNUNET_HELLO_Builder *b;
2368 enum GNUNET_GenericReturnValue ret;
2369
2370 b = GNUNET_HELLO_builder_from_msg (hello);
2371 ret = (NULL == b) ? GNUNET_SYSERR : GNUNET_OK;
2372 GNUNET_HELLO_builder_free (b);
2373 return ret;
2374}
2375
2376
2377/**
2378 * Core handler for p2p HELLO messages.
2379 *
2380 * @param cls closure
2381 * @param message message
2382 */
2383static void
2384handle_dht_p2p_hello (void *cls,
2385 const struct GNUNET_MessageHeader *hello)
2386{
2387 struct PeerInfo *peer = cls;
2388
2389 GNUNET_free (peer->hello);
2390 peer->hello_size = 0;
2391 GNUNET_break (GNUNET_OK ==
2392 GNUNET_HELLO_dht_msg_to_block (hello,
2393 &peer->id,
2394 &peer->hello,
2395 &peer->hello_size,
2396 &peer->hello_expiration));
2397}
2398
2399
2394void 2400void
2395GDS_u_receive (void *cls, 2401GDS_u_receive (void *cls,
2396 void **tctx, 2402 void **tctx,
@@ -2412,6 +2418,10 @@ GDS_u_receive (void *cls,
2412 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, 2418 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2413 struct PeerResultMessage, 2419 struct PeerResultMessage,
2414 pi), 2420 pi),
2421 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2422 GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO,
2423 struct GNUNET_MessageHeader,
2424 pi),
2415 GNUNET_MQ_handler_end () 2425 GNUNET_MQ_handler_end ()
2416 }; 2426 };
2417 const struct GNUNET_MessageHeader *mh = message; 2427 const struct GNUNET_MessageHeader *mh = message;
@@ -2438,6 +2448,34 @@ GDS_u_receive (void *cls,
2438} 2448}
2439 2449
2440 2450
2451/**
2452 * Send @a msg to all peers in our buckets.
2453 *
2454 * @param msg message to broadcast
2455 */
2456void
2457GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
2458{
2459 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2460 {
2461 struct PeerBucket *bucket = &k_buckets[bc];
2462 unsigned int count = 0;
2463
2464 for (struct PeerInfo *pos = bucket->head;
2465 NULL != pos;
2466 pos = pos->next)
2467 {
2468 if (count >= bucket_size)
2469 break; /* we only consider first #bucket_size entries per bucket */
2470 count++;
2471 GNUNET_break (0);
2472 do_send (pos,
2473 msg);
2474 }
2475 }
2476}
2477
2478
2441enum GNUNET_GenericReturnValue 2479enum GNUNET_GenericReturnValue
2442GDS_NEIGHBOURS_init () 2480GDS_NEIGHBOURS_init ()
2443{ 2481{
@@ -2458,41 +2496,8 @@ GDS_NEIGHBOURS_init ()
2458 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg, 2496 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2459 "DHT", 2497 "DHT",
2460 "CACHE_RESULTS"); 2498 "CACHE_RESULTS");
2461 {
2462 char *keyfile;
2463
2464 if (GNUNET_OK !=
2465 GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
2466 "PEER",
2467 "PRIVATE_KEY",
2468 &keyfile))
2469 {
2470 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2471 "Core service is lacking HOSTKEY configuration setting. Exiting.\n");
2472 return GNUNET_SYSERR;
2473 }
2474 if (GNUNET_SYSERR ==
2475 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
2476 GNUNET_YES,
2477 &my_private_key))
2478 {
2479 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2480 "Failed to setup peer's private key\n");
2481 GNUNET_free (keyfile);
2482 return GNUNET_SYSERR;
2483 }
2484 GNUNET_free (keyfile);
2485 }
2486 GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
2487 &my_identity.public_key);
2488 GNUNET_CRYPTO_hash (&my_identity,
2489 sizeof(struct GNUNET_PeerIdentity),
2490 &my_identity_hash);
2491
2492 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256, 2499 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2493 GNUNET_YES); 2500 GNUNET_YES);
2494 all_desired_peers = GNUNET_CONTAINER_multipeermap_create (256,
2495 GNUNET_NO);
2496 return GNUNET_OK; 2501 return GNUNET_OK;
2497} 2502}
2498 2503
@@ -2506,11 +2511,6 @@ GDS_NEIGHBOURS_done ()
2506 GNUNET_CONTAINER_multipeermap_size (all_connected_peers)); 2511 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2507 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers); 2512 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2508 all_connected_peers = NULL; 2513 all_connected_peers = NULL;
2509 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
2510 &free_connect_info,
2511 NULL);
2512 GNUNET_CONTAINER_multipeermap_destroy (all_desired_peers);
2513 all_desired_peers = NULL;
2514 GNUNET_assert (NULL == find_peer_task); 2514 GNUNET_assert (NULL == find_peer_task);
2515} 2515}
2516 2516
@@ -2518,7 +2518,7 @@ GDS_NEIGHBOURS_done ()
2518struct GNUNET_PeerIdentity * 2518struct GNUNET_PeerIdentity *
2519GDS_NEIGHBOURS_get_id () 2519GDS_NEIGHBOURS_get_id ()
2520{ 2520{
2521 return &my_identity; 2521 return &GDS_my_identity;
2522} 2522}
2523 2523
2524 2524