2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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
29 #include "gnunet_block_lib.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_nse_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_datacache_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_hello_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_statistics_service.h"
43 * How many buckets will we allow total.
45 #define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8
48 * What is the maximum number of peers in a given bucket.
50 #define DEFAULT_BUCKET_SIZE 4
54 * Linked list of messages to send to a particular other peer.
56 struct P2PPendingMessage
59 * Pointer to next item in the list
61 struct P2PPendingMessage *next;
64 * Pointer to previous item in the list
66 struct P2PPendingMessage *prev;
69 * Message importance level.
71 unsigned int importance;
74 * Time when this request was scheduled to be sent.
76 struct GNUNET_TIME_Absolute scheduled;
79 * How long to wait before sending message.
81 struct GNUNET_TIME_Relative timeout;
84 * Actual message to be sent, allocated at the end of the struct:
85 * // msg = (cast) &pm[1];
86 * // memcpy (&pm[1], data, len);
88 const struct GNUNET_MessageHeader *msg;
94 * Entry for a peer in a bucket.
99 * Next peer entry (DLL)
101 struct PeerInfo *next;
104 * Prev peer entry (DLL)
106 struct PeerInfo *prev;
109 * Count of outstanding messages for peer.
111 unsigned int pending_count;
114 * Head of pending messages to be sent to this peer.
116 struct P2PPendingMessage *head;
119 * Tail of pending messages to be sent to this peer.
121 struct P2PPendingMessage *tail;
124 * Core handle for sending messages to this peer.
126 struct GNUNET_CORE_TransmitHandle *th;
129 * Preference update context
131 struct GNUNET_CORE_InformationRequestContext *info_ctx;
134 * Task for scheduling message sends.
136 GNUNET_SCHEDULER_TaskIdentifier send_task;
139 * Task for scheduling preference updates
141 GNUNET_SCHEDULER_TaskIdentifier preference_task;
144 * What is the identity of the peer?
146 struct GNUNET_PeerIdentity id;
150 * What is the average latency for replies received?
152 struct GNUNET_TIME_Relative latency;
155 * Transport level distance to peer.
157 unsigned int distance;
164 * Peers are grouped into buckets.
171 struct PeerInfo *head;
176 struct PeerInfo *tail;
179 * Number of peers in the bucket.
181 unsigned int peers_size;
186 * The lowest currently used bucket.
188 static unsigned int lowest_bucket; /* Initially equal to MAX_BUCKETS - 1 */
191 * The buckets (Kademlia routing table, complete with growth).
192 * Array of size MAX_BUCKET_SIZE.
194 static struct PeerBucket k_buckets[MAX_BUCKETS];
197 * Hash map of all known peers, for easy removal from k_buckets on disconnect.
199 static struct GNUNET_CONTAINER_MultiHashMap *all_known_peers;
202 * Maximum size for each bucket.
204 static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
209 * Method called whenever a peer connects.
212 * @param peer peer identity this notification is about
213 * @param atsi performance data
216 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
217 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
219 struct PeerInfo *ret;
222 /* Check for connect to self message */
223 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228 "%s:%s Receives core connect message for peer %s distance %d!\n",
229 my_short_id, "dht", GNUNET_i2s (peer), distance);
233 GNUNET_CONTAINER_multihashmap_contains (all_known_peers,
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238 "%s:%s Received %s message for peer %s, but already have peer in RT!",
239 my_short_id, "DHT", "CORE CONNECT", GNUNET_i2s (peer));
245 peer_bucket = find_current_bucket (&peer->hashPubKey);
246 GNUNET_assert (peer_bucket >= lowest_bucket);
247 GNUNET_assert (peer_bucket < MAX_BUCKETS);
248 ret = GNUNET_malloc (sizeof (struct PeerInfo));
250 ret->latency = latency;
251 ret->distance = distance;
254 GNUNET_CONTAINER_DLL_insert_after (k_buckets[peer_bucket].head,
255 k_buckets[peer_bucket].tail,
256 k_buckets[peer_bucket].tail, ret);
257 k_buckets[peer_bucket].peers_size++;
258 if ((GNUNET_CRYPTO_hash_matching_bits
259 (&my_identity.hashPubKey, &peer->hashPubKey) > 0) &&
260 (k_buckets[peer_bucket].peers_size <= bucket_size))
261 ret->preference_task =
262 GNUNET_SCHEDULER_add_now (&update_core_preference, ret);
263 if ((k_buckets[lowest_bucket].peers_size) >= bucket_size)
264 enable_next_bucket ();
266 GNUNET_CONTAINER_multihashmap_put (all_known_peers, &peer->hashPubKey, ret,
267 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
268 increment_stats (STAT_PEERS_KNOWN);
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "%s:%s Adding peer to routing list: %s\n", my_short_id, "DHT",
273 ret == NULL ? "NOT ADDED" : "PEER ADDED");
279 * Method called whenever a peer disconnects.
282 * @param peer peer identity this notification is about
285 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
287 struct PeerInfo *to_remove;
290 /* Check for disconnect from self message */
291 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "%s:%s: Received peer disconnect message for peer `%s' from %s\n",
296 my_short_id, "DHT", GNUNET_i2s (peer), "CORE");
300 GNUNET_CONTAINER_multihashmap_contains (all_known_peers,
305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
306 "%s:%s: do not have peer `%s' in RT, can't disconnect!\n",
307 my_short_id, "DHT", GNUNET_i2s (peer));
311 increment_stats (STAT_DISCONNECTS);
312 GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains
313 (all_known_peers, &peer->hashPubKey));
315 GNUNET_CONTAINER_multihashmap_get (all_known_peers, &peer->hashPubKey);
316 GNUNET_assert (to_remove != NULL);
317 if (NULL != to_remove->info_ctx)
319 GNUNET_CORE_peer_change_preference_cancel (to_remove->info_ctx);
320 to_remove->info_ctx = NULL;
323 memcmp (peer, &to_remove->id,
324 sizeof (struct GNUNET_PeerIdentity)));
325 current_bucket = find_current_bucket (&to_remove->id.hashPubKey);
326 delete_peer (to_remove, current_bucket);
332 * Initialize neighbours subsystem.
335 GST_NEIGHBOURS_init ()
341 * Shutdown neighbours subsystem.
344 GST_NEIGHBOURS_done ()
353 /* end of gnunet-service-dht_neighbours.c */