diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-08-05 15:45:37 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-08-05 15:45:37 +0000 |
commit | c59802b4a2aa41f3293121742eaacd8df295302c (patch) | |
tree | b1514417abb26b66328eec964270aecee9c2d7b6 /src | |
parent | f52b27f49550725feebd74567b5e014122d05369 (diff) | |
download | gnunet-c59802b4a2aa41f3293121742eaacd8df295302c.tar.gz gnunet-c59802b4a2aa41f3293121742eaacd8df295302c.zip |
routing table changes, not stable
Diffstat (limited to 'src')
-rw-r--r-- | src/dht/gnunet-service-dht.c | 318 |
1 files changed, 241 insertions, 77 deletions
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c index 1e2ba80a1..125bd7fff 100644 --- a/src/dht/gnunet-service-dht.c +++ b/src/dht/gnunet-service-dht.c | |||
@@ -41,12 +41,20 @@ | |||
41 | #include "dhtlog.h" | 41 | #include "dhtlog.h" |
42 | #include "dht.h" | 42 | #include "dht.h" |
43 | 43 | ||
44 | #define PRINT_TABLES GNUNET_NO | ||
45 | |||
46 | #define EXTRA_CHECKS GNUNET_YES | ||
44 | /** | 47 | /** |
45 | * How many buckets will we allow total. | 48 | * How many buckets will we allow total. |
46 | */ | 49 | */ |
47 | #define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8 | 50 | #define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8 |
48 | 51 | ||
49 | /** | 52 | /** |
53 | * Should the DHT issue FIND_PEER requests to get better routing tables? | ||
54 | */ | ||
55 | #define DO_FIND_PEER GNUNET_YES | ||
56 | |||
57 | /** | ||
50 | * What is the maximum number of peers in a given bucket. | 58 | * What is the maximum number of peers in a given bucket. |
51 | */ | 59 | */ |
52 | #define DEFAULT_BUCKET_SIZE 8 | 60 | #define DEFAULT_BUCKET_SIZE 8 |
@@ -62,7 +70,7 @@ | |||
62 | 70 | ||
63 | #define DHT_DEFAULT_FIND_PEER_OPTIONS GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE | 71 | #define DHT_DEFAULT_FIND_PEER_OPTIONS GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE |
64 | 72 | ||
65 | #define DHT_DEFAULT_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | 73 | #define DHT_DEFAULT_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 1) |
66 | 74 | ||
67 | /** | 75 | /** |
68 | * Real maximum number of hops, at which point we refuse | 76 | * Real maximum number of hops, at which point we refuse |
@@ -473,6 +481,11 @@ static unsigned int lowest_bucket; /* Initially equal to MAX_BUCKETS - 1 */ | |||
473 | static struct PeerBucket k_buckets[MAX_BUCKETS]; /* From 0 to MAX_BUCKETS - 1 */ | 481 | static struct PeerBucket k_buckets[MAX_BUCKETS]; /* From 0 to MAX_BUCKETS - 1 */ |
474 | 482 | ||
475 | /** | 483 | /** |
484 | * Hash map of all known peers, for easy removal from k_buckets on disconnect. | ||
485 | */ | ||
486 | static struct GNUNET_CONTAINER_MultiHashMap *all_known_peers; | ||
487 | |||
488 | /** | ||
476 | * Maximum size for each bucket. | 489 | * Maximum size for each bucket. |
477 | */ | 490 | */ |
478 | static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; /* Initially equal to DEFAULT_BUCKET_SIZE */ | 491 | static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; /* Initially equal to DEFAULT_BUCKET_SIZE */ |
@@ -798,6 +811,65 @@ static int find_current_bucket(const GNUNET_HashCode *hc) | |||
798 | /** | 811 | /** |
799 | * Find a routing table entry from a peer identity | 812 | * Find a routing table entry from a peer identity |
800 | * | 813 | * |
814 | * @param peer the peer to look up | ||
815 | * | ||
816 | * @return the bucket number holding the peer, GNUNET_SYSERR if not found | ||
817 | */ | ||
818 | static int | ||
819 | find_bucket_by_peer(const struct PeerInfo *peer) | ||
820 | { | ||
821 | int bucket; | ||
822 | struct PeerInfo *pos; | ||
823 | |||
824 | for (bucket = lowest_bucket; bucket < MAX_BUCKETS - 1; bucket++) | ||
825 | { | ||
826 | pos = k_buckets[bucket].head; | ||
827 | while (pos != NULL) | ||
828 | { | ||
829 | if (peer == pos) | ||
830 | return bucket; | ||
831 | pos = pos->next; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | return GNUNET_SYSERR; /* No such peer. */ | ||
836 | } | ||
837 | |||
838 | #if PRINT_TABLES | ||
839 | /** | ||
840 | * Print the complete routing table for this peer. | ||
841 | */ | ||
842 | static void | ||
843 | print_routing_table () | ||
844 | { | ||
845 | int bucket; | ||
846 | struct PeerInfo *pos; | ||
847 | char char_buf[30000]; | ||
848 | int char_pos; | ||
849 | memset(char_buf, 0, sizeof(char_buf)); | ||
850 | char_pos = 0; | ||
851 | char_pos += sprintf(&char_buf[char_pos], "Printing routing table for peer %s\n", my_short_id); | ||
852 | //fprintf(stderr, "Printing routing table for peer %s\n", my_short_id); | ||
853 | for (bucket = lowest_bucket; bucket < MAX_BUCKETS; bucket++) | ||
854 | { | ||
855 | pos = k_buckets[bucket].head; | ||
856 | char_pos += sprintf(&char_buf[char_pos], "Bucket %d:\n", bucket); | ||
857 | //fprintf(stderr, "Bucket %d:\n", bucket); | ||
858 | while (pos != NULL) | ||
859 | { | ||
860 | //fprintf(stderr, "\tPeer %s, best bucket %d, %d bits match\n", GNUNET_i2s(&pos->id), find_bucket(&pos->id.hashPubKey), matching_bits(&pos->id.hashPubKey, &my_identity.hashPubKey)); | ||
861 | char_pos += sprintf(&char_buf[char_pos], "\tPeer %s, best bucket %d, %d bits match\n", GNUNET_i2s(&pos->id), find_bucket(&pos->id.hashPubKey), matching_bits(&pos->id.hashPubKey, &my_identity.hashPubKey)); | ||
862 | pos = pos->next; | ||
863 | } | ||
864 | } | ||
865 | fprintf(stderr, "%s", char_buf); | ||
866 | fflush(stderr); | ||
867 | } | ||
868 | #endif | ||
869 | |||
870 | /** | ||
871 | * Find a routing table entry from a peer identity | ||
872 | * | ||
801 | * @param peer the peer identity to look up | 873 | * @param peer the peer identity to look up |
802 | * | 874 | * |
803 | * @return the routing table entry, or NULL if not found | 875 | * @return the routing table entry, or NULL if not found |
@@ -831,11 +903,14 @@ find_peer_by_id(const struct GNUNET_PeerIdentity *peer) | |||
831 | * the peer to | 903 | * the peer to |
832 | * @param latency the core reported latency of this peer | 904 | * @param latency the core reported latency of this peer |
833 | * @param distance the transport level distance to this peer | 905 | * @param distance the transport level distance to this peer |
906 | * | ||
907 | * @return the newly added PeerInfo | ||
834 | */ | 908 | */ |
835 | static void add_peer(const struct GNUNET_PeerIdentity *peer, | 909 | static struct PeerInfo * |
836 | unsigned int bucket, | 910 | add_peer(const struct GNUNET_PeerIdentity *peer, |
837 | struct GNUNET_TIME_Relative latency, | 911 | unsigned int bucket, |
838 | unsigned int distance) | 912 | struct GNUNET_TIME_Relative latency, |
913 | unsigned int distance) | ||
839 | { | 914 | { |
840 | struct PeerInfo *new_peer; | 915 | struct PeerInfo *new_peer; |
841 | GNUNET_assert(bucket < MAX_BUCKETS); | 916 | GNUNET_assert(bucket < MAX_BUCKETS); |
@@ -850,6 +925,8 @@ static void add_peer(const struct GNUNET_PeerIdentity *peer, | |||
850 | k_buckets[bucket].tail, | 925 | k_buckets[bucket].tail, |
851 | new_peer); | 926 | new_peer); |
852 | k_buckets[bucket].peers_size++; | 927 | k_buckets[bucket].peers_size++; |
928 | |||
929 | return new_peer; | ||
853 | } | 930 | } |
854 | 931 | ||
855 | /** | 932 | /** |
@@ -870,6 +947,8 @@ static void remove_peer (struct PeerInfo *peer, | |||
870 | k_buckets[bucket].tail, | 947 | k_buckets[bucket].tail, |
871 | peer); | 948 | peer); |
872 | k_buckets[bucket].peers_size--; | 949 | k_buckets[bucket].peers_size--; |
950 | if ((bucket == lowest_bucket) && (k_buckets[lowest_bucket].peers_size == 0) && (lowest_bucket < MAX_BUCKETS - 1)) | ||
951 | lowest_bucket++; | ||
873 | } | 952 | } |
874 | 953 | ||
875 | /** | 954 | /** |
@@ -884,6 +963,21 @@ static void delete_peer (struct PeerInfo *peer, | |||
884 | { | 963 | { |
885 | struct P2PPendingMessage *pos; | 964 | struct P2PPendingMessage *pos; |
886 | struct P2PPendingMessage *next; | 965 | struct P2PPendingMessage *next; |
966 | //fprintf(stderr, "BEFORE REMOVAL\n"); | ||
967 | //print_routing_table(); | ||
968 | #if EXTRA_CHECKS | ||
969 | struct PeerInfo *peer_pos; | ||
970 | |||
971 | peer_pos = k_buckets[bucket].head; | ||
972 | while ((peer_pos != NULL) && (peer_pos != peer)) | ||
973 | peer_pos = peer_pos->next; | ||
974 | if (peer_pos == NULL) | ||
975 | { | ||
976 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s:%s: Expected peer `%s' in bucket %d\n", my_short_id, "DHT", GNUNET_i2s(&peer->id), bucket); | ||
977 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s:%s: Lowest bucket: %d, find_current_bucket: %d, peer resides in bucket: %d\n", my_short_id, "DHT", lowest_bucket, find_current_bucket(&peer->id.hashPubKey), find_bucket_by_peer(peer)); | ||
978 | } | ||
979 | GNUNET_assert(peer_pos != NULL); | ||
980 | #endif | ||
887 | remove_peer(peer, bucket); /* First remove the peer from its bucket */ | 981 | remove_peer(peer, bucket); /* First remove the peer from its bucket */ |
888 | 982 | ||
889 | if (peer->send_task != GNUNET_SCHEDULER_NO_TASK) | 983 | if (peer->send_task != GNUNET_SCHEDULER_NO_TASK) |
@@ -898,9 +992,43 @@ static void delete_peer (struct PeerInfo *peer, | |||
898 | GNUNET_free(pos); | 992 | GNUNET_free(pos); |
899 | pos = next; | 993 | pos = next; |
900 | } | 994 | } |
995 | |||
996 | GNUNET_assert(GNUNET_CONTAINER_multihashmap_contains(all_known_peers, &peer->id.hashPubKey)); | ||
997 | GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (all_known_peers, &peer->id.hashPubKey, peer)); | ||
901 | GNUNET_free(peer); | 998 | GNUNET_free(peer); |
999 | //fprintf(stderr, "AFTER REMOVAL\n"); | ||
1000 | //print_routing_table(); | ||
902 | } | 1001 | } |
903 | 1002 | ||
1003 | |||
1004 | /** | ||
1005 | * Iterator over hash map entries. | ||
1006 | * | ||
1007 | * @param cls closure | ||
1008 | * @param key current key code | ||
1009 | * @param value PeerInfo of the peer to move to new lowest bucket | ||
1010 | * @return GNUNET_YES if we should continue to | ||
1011 | * iterate, | ||
1012 | * GNUNET_NO if not. | ||
1013 | */ | ||
1014 | static int move_lowest_bucket (void *cls, | ||
1015 | const GNUNET_HashCode * key, | ||
1016 | void *value) | ||
1017 | { | ||
1018 | struct PeerInfo *peer = value; | ||
1019 | int new_bucket; | ||
1020 | |||
1021 | new_bucket = lowest_bucket - 1; | ||
1022 | remove_peer(peer, lowest_bucket); | ||
1023 | GNUNET_CONTAINER_DLL_insert_after(k_buckets[new_bucket].head, | ||
1024 | k_buckets[new_bucket].tail, | ||
1025 | k_buckets[new_bucket].tail, | ||
1026 | peer); | ||
1027 | k_buckets[new_bucket].peers_size++; | ||
1028 | return GNUNET_YES; | ||
1029 | } | ||
1030 | |||
1031 | |||
904 | /** | 1032 | /** |
905 | * The current lowest bucket is full, so change the lowest | 1033 | * The current lowest bucket is full, so change the lowest |
906 | * bucket to the next lower down, and move any appropriate | 1034 | * bucket to the next lower down, and move any appropriate |
@@ -908,84 +1036,61 @@ static void delete_peer (struct PeerInfo *peer, | |||
908 | */ | 1036 | */ |
909 | static void enable_next_bucket() | 1037 | static void enable_next_bucket() |
910 | { | 1038 | { |
911 | unsigned int new_bucket; | 1039 | struct GNUNET_CONTAINER_MultiHashMap *to_remove; |
912 | unsigned int to_remove; | ||
913 | int i; | ||
914 | struct PeerInfo *to_remove_list[bucket_size]; /* We either use CPU by making a list, or memory with array. Use memory. */ | ||
915 | struct PeerInfo *pos; | 1040 | struct PeerInfo *pos; |
916 | GNUNET_assert(lowest_bucket > 0); | 1041 | GNUNET_assert(lowest_bucket > 0); |
917 | 1042 | to_remove = GNUNET_CONTAINER_multihashmap_create(bucket_size); | |
918 | pos = k_buckets[lowest_bucket].head; | 1043 | pos = k_buckets[lowest_bucket].head; |
919 | memset(to_remove_list, 0, sizeof(to_remove_list)); | 1044 | |
920 | to_remove = 0; | 1045 | #if PRINT_TABLES |
1046 | fprintf(stderr, "Printing RT before new bucket\n"); | ||
1047 | print_routing_table(); | ||
1048 | #endif | ||
921 | /* Populate the array of peers which should be in the next lowest bucket */ | 1049 | /* Populate the array of peers which should be in the next lowest bucket */ |
922 | while (pos->next != NULL) | 1050 | while (pos != NULL) |
923 | { | 1051 | { |
924 | if (find_bucket(&pos->id.hashPubKey) < lowest_bucket) | 1052 | if (find_bucket(&pos->id.hashPubKey) < lowest_bucket) |
925 | { | 1053 | GNUNET_CONTAINER_multihashmap_put(to_remove, &pos->id.hashPubKey, pos, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); |
926 | to_remove_list[to_remove] = pos; | ||
927 | to_remove++; | ||
928 | } | ||
929 | pos = pos->next; | 1054 | pos = pos->next; |
930 | } | 1055 | } |
931 | new_bucket = lowest_bucket - 1; | ||
932 | 1056 | ||
933 | /* Remove peers from lowest bucket, insert into next lowest bucket */ | 1057 | /* Remove peers from lowest bucket, insert into next lowest bucket */ |
934 | for (i = 0; i < bucket_size; i++) | 1058 | GNUNET_CONTAINER_multihashmap_iterate(to_remove, &move_lowest_bucket, NULL); |
935 | { | 1059 | lowest_bucket = lowest_bucket - 1; |
936 | if (to_remove_list[i] != NULL) | 1060 | #if PRINT_TABLES |
937 | { | 1061 | fprintf(stderr, "Printing RT after new bucket\n"); |
938 | remove_peer(to_remove_list[i], lowest_bucket); | 1062 | print_routing_table(); |
939 | GNUNET_CONTAINER_DLL_insert_after(k_buckets[new_bucket].head, | 1063 | #endif |
940 | k_buckets[new_bucket].tail, | ||
941 | k_buckets[new_bucket].tail, | ||
942 | to_remove_list[i]); | ||
943 | k_buckets[new_bucket].peers_size++; | ||
944 | } | ||
945 | else | ||
946 | break; | ||
947 | } | ||
948 | lowest_bucket = new_bucket; | ||
949 | } | 1064 | } |
1065 | |||
1066 | |||
950 | /** | 1067 | /** |
951 | * Attempt to add a peer to our k-buckets. | 1068 | * Attempt to add a peer to our k-buckets. |
952 | * | 1069 | * |
953 | * @param peer, the peer identity of the peer being added | 1070 | * @param peer, the peer identity of the peer being added |
954 | * | 1071 | * |
955 | * @return GNUNET_YES if the peer was added, | 1072 | * @return NULL if the peer was not added, |
956 | * GNUNET_NO if not, | 1073 | * pointer to PeerInfo for new peer otherwise |
957 | * GNUNET_SYSERR on err (peer is us!) | ||
958 | */ | 1074 | */ |
959 | static int try_add_peer(const struct GNUNET_PeerIdentity *peer, | 1075 | static struct PeerInfo * |
960 | unsigned int bucket, | 1076 | try_add_peer(const struct GNUNET_PeerIdentity *peer, |
961 | struct GNUNET_TIME_Relative latency, | 1077 | unsigned int bucket, |
962 | unsigned int distance) | 1078 | struct GNUNET_TIME_Relative latency, |
1079 | unsigned int distance) | ||
963 | { | 1080 | { |
964 | int peer_bucket; | 1081 | int peer_bucket; |
965 | 1082 | struct PeerInfo *new_peer; | |
966 | peer_bucket = find_current_bucket(&peer->hashPubKey); | 1083 | peer_bucket = find_current_bucket(&peer->hashPubKey); |
967 | if (peer_bucket == GNUNET_SYSERR) | 1084 | if (peer_bucket == GNUNET_SYSERR) |
968 | return GNUNET_SYSERR; | 1085 | return NULL; |
969 | 1086 | ||
970 | GNUNET_assert(peer_bucket >= lowest_bucket); | 1087 | GNUNET_assert(peer_bucket >= lowest_bucket); |
971 | if ((k_buckets[peer_bucket].peers_size) < bucket_size) | 1088 | new_peer = add_peer(peer, peer_bucket, latency, distance); |
972 | { | 1089 | |
973 | add_peer(peer, peer_bucket, latency, distance); | 1090 | if ((k_buckets[lowest_bucket].peers_size) >= bucket_size) |
974 | return GNUNET_YES; | 1091 | enable_next_bucket(); |
975 | } | 1092 | |
976 | else if ((peer_bucket == lowest_bucket) && (lowest_bucket > 0)) | 1093 | return new_peer; |
977 | { | ||
978 | enable_next_bucket(); | ||
979 | return try_add_peer(peer, bucket, latency, distance); /* Recurse, if proper bucket still full ping peers */ | ||
980 | } | ||
981 | else if ((k_buckets[peer_bucket].peers_size) == bucket_size) | ||
982 | { | ||
983 | /* TODO: implement ping_oldest_peer */ | ||
984 | //ping_oldest_peer(bucket, peer, latency, distance); /* Find oldest peer, ping it. If no response, remove and add new peer! */ | ||
985 | return GNUNET_NO; | ||
986 | } | ||
987 | GNUNET_break(0); | ||
988 | return GNUNET_NO; | ||
989 | } | 1094 | } |
990 | 1095 | ||
991 | 1096 | ||
@@ -1181,9 +1286,10 @@ static int route_result_message(void *cls, | |||
1181 | { | 1286 | { |
1182 | if (GNUNET_YES == consider_peer(&new_peer)) | 1287 | if (GNUNET_YES == consider_peer(&new_peer)) |
1183 | { | 1288 | { |
1184 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s:%s Received HELLO message for another peer, offering to transport!\n", my_short_id, "DHT"); | ||
1185 | GNUNET_TRANSPORT_offer_hello(transport_handle, hello_msg); | 1289 | GNUNET_TRANSPORT_offer_hello(transport_handle, hello_msg); |
1186 | GNUNET_CORE_peer_request_connect(sched, cfg, GNUNET_TIME_UNIT_FOREVER_REL, &new_peer, NULL, NULL); /* FIXME: Do we need this??? */ | 1290 | /* GNUNET_CORE_peer_request_connect(sched, cfg, GNUNET_TIME_UNIT_FOREVER_REL, &new_peer, NULL, NULL); */ |
1291 | /* peer_request_connect call causes service to segfault */ | ||
1292 | /* FIXME: Do we need this (peer_request_connect call)??? */ | ||
1187 | } | 1293 | } |
1188 | } | 1294 | } |
1189 | 1295 | ||
@@ -1440,7 +1546,7 @@ handle_dht_find_peer (void *cls, | |||
1440 | ntohs (find_msg->size), | 1546 | ntohs (find_msg->size), |
1441 | sizeof (struct GNUNET_MessageHeader)); | 1547 | sizeof (struct GNUNET_MessageHeader)); |
1442 | #endif | 1548 | #endif |
1443 | if ((my_hello == NULL) || (message_context->closest != GNUNET_YES)) | 1549 | if (my_hello == NULL) |
1444 | { | 1550 | { |
1445 | #if DEBUG_DHT | 1551 | #if DEBUG_DHT |
1446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1552 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1474,6 +1580,14 @@ handle_dht_find_peer (void *cls, | |||
1474 | new_msg_ctx->bloom = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | 1580 | new_msg_ctx->bloom = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); |
1475 | new_msg_ctx->hop_count = 0; | 1581 | new_msg_ctx->hop_count = 0; |
1476 | route_result_message(cls, find_peer_result, new_msg_ctx); | 1582 | route_result_message(cls, find_peer_result, new_msg_ctx); |
1583 | #if DEBUG_DHT_ROUTING | ||
1584 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
1585 | { | ||
1586 | dhtlog_handle->insert_query (NULL, message_context->unique_id, DHTLOG_FIND_PEER, | ||
1587 | message_context->hop_count, GNUNET_YES, &my_identity, | ||
1588 | message_context->key); | ||
1589 | } | ||
1590 | #endif | ||
1477 | //send_reply_to_client(message_context->client, find_peer_result, message_context->unique_id); | 1591 | //send_reply_to_client(message_context->client, find_peer_result, message_context->unique_id); |
1478 | GNUNET_free(find_peer_result); | 1592 | GNUNET_free(find_peer_result); |
1479 | } | 1593 | } |
@@ -1613,6 +1727,7 @@ find_closest_peer (const GNUNET_HashCode *hc) | |||
1613 | unsigned int lowest_distance; | 1727 | unsigned int lowest_distance; |
1614 | unsigned int temp_distance; | 1728 | unsigned int temp_distance; |
1615 | int bucket; | 1729 | int bucket; |
1730 | int count; | ||
1616 | 1731 | ||
1617 | lowest_distance = -1; | 1732 | lowest_distance = -1; |
1618 | 1733 | ||
@@ -1623,7 +1738,8 @@ find_closest_peer (const GNUNET_HashCode *hc) | |||
1623 | for (bucket = lowest_bucket; bucket < MAX_BUCKETS; bucket++) | 1738 | for (bucket = lowest_bucket; bucket < MAX_BUCKETS; bucket++) |
1624 | { | 1739 | { |
1625 | pos = k_buckets[bucket].head; | 1740 | pos = k_buckets[bucket].head; |
1626 | while (pos != NULL) | 1741 | count = 0; |
1742 | while ((pos != NULL) && (count < bucket_size)) | ||
1627 | { | 1743 | { |
1628 | temp_distance = distance(&pos->id.hashPubKey, hc); | 1744 | temp_distance = distance(&pos->id.hashPubKey, hc); |
1629 | if (temp_distance <= lowest_distance) | 1745 | if (temp_distance <= lowest_distance) |
@@ -1632,6 +1748,7 @@ find_closest_peer (const GNUNET_HashCode *hc) | |||
1632 | current_closest = pos; | 1748 | current_closest = pos; |
1633 | } | 1749 | } |
1634 | pos = pos->next; | 1750 | pos = pos->next; |
1751 | count++; | ||
1635 | } | 1752 | } |
1636 | } | 1753 | } |
1637 | GNUNET_assert(current_closest != NULL); | 1754 | GNUNET_assert(current_closest != NULL); |
@@ -1652,6 +1769,7 @@ am_closest_peer (const GNUNET_HashCode * target) | |||
1652 | int bits; | 1769 | int bits; |
1653 | int other_bits; | 1770 | int other_bits; |
1654 | int bucket_num; | 1771 | int bucket_num; |
1772 | int count; | ||
1655 | struct PeerInfo *pos; | 1773 | struct PeerInfo *pos; |
1656 | unsigned int my_distance; | 1774 | unsigned int my_distance; |
1657 | 1775 | ||
@@ -1663,13 +1781,15 @@ am_closest_peer (const GNUNET_HashCode * target) | |||
1663 | my_distance = distance(&my_identity.hashPubKey, target); | 1781 | my_distance = distance(&my_identity.hashPubKey, target); |
1664 | 1782 | ||
1665 | pos = k_buckets[bucket_num].head; | 1783 | pos = k_buckets[bucket_num].head; |
1666 | while (pos != NULL) | 1784 | count = 0; |
1785 | while ((pos != NULL) && (count < bucket_size)) | ||
1667 | { | 1786 | { |
1668 | other_bits = matching_bits(&pos->id.hashPubKey, target); | 1787 | other_bits = matching_bits(&pos->id.hashPubKey, target); |
1669 | if (other_bits > bits) | 1788 | if (other_bits > bits) |
1670 | return GNUNET_NO; | 1789 | return GNUNET_NO; |
1671 | else if (other_bits == bits) /* We match the same number of bits, do distance comparison */ | 1790 | else if (other_bits == bits) /* We match the same number of bits, do distance comparison */ |
1672 | { | 1791 | { |
1792 | /* FIXME: why not just return GNUNET_YES here? We are certainly close. */ | ||
1673 | if (distance(&pos->id.hashPubKey, target) < my_distance) | 1793 | if (distance(&pos->id.hashPubKey, target) < my_distance) |
1674 | return GNUNET_NO; | 1794 | return GNUNET_NO; |
1675 | } | 1795 | } |
@@ -1724,6 +1844,7 @@ select_peer (const GNUNET_HashCode * target, | |||
1724 | { | 1844 | { |
1725 | unsigned int distance; | 1845 | unsigned int distance; |
1726 | unsigned int bc; | 1846 | unsigned int bc; |
1847 | unsigned int count; | ||
1727 | struct PeerInfo *pos; | 1848 | struct PeerInfo *pos; |
1728 | #if USE_KADEMLIA | 1849 | #if USE_KADEMLIA |
1729 | const struct PeerInfo *chosen; | 1850 | const struct PeerInfo *chosen; |
@@ -1769,7 +1890,8 @@ select_peer (const GNUNET_HashCode * target, | |||
1769 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) | 1890 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) |
1770 | { | 1891 | { |
1771 | pos = k_buckets[bc].head; | 1892 | pos = k_buckets[bc].head; |
1772 | while (pos != NULL) | 1893 | count = 0; |
1894 | while ((pos != NULL) && (count < bucket_size)) | ||
1773 | { | 1895 | { |
1774 | if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) | 1896 | if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) |
1775 | total_distance += (unsigned long long)inverse_distance (target, &pos->id.hashPubKey); | 1897 | total_distance += (unsigned long long)inverse_distance (target, &pos->id.hashPubKey); |
@@ -1779,6 +1901,7 @@ select_peer (const GNUNET_HashCode * target, | |||
1779 | my_short_id, "DHT", total_distance, GNUNET_i2s(&pos->id), GNUNET_h2s(target) , inverse_distance(target, &pos->id.hashPubKey)); | 1901 | my_short_id, "DHT", total_distance, GNUNET_i2s(&pos->id), GNUNET_h2s(target) , inverse_distance(target, &pos->id.hashPubKey)); |
1780 | #endif | 1902 | #endif |
1781 | pos = pos->next; | 1903 | pos = pos->next; |
1904 | count++; | ||
1782 | } | 1905 | } |
1783 | } | 1906 | } |
1784 | if (total_distance == 0) | 1907 | if (total_distance == 0) |
@@ -1790,7 +1913,8 @@ select_peer (const GNUNET_HashCode * target, | |||
1790 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) | 1913 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) |
1791 | { | 1914 | { |
1792 | pos = k_buckets[bc].head; | 1915 | pos = k_buckets[bc].head; |
1793 | while (pos != NULL) | 1916 | count = 0; |
1917 | while ((pos != NULL) && (count < bucket_size)) | ||
1794 | { | 1918 | { |
1795 | if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) | 1919 | if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) |
1796 | { | 1920 | { |
@@ -1808,6 +1932,7 @@ select_peer (const GNUNET_HashCode * target, | |||
1808 | #endif | 1932 | #endif |
1809 | } | 1933 | } |
1810 | pos = pos->next; | 1934 | pos = pos->next; |
1935 | count++; | ||
1811 | } | 1936 | } |
1812 | } | 1937 | } |
1813 | #if DEBUG_DHT | 1938 | #if DEBUG_DHT |
@@ -2023,7 +2148,7 @@ static int route_message(void *cls, | |||
2023 | if ((handle_dht_get (cls, msg, message_context) > 0) && (stop_on_found == GNUNET_YES)) | 2148 | if ((handle_dht_get (cls, msg, message_context) > 0) && (stop_on_found == GNUNET_YES)) |
2024 | forward_count = 0; | 2149 | forward_count = 0; |
2025 | break; | 2150 | break; |
2026 | case GNUNET_MESSAGE_TYPE_DHT_PUT: /* Check if closest, if so insert data. FIXME: thresholding?*/ | 2151 | case GNUNET_MESSAGE_TYPE_DHT_PUT: /* Check if closest, if so insert data. FIXME: thresholding to reduce complexity?*/ |
2027 | if (message_context->closest == GNUNET_YES) | 2152 | if (message_context->closest == GNUNET_YES) |
2028 | { | 2153 | { |
2029 | #if DEBUG_DHT_ROUTING | 2154 | #if DEBUG_DHT_ROUTING |
@@ -2050,12 +2175,24 @@ static int route_message(void *cls, | |||
2050 | #endif | 2175 | #endif |
2051 | break; | 2176 | break; |
2052 | case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER: /* Check if closest and not started by us, check options, add to requests seen */ | 2177 | case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER: /* Check if closest and not started by us, check options, add to requests seen */ |
2053 | if (0 != memcmp(message_context->peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))) | 2178 | if (((message_context->hop_count > 0) && (0 != memcmp(message_context->peer, &my_identity, sizeof(struct GNUNET_PeerIdentity)))) || (message_context->client != NULL)) |
2054 | { | 2179 | { |
2055 | cache_response (cls, message_context); | 2180 | cache_response (cls, message_context); |
2056 | if ((message_context->closest == GNUNET_YES) || (message_context->msg_options == GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) | 2181 | if ((message_context->closest == GNUNET_YES) || (message_context->msg_options == GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) |
2057 | handle_dht_find_peer (cls, msg, message_context); | 2182 | handle_dht_find_peer (cls, msg, message_context); |
2058 | } | 2183 | } |
2184 | #if DEBUG_DHT_ROUTING | ||
2185 | if (message_context->hop_count == 0) /* Locally initiated request */ | ||
2186 | { | ||
2187 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2188 | { | ||
2189 | dhtlog_handle->insert_dhtkey(NULL, message_context->key); | ||
2190 | dhtlog_handle->insert_query (NULL, message_context->unique_id, DHTLOG_FIND_PEER, | ||
2191 | message_context->hop_count, GNUNET_NO, &my_identity, | ||
2192 | message_context->key); | ||
2193 | } | ||
2194 | } | ||
2195 | #endif | ||
2059 | break; | 2196 | break; |
2060 | default: | 2197 | default: |
2061 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 2198 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
@@ -2065,7 +2202,7 @@ static int route_message(void *cls, | |||
2065 | for (i = 0; i < forward_count; i++) | 2202 | for (i = 0; i < forward_count; i++) |
2066 | { | 2203 | { |
2067 | selected = select_peer(message_context->key, message_context->bloom); | 2204 | selected = select_peer(message_context->key, message_context->bloom); |
2068 | 2205 | /* FIXME: either log to sql or log to stats or both when selected is NULL at this point! */ | |
2069 | if (selected != NULL) | 2206 | if (selected != NULL) |
2070 | { | 2207 | { |
2071 | GNUNET_CONTAINER_bloomfilter_add(message_context->bloom, &selected->id.hashPubKey); | 2208 | GNUNET_CONTAINER_bloomfilter_add(message_context->bloom, &selected->id.hashPubKey); |
@@ -2160,7 +2297,7 @@ send_find_peer_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc | |||
2160 | find_peer_msg->type = htons(GNUNET_MESSAGE_TYPE_DHT_FIND_PEER); | 2297 | find_peer_msg->type = htons(GNUNET_MESSAGE_TYPE_DHT_FIND_PEER); |
2161 | memset(&message_context, 0, sizeof(struct DHT_MessageContext)); | 2298 | memset(&message_context, 0, sizeof(struct DHT_MessageContext)); |
2162 | message_context.key = &my_identity.hashPubKey; | 2299 | message_context.key = &my_identity.hashPubKey; |
2163 | message_context.unique_id = GNUNET_ntohll (GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK, (uint64_t)-1)); | 2300 | message_context.unique_id = GNUNET_ntohll (GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG, (uint64_t)-1)); |
2164 | message_context.replication = ntohl (DHT_DEFAULT_FIND_PEER_REPLICATION); | 2301 | message_context.replication = ntohl (DHT_DEFAULT_FIND_PEER_REPLICATION); |
2165 | message_context.msg_options = ntohl (DHT_DEFAULT_FIND_PEER_OPTIONS); | 2302 | message_context.msg_options = ntohl (DHT_DEFAULT_FIND_PEER_OPTIONS); |
2166 | message_context.network_size = estimate_diameter(); | 2303 | message_context.network_size = estimate_diameter(); |
@@ -2488,7 +2625,7 @@ void handle_core_connect (void *cls, | |||
2488 | struct GNUNET_TIME_Relative latency, | 2625 | struct GNUNET_TIME_Relative latency, |
2489 | uint32_t distance) | 2626 | uint32_t distance) |
2490 | { | 2627 | { |
2491 | int ret; | 2628 | struct PeerInfo *ret; |
2492 | 2629 | ||
2493 | #if DEBUG_DHT | 2630 | #if DEBUG_DHT |
2494 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2631 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -2500,13 +2637,37 @@ void handle_core_connect (void *cls, | |||
2500 | find_current_bucket(&peer->hashPubKey), | 2637 | find_current_bucket(&peer->hashPubKey), |
2501 | latency, | 2638 | latency, |
2502 | distance); | 2639 | distance); |
2640 | if (ret != NULL) | ||
2641 | GNUNET_CONTAINER_multihashmap_put(all_known_peers, &peer->hashPubKey, ret, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
2503 | #if DEBUG_DHT | 2642 | #if DEBUG_DHT |
2504 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2643 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
2505 | "%s:%s Adding peer to routing list: %s\n", my_short_id, "DHT", ret == GNUNET_YES ? "PEER ADDED" : "NOT ADDED"); | 2644 | "%s:%s Adding peer to routing list: %s\n", my_short_id, "DHT", ret == NULL ? "NOT ADDED" : "PEER ADDED"); |
2506 | #endif | 2645 | #endif |
2507 | } | 2646 | } |
2508 | 2647 | ||
2509 | /** | 2648 | /** |
2649 | * Method called whenever a peer disconnects. | ||
2650 | * | ||
2651 | * @param cls closure | ||
2652 | * @param peer peer identity this notification is about | ||
2653 | */ | ||
2654 | void handle_core_disconnect (void *cls, | ||
2655 | const struct | ||
2656 | GNUNET_PeerIdentity * peer) | ||
2657 | { | ||
2658 | struct PeerInfo *to_remove; | ||
2659 | int current_bucket; | ||
2660 | |||
2661 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s:%s: Received peer disconnect message for peer `%s' from %s\n", my_short_id, "DHT", GNUNET_i2s(peer), "CORE"); | ||
2662 | |||
2663 | GNUNET_assert(GNUNET_CONTAINER_multihashmap_contains(all_known_peers, &peer->hashPubKey)); | ||
2664 | to_remove = GNUNET_CONTAINER_multihashmap_get(all_known_peers, &peer->hashPubKey); | ||
2665 | GNUNET_assert(0 == memcmp(peer, &to_remove->id, sizeof(struct GNUNET_PeerIdentity))); | ||
2666 | current_bucket = find_current_bucket(&to_remove->id.hashPubKey); | ||
2667 | delete_peer(to_remove, current_bucket); | ||
2668 | } | ||
2669 | |||
2670 | /** | ||
2510 | * Process dht requests. | 2671 | * Process dht requests. |
2511 | * | 2672 | * |
2512 | * @param cls closure | 2673 | * @param cls closure |
@@ -2529,8 +2690,8 @@ run (void *cls, | |||
2529 | GNUNET_TIME_UNIT_FOREVER_REL, | 2690 | GNUNET_TIME_UNIT_FOREVER_REL, |
2530 | NULL, /* Closure passed to DHT functionas around? */ | 2691 | NULL, /* Closure passed to DHT functionas around? */ |
2531 | &core_init, /* Call core_init once connected */ | 2692 | &core_init, /* Call core_init once connected */ |
2532 | &handle_core_connect, /* Don't care about connects */ | 2693 | &handle_core_connect, /* Handle connects */ |
2533 | NULL, /* FIXME: remove peers on disconnects */ | 2694 | &handle_core_disconnect, /* FIXME: remove peers on disconnects */ |
2534 | NULL, /* Do we care about "status" updates? */ | 2695 | NULL, /* Do we care about "status" updates? */ |
2535 | NULL, /* Don't want notified about all incoming messages */ | 2696 | NULL, /* Don't want notified about all incoming messages */ |
2536 | GNUNET_NO, /* For header only inbound notification */ | 2697 | GNUNET_NO, /* For header only inbound notification */ |
@@ -2550,8 +2711,8 @@ run (void *cls, | |||
2550 | lowest_bucket = MAX_BUCKETS - 1; | 2711 | lowest_bucket = MAX_BUCKETS - 1; |
2551 | forward_list.hashmap = GNUNET_CONTAINER_multihashmap_create(MAX_OUTSTANDING_FORWARDS / 10); | 2712 | forward_list.hashmap = GNUNET_CONTAINER_multihashmap_create(MAX_OUTSTANDING_FORWARDS / 10); |
2552 | forward_list.minHeap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN); | 2713 | forward_list.minHeap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN); |
2553 | /* Scheduled the task to clean up when shutdown is called */ | 2714 | all_known_peers = GNUNET_CONTAINER_multihashmap_create(MAX_BUCKETS / 8); |
2554 | 2715 | GNUNET_assert(all_known_peers != NULL); | |
2555 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging")) | 2716 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging")) |
2556 | { | 2717 | { |
2557 | debug_routes = GNUNET_YES; | 2718 | debug_routes = GNUNET_YES; |
@@ -2589,10 +2750,13 @@ run (void *cls, | |||
2589 | } | 2750 | } |
2590 | } | 2751 | } |
2591 | 2752 | ||
2753 | #if DO_FIND_PEER | ||
2592 | GNUNET_SCHEDULER_add_delayed (sched, | 2754 | GNUNET_SCHEDULER_add_delayed (sched, |
2593 | GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30), | 2755 | GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30), |
2594 | &send_find_peer_message, NULL); | 2756 | &send_find_peer_message, NULL); |
2757 | #endif | ||
2595 | 2758 | ||
2759 | /* Scheduled the task to clean up when shutdown is called */ | ||
2596 | cleanup_task = GNUNET_SCHEDULER_add_delayed (sched, | 2760 | cleanup_task = GNUNET_SCHEDULER_add_delayed (sched, |
2597 | GNUNET_TIME_UNIT_FOREVER_REL, | 2761 | GNUNET_TIME_UNIT_FOREVER_REL, |
2598 | &shutdown_task, NULL); | 2762 | &shutdown_task, NULL); |