diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-01-18 13:57:58 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-01-18 13:57:58 +0000 |
commit | c914e078ab8e9dc2b65f2bc02ce260b9d1d209de (patch) | |
tree | 7ee8cd9ad2b4302a0f5166f3ca05c6407fe3b6fe /src/topology/gnunet-daemon-topology.c | |
parent | 7a65c4fb6e8d2f0fd85fe8e951214c39882193e7 (diff) | |
download | gnunet-c914e078ab8e9dc2b65f2bc02ce260b9d1d209de.tar.gz gnunet-c914e078ab8e9dc2b65f2bc02ce260b9d1d209de.zip |
cleaning up topology code:
Diffstat (limited to 'src/topology/gnunet-daemon-topology.c')
-rw-r--r-- | src/topology/gnunet-daemon-topology.c | 1041 |
1 files changed, 491 insertions, 550 deletions
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c index 16707777d..5c581fd42 100644 --- a/src/topology/gnunet-daemon-topology.c +++ b/src/topology/gnunet-daemon-topology.c | |||
@@ -22,6 +22,20 @@ | |||
22 | * @file topology/gnunet-daemon-topology.c | 22 | * @file topology/gnunet-daemon-topology.c |
23 | * @brief code for maintaining the mesh topology | 23 | * @brief code for maintaining the mesh topology |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * | ||
26 | * TODO: | ||
27 | * - make sure that PEERINFO *also* notifies us when a HELLO expires | ||
28 | * (otherwise the 'soft state' of this module does not work nicely) | ||
29 | * - CORE API's connect/disconnect API is not nice (we think we are | ||
30 | * connected when we are not; disconnect using bandwidth-limiting | ||
31 | * does not really work and is not nice) | ||
32 | * OPTIMIZATIONS: | ||
33 | * - move code to use hash table instead of linked list | ||
34 | * - instead of periodically discarding blacklisted entries, | ||
35 | * simply add task that is triggered at the right time (earlier free, | ||
36 | * more balanced load) | ||
37 | * - check if new HELLO learned is different from old HELLO | ||
38 | * before resetting entire state! | ||
25 | */ | 39 | */ |
26 | 40 | ||
27 | #include <stdlib.h> | 41 | #include <stdlib.h> |
@@ -36,29 +50,26 @@ | |||
36 | #define DEBUG_TOPOLOGY GNUNET_NO | 50 | #define DEBUG_TOPOLOGY GNUNET_NO |
37 | 51 | ||
38 | /** | 52 | /** |
39 | * For how long do we blacklist a peer after a failed | 53 | * For how long do we blacklist a peer after a failed connection |
40 | * connection attempt? | 54 | * attempt? |
41 | */ | 55 | */ |
42 | #define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS | 56 | #define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS |
43 | 57 | ||
44 | /** | 58 | /** |
45 | * For how long do we blacklist a friend after a failed | 59 | * For how long do we blacklist a friend after a failed connection |
46 | * connection attempt? | 60 | * attempt? |
47 | */ | 61 | */ |
48 | #define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | 62 | #define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) |
49 | 63 | ||
50 | /** | 64 | /** |
51 | * How frequently are we allowed to ask PEERINFO for more | 65 | * How often do we at most advertise any HELLO to a peer? |
52 | * HELLO's to advertise (at most)? | ||
53 | */ | 66 | */ |
54 | #define MIN_HELLO_GATHER_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 27) | 67 | #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) |
55 | 68 | ||
56 | /** | 69 | /** |
57 | * How often do we at most advertise the same HELLO to the same peer? | 70 | * How often do we at most advertise the same HELLO to the same peer? |
58 | * Also used to remove HELLOs of peers that PEERINFO no longer lists | ||
59 | * from our cache. | ||
60 | */ | 71 | */ |
61 | #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) | 72 | #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) |
62 | 73 | ||
63 | 74 | ||
64 | /** | 75 | /** |
@@ -73,68 +84,65 @@ struct PeerList | |||
73 | struct PeerList *next; | 84 | struct PeerList *next; |
74 | 85 | ||
75 | /** | 86 | /** |
76 | * Is this peer listed here because he is a friend? | 87 | * Our handle for the request to transmit HELLOs to this peer; NULL |
88 | * if no such request is pending. | ||
77 | */ | 89 | */ |
78 | int is_friend; | 90 | struct GNUNET_CORE_TransmitHandle *hello_req; |
79 | 91 | ||
80 | /** | 92 | /** |
81 | * Are we connected to this peer right now? | 93 | * Our handle for the request to connect to this peer; NULL if no |
94 | * such request is pending. | ||
82 | */ | 95 | */ |
83 | int is_connected; | 96 | struct GNUNET_CORE_TransmitHandle *connect_req; |
84 | 97 | ||
85 | /** | 98 | /** |
86 | * Until what time should we not try to connect again | 99 | * Pointer to the HELLO message of this peer; can be NULL. |
87 | * to this peer? | ||
88 | */ | 100 | */ |
89 | struct GNUNET_TIME_Absolute blacklisted_until; | 101 | struct GNUNET_HELLO_Message *hello; |
90 | 102 | ||
91 | /** | 103 | /** |
92 | * Last time we transmitted a HELLO to this peer? | 104 | * Bloom filter used to mark which peers already got the HELLO |
105 | * from this peer. | ||
93 | */ | 106 | */ |
94 | struct GNUNET_TIME_Absolute last_hello_sent; | 107 | struct GNUNET_CONTAINER_BloomFilter *filter; |
95 | 108 | ||
96 | /** | 109 | /** |
97 | * ID of the peer. | 110 | * Is this peer listed here because he is a friend? |
98 | */ | 111 | */ |
99 | struct GNUNET_PeerIdentity id; | 112 | int is_friend; |
100 | |||
101 | }; | ||
102 | 113 | ||
114 | /** | ||
115 | * Are we connected to this peer right now? | ||
116 | */ | ||
117 | int is_connected; | ||
103 | 118 | ||
104 | /** | ||
105 | * List of HELLOs we may consider for advertising. | ||
106 | */ | ||
107 | struct HelloList | ||
108 | { | ||
109 | /** | 119 | /** |
110 | * This is a linked list. | 120 | * Until what time should we not try to connect again |
121 | * to this peer? | ||
111 | */ | 122 | */ |
112 | struct HelloList *next; | 123 | struct GNUNET_TIME_Absolute blacklisted_until; |
113 | 124 | ||
114 | /** | 125 | /** |
115 | * Pointer to the HELLO message. Memory allocated as part | 126 | * Next time we are allowed to transmit a HELLO to this peer? |
116 | * of the "struct HelloList" --- do not free! | ||
117 | */ | 127 | */ |
118 | struct GNUNET_HELLO_Message *msg; | 128 | struct GNUNET_TIME_Absolute next_hello_allowed; |
119 | 129 | ||
120 | /** | 130 | /** |
121 | * Bloom filter used to mark which peers already got | 131 | * When should we reset the bloom filter of this entry? |
122 | * this HELLO. | ||
123 | */ | 132 | */ |
124 | struct GNUNET_CONTAINER_BloomFilter *filter; | 133 | struct GNUNET_TIME_Absolute filter_expiration; |
125 | 134 | ||
126 | /** | 135 | /** |
127 | * What peer is this HELLO for? | 136 | * ID of task we use to wait for the time to send the next HELLO |
137 | * to this peer. | ||
128 | */ | 138 | */ |
129 | struct GNUNET_PeerIdentity id; | 139 | GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; |
130 | 140 | ||
131 | /** | 141 | /** |
132 | * When should we remove this entry from the linked list (either | 142 | * ID of the peer. |
133 | * resetting the filter or possibly eliminating it for good because | ||
134 | * we no longer consider the peer to be participating in the | ||
135 | * network)? | ||
136 | */ | 143 | */ |
137 | struct GNUNET_TIME_Absolute expiration; | 144 | struct GNUNET_PeerIdentity id; |
145 | |||
138 | }; | 146 | }; |
139 | 147 | ||
140 | 148 | ||
@@ -166,29 +174,21 @@ struct DisconnectList | |||
166 | }; | 174 | }; |
167 | 175 | ||
168 | 176 | ||
169 | |||
170 | /** | 177 | /** |
171 | * Our peerinfo notification context. We use notification | 178 | * Our peerinfo notification context. We use notification |
172 | * to instantly learn about new peers as they are discovered | 179 | * to instantly learn about new peers as they are discovered. |
173 | * as well as periodic iteration to try peers again after | ||
174 | * a while. | ||
175 | */ | 180 | */ |
176 | static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify; | 181 | static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify; |
177 | 182 | ||
178 | /** | 183 | /** |
179 | * Linked list of HELLOs for advertising. | ||
180 | */ | ||
181 | static struct HelloList *hellos; | ||
182 | |||
183 | /** | ||
184 | * Our scheduler. | 184 | * Our scheduler. |
185 | */ | 185 | */ |
186 | static struct GNUNET_SCHEDULER_Handle * sched; | 186 | static struct GNUNET_SCHEDULER_Handle *sched; |
187 | 187 | ||
188 | /** | 188 | /** |
189 | * Our configuration. | 189 | * Our configuration. |
190 | */ | 190 | */ |
191 | static const struct GNUNET_CONFIGURATION_Handle * cfg; | 191 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
192 | 192 | ||
193 | /** | 193 | /** |
194 | * Handle to the core API. | 194 | * Handle to the core API. |
@@ -206,15 +206,10 @@ static struct GNUNET_TRANSPORT_Handle *transport; | |||
206 | static struct GNUNET_PeerIdentity my_identity; | 206 | static struct GNUNET_PeerIdentity my_identity; |
207 | 207 | ||
208 | /** | 208 | /** |
209 | * Linked list of all of our friends and all of our current | 209 | * Linked list of all of our friends, all of our current neighbours |
210 | * neighbours. | 210 | * and all peers for which we have HELLOs. So pretty much everyone. |
211 | */ | ||
212 | static struct PeerList *friends; | ||
213 | |||
214 | /** | ||
215 | * Timestamp from the last time we tried to gather HELLOs. | ||
216 | */ | 211 | */ |
217 | static struct GNUNET_TIME_Absolute last_hello_gather_time; | 212 | static struct PeerList *peers; |
218 | 213 | ||
219 | /** | 214 | /** |
220 | * Flag to disallow non-friend connections (pure F2F mode). | 215 | * Flag to disallow non-friend connections (pure F2F mode). |
@@ -248,18 +243,6 @@ static unsigned int friend_count; | |||
248 | static int autoconnect; | 243 | static int autoconnect; |
249 | 244 | ||
250 | /** | 245 | /** |
251 | * Non-NULL if we are currently having a request pending with | ||
252 | * PEERINFO asking for HELLOs for advertising? | ||
253 | */ | ||
254 | static struct GNUNET_PEERINFO_IteratorContext *pitr; | ||
255 | |||
256 | /** | ||
257 | * Non-NULL if we are currently having a request pending with | ||
258 | * PEERINFO looking for more peers to connect to. | ||
259 | */ | ||
260 | static struct GNUNET_PEERINFO_IteratorContext *pitr_more; | ||
261 | |||
262 | /** | ||
263 | * Head of doubly-linked list of active 'disconnect' requests that we have issued. | 246 | * Head of doubly-linked list of active 'disconnect' requests that we have issued. |
264 | */ | 247 | */ |
265 | static struct DisconnectList *disconnect_head; | 248 | static struct DisconnectList *disconnect_head; |
@@ -303,7 +286,10 @@ disconnect_done (void *cls, | |||
303 | 286 | ||
304 | 287 | ||
305 | /** | 288 | /** |
306 | * Force a disconnect from the specified peer. | 289 | * Force a disconnect from the specified peer. This is currently done by |
290 | * changing the bandwidth policy to 0 bytes per second. | ||
291 | * FIXME: maybe we want a nicer CORE API for both connect and disconnect... | ||
292 | * FIXME: this policy change is never undone; how do we reconnect ever? | ||
307 | */ | 293 | */ |
308 | static void | 294 | static void |
309 | force_disconnect (const struct GNUNET_PeerIdentity *peer) | 295 | force_disconnect (const struct GNUNET_PeerIdentity *peer) |
@@ -327,14 +313,18 @@ force_disconnect (const struct GNUNET_PeerIdentity *peer) | |||
327 | 313 | ||
328 | 314 | ||
329 | /** | 315 | /** |
330 | * Function called by core when our attempt to connect | 316 | * Function called by core when our attempt to connect succeeded. |
331 | * succeeded. Does nothing. | 317 | * Transmits a 'DUMMY' message to trigger the session key exchange. |
318 | * FIXME: this is an issue with the current CORE API. | ||
332 | */ | 319 | */ |
333 | static size_t | 320 | static size_t |
334 | ready_callback (void *cls, | 321 | ready_callback (void *cls, |
335 | size_t size, void *buf) | 322 | size_t size, void *buf) |
336 | { | 323 | { |
324 | struct PeerList *pos = cls; | ||
337 | struct GNUNET_MessageHeader hdr; | 325 | struct GNUNET_MessageHeader hdr; |
326 | |||
327 | pos->connect_req = NULL; | ||
338 | if (buf == NULL) | 328 | if (buf == NULL) |
339 | { | 329 | { |
340 | #if DEBUG_TOPOLOGY | 330 | #if DEBUG_TOPOLOGY |
@@ -361,26 +351,8 @@ ready_callback (void *cls, | |||
361 | * @param pos entry in our friend list; NULL if not in friend list yet | 351 | * @param pos entry in our friend list; NULL if not in friend list yet |
362 | */ | 352 | */ |
363 | static void | 353 | static void |
364 | attempt_connect (const struct GNUNET_PeerIdentity *peer, | 354 | attempt_connect (struct PeerList *pos) |
365 | struct PeerList *pos) | ||
366 | { | 355 | { |
367 | if (pos == NULL) | ||
368 | { | ||
369 | pos = friends; | ||
370 | while (pos != NULL) | ||
371 | { | ||
372 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
373 | break; | ||
374 | pos = pos->next; | ||
375 | } | ||
376 | } | ||
377 | if (pos == NULL) | ||
378 | { | ||
379 | pos = GNUNET_malloc (sizeof(struct PeerList)); | ||
380 | pos->id = *peer; | ||
381 | pos->next = friends; | ||
382 | friends = pos; | ||
383 | } | ||
384 | if (GNUNET_YES == pos->is_friend) | 356 | if (GNUNET_YES == pos->is_friend) |
385 | pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND); | 357 | pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND); |
386 | else | 358 | else |
@@ -388,42 +360,35 @@ attempt_connect (const struct GNUNET_PeerIdentity *peer, | |||
388 | #if DEBUG_TOPOLOGY | 360 | #if DEBUG_TOPOLOGY |
389 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 361 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
390 | "Asking core to connect to `%s'\n", | 362 | "Asking core to connect to `%s'\n", |
391 | GNUNET_i2s (peer)); | 363 | GNUNET_i2s (&pos->id)); |
392 | #endif | 364 | #endif |
393 | GNUNET_CORE_notify_transmit_ready (handle, | 365 | pos->connect_req = GNUNET_CORE_notify_transmit_ready (handle, |
394 | 0 /* priority */, | 366 | 0 /* priority */, |
395 | GNUNET_TIME_UNIT_MINUTES, | 367 | GNUNET_TIME_UNIT_MINUTES, |
396 | peer, | 368 | &pos->id, |
397 | sizeof(struct GNUNET_MessageHeader), | 369 | sizeof(struct GNUNET_MessageHeader), |
398 | &ready_callback, | 370 | &ready_callback, |
399 | NULL); | 371 | pos); |
400 | } | 372 | } |
401 | 373 | ||
402 | 374 | ||
403 | /** | 375 | /** |
404 | * Is this peer one of our friends? | 376 | * Find a peer in our linked list. |
377 | * FIXME: should probably use a hash map instead. | ||
405 | */ | 378 | */ |
406 | static int | 379 | struct PeerList * |
407 | is_friend (const struct GNUNET_PeerIdentity * peer) | 380 | find_peer (const struct GNUNET_PeerIdentity * peer) |
408 | { | 381 | { |
409 | struct PeerList *pos; | 382 | struct PeerList *pos; |
410 | 383 | ||
411 | pos = friends; | 384 | pos = peers; |
412 | while (pos != NULL) | 385 | while (pos != NULL) |
413 | { | 386 | { |
414 | if ( (GNUNET_YES == pos->is_friend) && | 387 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) |
415 | (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) ) | 388 | return pos; |
416 | { | ||
417 | #if DEBUG_TOPOLOGY | ||
418 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
419 | "Determined that `%s' is a friend\n", | ||
420 | GNUNET_i2s (peer)); | ||
421 | #endif | ||
422 | return GNUNET_YES; | ||
423 | } | ||
424 | pos = pos->next; | 389 | pos = pos->next; |
425 | } | 390 | } |
426 | return GNUNET_NO; | 391 | return NULL; |
427 | } | 392 | } |
428 | 393 | ||
429 | 394 | ||
@@ -431,18 +396,18 @@ is_friend (const struct GNUNET_PeerIdentity * peer) | |||
431 | * Check if an additional connection from the given peer is allowed. | 396 | * Check if an additional connection from the given peer is allowed. |
432 | */ | 397 | */ |
433 | static int | 398 | static int |
434 | is_connection_allowed (const struct GNUNET_PeerIdentity * peer) | 399 | is_connection_allowed (struct PeerList *peer) |
435 | { | 400 | { |
436 | if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) | 401 | if (0 == memcmp (&my_identity, &peer->id, sizeof (struct GNUNET_PeerIdentity))) |
437 | return GNUNET_SYSERR; /* disallow connections to self */ | 402 | return GNUNET_SYSERR; /* disallow connections to self */ |
438 | if (is_friend (peer)) | 403 | if (peer->is_friend) |
439 | return GNUNET_OK; | 404 | return GNUNET_OK; |
440 | if (GNUNET_YES == friends_only) | 405 | if (GNUNET_YES == friends_only) |
441 | { | 406 | { |
442 | #if DEBUG_TOPOLOGY | 407 | #if DEBUG_TOPOLOGY |
443 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 408 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
444 | "Determined that `%s' is not allowed to connect (not a friend)\n", | 409 | "Determined that `%s' is not allowed to connect (not a friend)\n", |
445 | GNUNET_i2s (peer)); | 410 | GNUNET_i2s (&peer->id)); |
446 | #endif | 411 | #endif |
447 | return GNUNET_SYSERR; | 412 | return GNUNET_SYSERR; |
448 | } | 413 | } |
@@ -451,21 +416,220 @@ is_connection_allowed (const struct GNUNET_PeerIdentity * peer) | |||
451 | #if DEBUG_TOPOLOGY | 416 | #if DEBUG_TOPOLOGY |
452 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 417 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
453 | "Determined that `%s' is not allowed to connect (not enough connected friends)\n", | 418 | "Determined that `%s' is not allowed to connect (not enough connected friends)\n", |
454 | GNUNET_i2s (peer)); | 419 | GNUNET_i2s (&peer->id)); |
455 | #endif | 420 | #endif |
456 | return GNUNET_SYSERR; | 421 | return GNUNET_SYSERR; |
457 | } | 422 | } |
458 | 423 | ||
459 | 424 | ||
460 | /** | 425 | /** |
426 | * Create a new entry in the peer list. | ||
427 | * | ||
428 | * @param peer identity of the new entry | ||
429 | * @param hello hello message, can be NULL | ||
430 | * @param is_friend is the new entry for a friend? | ||
431 | * @return the new entry | ||
432 | */ | ||
433 | static struct PeerList * | ||
434 | make_peer (const struct | ||
435 | GNUNET_PeerIdentity * peer, | ||
436 | const struct GNUNET_HELLO_Message *hello, | ||
437 | int is_friend) | ||
438 | { | ||
439 | struct PeerList *ret; | ||
440 | |||
441 | ret = GNUNET_malloc (sizeof (struct PeerList)); | ||
442 | ret->id = *peer; | ||
443 | ret->is_friend = is_friend; | ||
444 | if (hello != NULL) | ||
445 | { | ||
446 | ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello)); | ||
447 | memcpy (ret->hello, hello, | ||
448 | GNUNET_HELLO_size (hello)); | ||
449 | } | ||
450 | ret->next = peers; | ||
451 | peers = ret; | ||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Free all resources associated with the given peer. | ||
458 | * | ||
459 | * @param peer peer to free | ||
460 | */ | ||
461 | static void | ||
462 | free_peer (struct PeerList *peer) | ||
463 | { | ||
464 | struct PeerList *pos; | ||
465 | struct PeerList *prev; | ||
466 | struct PeerList *next; | ||
467 | |||
468 | prev = NULL; | ||
469 | next = peers; | ||
470 | while (peer != (pos = next)) | ||
471 | { | ||
472 | next = pos->next; | ||
473 | prev = pos; | ||
474 | } | ||
475 | GNUNET_assert (pos != NULL); | ||
476 | if (prev == NULL) | ||
477 | peers = next; | ||
478 | else | ||
479 | prev->next = next; | ||
480 | if (pos->hello_req != NULL) | ||
481 | GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); | ||
482 | if (pos->connect_req != NULL) | ||
483 | GNUNET_CORE_notify_transmit_ready_cancel (pos->connect_req); | ||
484 | if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
485 | GNUNET_SCHEDULER_cancel (sched, | ||
486 | pos->hello_delay_task); | ||
487 | GNUNET_free (pos); | ||
488 | } | ||
489 | |||
490 | |||
491 | /** | ||
492 | * Setup bloom filter for the given peer entry. | ||
493 | * | ||
494 | * @param peer entry to initialize | ||
495 | */ | ||
496 | static void | ||
497 | setup_filter (struct PeerList *peer) | ||
498 | { | ||
499 | /* 2^{-5} chance of not sending a HELLO to a peer is | ||
500 | acceptably small (if the filter is 50% full); | ||
501 | 64 bytes of memory are small compared to the rest | ||
502 | of the data structure and would only really become | ||
503 | "useless" once a HELLO has been passed on to ~100 | ||
504 | other peers, which is likely more than enough in | ||
505 | any case; hence 64, 5 as bloomfilter parameters. */ | ||
506 | peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5); | ||
507 | peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); | ||
508 | /* never send a peer its own HELLO */ | ||
509 | GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->id.hashPubKey); | ||
510 | } | ||
511 | |||
512 | |||
513 | /** | ||
514 | * Function to fill send buffer with HELLO. | ||
515 | * | ||
516 | * @param cls 'struct PeerList' of the target peer | ||
517 | * @param size number of bytes available in buf | ||
518 | * @param buf where the callee should write the message | ||
519 | * @return number of bytes written to buf | ||
520 | */ | ||
521 | static size_t | ||
522 | hello_advertising_ready (void *cls, | ||
523 | size_t size, | ||
524 | void *buf); | ||
525 | |||
526 | |||
527 | /** | ||
528 | * Calculate when we would like to send the next HELLO to this | ||
529 | * peer and ask for it. | ||
530 | * | ||
531 | * @param cls for which peer to schedule the HELLO | ||
532 | * @param tc task context | ||
533 | */ | ||
534 | static void | ||
535 | schedule_next_hello (void *cls, | ||
536 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
537 | { | ||
538 | struct PeerList *pl = cls; | ||
539 | struct PeerList *pos; | ||
540 | struct PeerList *next; | ||
541 | uint16_t next_want; | ||
542 | struct GNUNET_TIME_Relative next_adv; | ||
543 | struct GNUNET_TIME_Relative rst_time; | ||
544 | |||
545 | pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
546 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
547 | return; /* we're out of here */ | ||
548 | next_want = 0; | ||
549 | next_adv = GNUNET_TIME_UNIT_FOREVER_REL; | ||
550 | /* find applicable HELLOs */ | ||
551 | next = peers; | ||
552 | while (NULL != (pos = next)) | ||
553 | { | ||
554 | next = pos->next; | ||
555 | if (pos->hello == NULL) | ||
556 | continue; | ||
557 | rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); | ||
558 | if (0 == rst_time.value) | ||
559 | { | ||
560 | /* time to discard... */ | ||
561 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | ||
562 | setup_filter (pos); | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | if (rst_time.value < next_adv.value) | ||
567 | next_want = GNUNET_HELLO_size (pos->hello); | ||
568 | next_adv = GNUNET_TIME_relative_min (rst_time, | ||
569 | next_adv); | ||
570 | } | ||
571 | if (GNUNET_NO == | ||
572 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | ||
573 | &pl->id.hashPubKey)) | ||
574 | break; | ||
575 | } | ||
576 | if (pos != NULL) | ||
577 | next_adv = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); | ||
578 | if (next_adv.value == 0) | ||
579 | { | ||
580 | /* now! */ | ||
581 | pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0, | ||
582 | next_adv, | ||
583 | &pl->id, | ||
584 | next_want, | ||
585 | &hello_advertising_ready, | ||
586 | pl); | ||
587 | return; | ||
588 | } | ||
589 | pl->hello_delay_task | ||
590 | = GNUNET_SCHEDULER_add_delayed (sched, | ||
591 | next_adv, | ||
592 | &schedule_next_hello, | ||
593 | pl); | ||
594 | } | ||
595 | |||
596 | |||
597 | /** | ||
598 | * Cancel existing requests for sending HELLOs to this peer | ||
599 | * and recalculate when we should send HELLOs to it based | ||
600 | * on our current state (something changed!). | ||
601 | */ | ||
602 | static void | ||
603 | reschedule_hellos (struct PeerList *peer) | ||
604 | { | ||
605 | if (peer->hello_req != NULL) | ||
606 | { | ||
607 | GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req); | ||
608 | peer->hello_req = NULL; | ||
609 | } | ||
610 | if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
611 | { | ||
612 | GNUNET_SCHEDULER_cancel (sched, | ||
613 | peer->hello_delay_task); | ||
614 | peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
615 | } | ||
616 | peer->hello_delay_task | ||
617 | = GNUNET_SCHEDULER_add_now (sched, | ||
618 | &schedule_next_hello, | ||
619 | peer); | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
461 | * Method called whenever a peer connects. | 624 | * Method called whenever a peer connects. |
462 | * | 625 | * |
463 | * @param cls closure | 626 | * @param cls closure |
464 | * @param peer peer identity this notification is about | 627 | * @param peer peer identity this notification is about |
465 | */ | 628 | */ |
466 | static void connect_notify (void *cls, | 629 | static void |
467 | const struct | 630 | connect_notify (void *cls, |
468 | GNUNET_PeerIdentity * peer) | 631 | const struct |
632 | GNUNET_PeerIdentity * peer) | ||
469 | { | 633 | { |
470 | struct PeerList *pos; | 634 | struct PeerList *pos; |
471 | 635 | ||
@@ -473,36 +637,34 @@ static void connect_notify (void *cls, | |||
473 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 637 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
474 | "Core told us that we are connecting to `%s'\n", | 638 | "Core told us that we are connecting to `%s'\n", |
475 | GNUNET_i2s (peer)); | 639 | GNUNET_i2s (peer)); |
476 | #endif | 640 | #endif |
477 | connection_count++; | 641 | connection_count++; |
478 | pos = friends; | 642 | pos = find_peer (peer); |
479 | while (pos != NULL) | 643 | if (pos == NULL) |
480 | { | 644 | { |
481 | if ( (GNUNET_YES == pos->is_friend) && | 645 | pos = make_peer (peer, NULL, GNUNET_NO); |
482 | (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) ) | 646 | if (GNUNET_OK != is_connection_allowed (pos)) |
483 | { | 647 | { |
484 | GNUNET_assert (GNUNET_NO == pos->is_connected); | 648 | GNUNET_assert (pos->is_friend == GNUNET_NO); |
485 | pos->is_connected = GNUNET_YES; | 649 | pos->is_connected = GNUNET_YES; |
486 | pos->blacklisted_until.value = 0; /* remove blacklisting */ | 650 | #if DEBUG_TOPOLOGY |
487 | friend_count++; | 651 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
652 | "Connection to `%s' is forbidden, forcing disconnect!\n", | ||
653 | GNUNET_i2s (peer)); | ||
654 | #endif | ||
655 | force_disconnect (&pos->id); | ||
488 | return; | 656 | return; |
489 | } | 657 | } |
490 | pos = pos->next; | ||
491 | } | 658 | } |
492 | pos = GNUNET_malloc (sizeof(struct PeerList)); | 659 | else |
493 | pos->id = *peer; | ||
494 | pos->is_connected = GNUNET_YES; | ||
495 | pos->next = friends; | ||
496 | friends = pos; | ||
497 | if (GNUNET_OK != is_connection_allowed (peer)) | ||
498 | { | 660 | { |
499 | #if DEBUG_TOPOLOGY | 661 | GNUNET_assert (GNUNET_NO == pos->is_connected); |
500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 662 | pos->blacklisted_until.value = 0; /* remove blacklisting */ |
501 | "Connection to `%s' is forbidden, forcing disconnect!\n", | ||
502 | GNUNET_i2s (peer)); | ||
503 | #endif | ||
504 | force_disconnect (peer); | ||
505 | } | 663 | } |
664 | pos->is_connected = GNUNET_YES; | ||
665 | if (pos->is_friend) | ||
666 | friend_count++; | ||
667 | reschedule_hellos (pos); | ||
506 | } | 668 | } |
507 | 669 | ||
508 | 670 | ||
@@ -514,12 +676,12 @@ drop_non_friends () | |||
514 | { | 676 | { |
515 | struct PeerList *pos; | 677 | struct PeerList *pos; |
516 | 678 | ||
517 | pos = friends; | 679 | pos = peers; |
518 | while (pos != NULL) | 680 | while (pos != NULL) |
519 | { | 681 | { |
520 | if (GNUNET_NO == pos->is_friend) | 682 | if ( (GNUNET_NO == pos->is_friend) && |
683 | (GNUNET_YES == pos->is_connected) ) | ||
521 | { | 684 | { |
522 | GNUNET_assert (GNUNET_YES == pos->is_connected); | ||
523 | #if DEBUG_TOPOLOGY | 685 | #if DEBUG_TOPOLOGY |
524 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 686 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
525 | "Connection to `%s' is not from a friend, forcing disconnect!\n", | 687 | "Connection to `%s' is not from a friend, forcing disconnect!\n", |
@@ -533,106 +695,73 @@ drop_non_friends () | |||
533 | 695 | ||
534 | 696 | ||
535 | /** | 697 | /** |
698 | * Try to add more peers to our connection set. | ||
699 | */ | ||
700 | static void | ||
701 | try_add_peers () | ||
702 | { | ||
703 | struct PeerList *pos; | ||
704 | |||
705 | pos = peers; | ||
706 | while (pos != NULL) | ||
707 | { | ||
708 | if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) && | ||
709 | ( (GNUNET_YES == pos->is_friend) || | ||
710 | (friend_count >= minimum_friend_count) ) && | ||
711 | (GNUNET_YES != pos->is_connected) ) | ||
712 | attempt_connect (pos); | ||
713 | pos = pos->next; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | |||
718 | /** | ||
536 | * Method called whenever a peer disconnects. | 719 | * Method called whenever a peer disconnects. |
537 | * | 720 | * |
538 | * @param cls closure | 721 | * @param cls closure |
539 | * @param peer peer identity this notification is about | 722 | * @param peer peer identity this notification is about |
540 | */ | 723 | */ |
541 | static void disconnect_notify (void *cls, | 724 | static void |
542 | const struct | 725 | disconnect_notify (void *cls, |
543 | GNUNET_PeerIdentity * peer) | 726 | const struct |
727 | GNUNET_PeerIdentity * peer) | ||
544 | { | 728 | { |
545 | struct PeerList *pos; | 729 | struct PeerList *pos; |
546 | struct PeerList *prev; | ||
547 | 730 | ||
548 | #if DEBUG_TOPOLOGY | 731 | #if DEBUG_TOPOLOGY |
549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 732 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
550 | "Core told us that we disconnected from `%s'\n", | 733 | "Core told us that we disconnected from `%s'\n", |
551 | GNUNET_i2s (peer)); | 734 | GNUNET_i2s (peer)); |
552 | #endif | 735 | #endif |
736 | pos = find_peer (peer); | ||
737 | if (pos == NULL) | ||
738 | { | ||
739 | GNUNET_break (0); | ||
740 | return; | ||
741 | } | ||
742 | if (pos->is_connected != GNUNET_YES) | ||
743 | { | ||
744 | GNUNET_break (0); | ||
745 | return; | ||
746 | } | ||
553 | connection_count--; | 747 | connection_count--; |
554 | pos = friends; | 748 | if (pos->is_friend) |
555 | prev = NULL; | 749 | friend_count--; |
556 | while (pos != NULL) | 750 | if ( (connection_count < target_connection_count) || |
751 | (friend_count < minimum_friend_count) ) | ||
752 | try_add_peers (); | ||
753 | if (friend_count < minimum_friend_count) | ||
557 | { | 754 | { |
558 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) | 755 | /* disconnect from all non-friends */ |
559 | { | ||
560 | GNUNET_assert (GNUNET_YES == pos->is_connected); | ||
561 | pos->is_connected = GNUNET_NO; | ||
562 | if (GNUNET_YES == pos->is_friend) | ||
563 | { | ||
564 | friend_count--; | ||
565 | if (friend_count < minimum_friend_count) | ||
566 | { | ||
567 | /* disconnect from all non-friends */ | ||
568 | #if DEBUG_TOPOLOGY | 756 | #if DEBUG_TOPOLOGY |
569 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 757 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
570 | "Not enough friendly connections, dropping all non-friend connections\n"); | 758 | "Not enough friendly connections, dropping all non-friend connections\n"); |
571 | #endif | 759 | #endif |
572 | drop_non_friends (); | 760 | drop_non_friends (); |
573 | attempt_connect (peer, pos); | ||
574 | } | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | /* free entry */ | ||
579 | if (prev == NULL) | ||
580 | friends = pos->next; | ||
581 | else | ||
582 | prev->next = pos->next; | ||
583 | GNUNET_free (pos); | ||
584 | } | ||
585 | return; | ||
586 | } | ||
587 | prev = pos; | ||
588 | pos = pos->next; | ||
589 | } | 761 | } |
590 | GNUNET_break (0); | ||
591 | } | ||
592 | |||
593 | |||
594 | /** | ||
595 | * Find more peers that we should connect to and ask the | ||
596 | * core to establish connections. | ||
597 | */ | ||
598 | static void | ||
599 | find_more_peers (void *cls, | ||
600 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
601 | |||
602 | |||
603 | /** | ||
604 | * Determine when we should try again to find more peers and | ||
605 | * schedule the task. | ||
606 | */ | ||
607 | static void | ||
608 | schedule_peer_search () | ||
609 | { | ||
610 | struct GNUNET_TIME_Relative delay; | ||
611 | |||
612 | /* Typically, we try again every 15 minutes; the minimum period is | ||
613 | 15s; if we are above the connection target, we reduce re-trying | ||
614 | by the square of how much we are above; so for example, with 200% | ||
615 | of the connection target we would only look for more peers once | ||
616 | every hour (after all, we're quite busy processing twice as many | ||
617 | connections as we intended to have); similarly, if we are at only | ||
618 | 25% of our connectivity goal, we will try 16x as hard to connect | ||
619 | (so roughly once a minute, plus the 15s minimum delay */ | ||
620 | delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
621 | 15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count); | ||
622 | #if DEBUG_TOPOLOGY | ||
623 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
624 | "Will try to find more peers in %llums\n", | ||
625 | (unsigned long long) delay.value); | ||
626 | #endif | ||
627 | GNUNET_SCHEDULER_add_delayed (sched, | ||
628 | delay, | ||
629 | &find_more_peers, | ||
630 | NULL); | ||
631 | } | 762 | } |
632 | 763 | ||
633 | 764 | ||
634 | |||
635 | |||
636 | /** | 765 | /** |
637 | * Iterator called on each address. | 766 | * Iterator called on each address. |
638 | * | 767 | * |
@@ -656,15 +785,16 @@ address_iterator (void *cls, | |||
656 | 785 | ||
657 | 786 | ||
658 | /** | 787 | /** |
659 | * We've gotten a HELLO from another peer. | 788 | * We've gotten a HELLO from another peer. Consider it for |
660 | * Consider it for advertising. | 789 | * advertising. |
661 | */ | 790 | */ |
662 | static void | 791 | static void |
663 | consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | 792 | consider_for_advertising (const struct GNUNET_HELLO_Message *hello) |
664 | { | 793 | { |
665 | int have_address; | 794 | int have_address; |
666 | struct GNUNET_PeerIdentity pid; | 795 | struct GNUNET_PeerIdentity pid; |
667 | struct HelloList *pos; | 796 | struct PeerList *peer; |
797 | struct PeerList *pos; | ||
668 | uint16_t size; | 798 | uint16_t size; |
669 | 799 | ||
670 | have_address = GNUNET_NO; | 800 | have_address = GNUNET_NO; |
@@ -675,15 +805,11 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | |||
675 | if (GNUNET_NO == have_address) | 805 | if (GNUNET_NO == have_address) |
676 | return; /* no point in advertising this one... */ | 806 | return; /* no point in advertising this one... */ |
677 | GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid)); | 807 | GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid)); |
678 | pos = hellos; | 808 | peer = find_peer (&pid); |
679 | while (pos != NULL) | 809 | if (peer == NULL) |
680 | { | 810 | peer = make_peer (&pid, hello, GNUNET_NO); |
681 | if (0 == memcmp (&pos->id, | 811 | // FIXME: check if 'hello' is any different from peer->hello? |
682 | &pid, | 812 | GNUNET_free_non_null (peer->hello); |
683 | sizeof(struct GNUNET_PeerIdentity))) | ||
684 | return; /* duplicate, at least "mostly" */ | ||
685 | pos = pos->next; | ||
686 | } | ||
687 | #if DEBUG_TOPOLOGY | 813 | #if DEBUG_TOPOLOGY |
688 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 814 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
689 | "Found `%s' from peer `%s' for advertising\n", | 815 | "Found `%s' from peer `%s' for advertising\n", |
@@ -691,29 +817,30 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | |||
691 | GNUNET_i2s (&pid)); | 817 | GNUNET_i2s (&pid)); |
692 | #endif | 818 | #endif |
693 | size = GNUNET_HELLO_size (hello); | 819 | size = GNUNET_HELLO_size (hello); |
694 | pos = GNUNET_malloc (sizeof(struct HelloList) + size); | 820 | peer->hello = GNUNET_malloc (size); |
695 | pos->msg = (struct GNUNET_HELLO_Message*) &pos[1]; | 821 | memcpy (peer->hello, hello, size); |
696 | memcpy (&pos->msg, hello, size); | 822 | if (peer->filter != NULL) |
697 | pos->id = pid; | 823 | GNUNET_CONTAINER_bloomfilter_free (peer->filter); |
698 | pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); | 824 | setup_filter (peer); |
699 | /* 2^{-5} chance of not sending a HELLO to a peer is | 825 | /* since we have a new HELLO to pick from, re-schedule all |
700 | acceptably small (if the filter is 50% full); | 826 | HELLO requests that are not bound by the HELLO send rate! */ |
701 | 64 bytes of memory are small compared to the rest | 827 | pos = peers; |
702 | of the data structure and would only really become | 828 | while (NULL != pos) |
703 | "useless" once a HELLO has been passed on to ~100 | 829 | { |
704 | other peers, which is likely more than enough in | 830 | if (pos != peer) |
705 | any case; hence 64, 5 as bloomfilter parameters. */ | 831 | { |
706 | pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5); | 832 | if ( (pos->is_connected) && |
707 | /* never send a peer its own HELLO */ | 833 | (GNUNET_TIME_absolute_get_remaining (pos->next_hello_allowed).value <= HELLO_ADVERTISEMENT_MIN_FREQUENCY.value) ) |
708 | GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey); | 834 | reschedule_hellos (pos); |
709 | pos->next = hellos; | 835 | } |
710 | hellos = pos; | 836 | pos = pos->next; |
837 | } | ||
711 | } | 838 | } |
712 | 839 | ||
713 | 840 | ||
714 | /** | 841 | /** |
715 | * Peerinfo calls this function to let us know about a | 842 | * Peerinfo calls this function to let us know about a possible peer |
716 | * possible peer that we might want to connect to. | 843 | * that we might want to connect to. |
717 | */ | 844 | */ |
718 | static void | 845 | static void |
719 | process_peer (void *cls, | 846 | process_peer (void *cls, |
@@ -723,102 +850,59 @@ process_peer (void *cls, | |||
723 | { | 850 | { |
724 | struct PeerList *pos; | 851 | struct PeerList *pos; |
725 | 852 | ||
726 | if (peer == NULL) | 853 | GNUNET_assert (peer != NULL); |
854 | if (0 == memcmp (&my_identity, | ||
855 | peer, sizeof (struct GNUNET_PeerIdentity))) | ||
856 | return; /* that's me! */ | ||
857 | if (hello == NULL) | ||
727 | { | 858 | { |
728 | pitr_more = NULL; | 859 | /* free existing HELLO, if any */ |
729 | /* last call, schedule 'find_more_peers' again... */ | 860 | pos = find_peer (peer); |
730 | if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 861 | if (NULL != (pos = find_peer (peer))) |
731 | { | 862 | { |
732 | #if DEBUG_TOPOLOGY | 863 | GNUNET_free_non_null (pos->hello); |
733 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 864 | pos->hello = NULL; |
734 | "Received shutdown request, stopping search for peers to connect to.\n"); | 865 | if (pos->filter != NULL) |
735 | #endif | 866 | { |
736 | return; | 867 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); |
868 | pos->filter = NULL; | ||
869 | } | ||
870 | if ( (! pos->is_connected) && | ||
871 | (! pos->is_friend) && | ||
872 | (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) | ||
873 | free_peer (pos); | ||
737 | } | 874 | } |
738 | schedule_peer_search (); | ||
739 | return; | ||
740 | } | ||
741 | if (hello == NULL) | ||
742 | { | ||
743 | /* no HELLO known; can not connect, ignore! */ | ||
744 | return; | 875 | return; |
745 | } | 876 | } |
746 | if (0 == memcmp (&my_identity, | ||
747 | peer, sizeof (struct GNUNET_PeerIdentity))) | ||
748 | return; /* that's me! */ | ||
749 | |||
750 | consider_for_advertising (hello); | 877 | consider_for_advertising (hello); |
878 | pos = find_peer (peer); | ||
751 | #if DEBUG_TOPOLOGY | 879 | #if DEBUG_TOPOLOGY |
752 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 880 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
753 | "Considering connecting to peer `%s'\n", | 881 | "Considering connecting to peer `%s'\n", |
754 | GNUNET_i2s (peer)); | 882 | GNUNET_i2s (peer)); |
755 | #endif | 883 | #endif |
756 | pos = friends; | 884 | if (GNUNET_YES == pos->is_connected) |
757 | while (pos != NULL) | ||
758 | { | ||
759 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
760 | { | ||
761 | if (GNUNET_YES == pos->is_connected) | ||
762 | { | ||
763 | #if DEBUG_TOPOLOGY | ||
764 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
765 | "Already connected to peer `%s'\n", | ||
766 | GNUNET_i2s (peer)); | ||
767 | #endif | ||
768 | return; | ||
769 | } | ||
770 | if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0) | ||
771 | { | ||
772 | #if DEBUG_TOPOLOGY | ||
773 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
774 | "Already tried peer `%s' recently\n", | ||
775 | GNUNET_i2s (peer)); | ||
776 | #endif | ||
777 | return; /* peer still blacklisted */ | ||
778 | } | ||
779 | if (GNUNET_YES == pos->is_friend) | ||
780 | { | ||
781 | attempt_connect (peer, pos); | ||
782 | return; | ||
783 | } | ||
784 | } | ||
785 | pos = pos->next; | ||
786 | } | ||
787 | if ( (GNUNET_YES == friends_only) || | ||
788 | (friend_count < minimum_friend_count) ) | ||
789 | { | 885 | { |
790 | #if DEBUG_TOPOLOGY | 886 | #if DEBUG_TOPOLOGY |
791 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 887 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
792 | "Peer `%s' is not a friend, and we currently only connect to friends\n", | 888 | "Already connected to peer `%s'\n", |
793 | GNUNET_i2s (peer)); | 889 | GNUNET_i2s (peer)); |
794 | #endif | 890 | #endif |
795 | return; | 891 | return; |
796 | } | 892 | } |
797 | attempt_connect (peer, NULL); | 893 | if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0) |
798 | } | 894 | { |
799 | |||
800 | |||
801 | /** | ||
802 | * Try to add more friends to our connection set. | ||
803 | */ | ||
804 | static void | ||
805 | try_add_friends () | ||
806 | { | ||
807 | struct PeerList *pos; | ||
808 | |||
809 | #if DEBUG_TOPOLOGY | 895 | #if DEBUG_TOPOLOGY |
810 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 896 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
811 | "Considering all of our friends for new connections\n"); | 897 | "Already tried peer `%s' recently\n", |
898 | GNUNET_i2s (peer)); | ||
812 | #endif | 899 | #endif |
813 | pos = friends; | 900 | return; /* peer still blacklisted */ |
814 | while (pos != NULL) | ||
815 | { | ||
816 | if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) && | ||
817 | (GNUNET_YES == pos->is_friend) && | ||
818 | (GNUNET_YES != pos->is_connected) ) | ||
819 | attempt_connect (&pos->id, pos); | ||
820 | pos = pos->next; | ||
821 | } | 901 | } |
902 | if ( (GNUNET_YES == pos->is_friend) || | ||
903 | (GNUNET_YES != friends_only) || | ||
904 | (friend_count >= minimum_friend_count) ) | ||
905 | attempt_connect (pos); | ||
822 | } | 906 | } |
823 | 907 | ||
824 | 908 | ||
@@ -827,82 +911,27 @@ try_add_friends () | |||
827 | * where the blacklisting has expired. | 911 | * where the blacklisting has expired. |
828 | */ | 912 | */ |
829 | static void | 913 | static void |
830 | discard_old_blacklist_entries () | 914 | discard_old_blacklist_entries (void *cls, |
915 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
831 | { | 916 | { |
832 | struct PeerList *pos; | 917 | struct PeerList *pos; |
833 | struct PeerList *next; | 918 | struct PeerList *next; |
834 | struct PeerList *prev; | ||
835 | 919 | ||
836 | next = friends; | 920 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
837 | prev = NULL; | 921 | return; |
922 | next = peers; | ||
838 | while (NULL != (pos = next)) | 923 | while (NULL != (pos = next)) |
839 | { | 924 | { |
840 | next = pos->next; | 925 | next = pos->next; |
841 | if ( (GNUNET_NO == pos->is_friend) && | 926 | if ( (GNUNET_NO == pos->is_friend) && |
842 | (GNUNET_NO == pos->is_connected) && | 927 | (GNUNET_NO == pos->is_connected) && |
843 | (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) | 928 | (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) |
844 | { | 929 | free_peer (pos); |
845 | /* delete 'pos' from list */ | ||
846 | #if DEBUG_TOPOLOGY | ||
847 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
848 | "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n", | ||
849 | GNUNET_i2s (&pos->id)); | ||
850 | #endif | ||
851 | if (prev == NULL) | ||
852 | friends = next; | ||
853 | else | ||
854 | prev->next = next; | ||
855 | GNUNET_free (pos); | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | prev = pos; | ||
860 | } | ||
861 | } | ||
862 | } | ||
863 | |||
864 | |||
865 | /** | ||
866 | * Find more peers that we should connect to and ask the | ||
867 | * core to establish connections. | ||
868 | */ | ||
869 | static void | ||
870 | find_more_peers (void *cls, | ||
871 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
872 | { | ||
873 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
874 | { | ||
875 | #if DEBUG_TOPOLOGY | ||
876 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
877 | "Received shutdown request, stopping search for peers to connect to.\n"); | ||
878 | #endif | ||
879 | return; | ||
880 | } | ||
881 | discard_old_blacklist_entries (); | ||
882 | if (connection_count <= target_connection_count) | ||
883 | { | ||
884 | schedule_peer_search (); | ||
885 | return; | ||
886 | } | 930 | } |
887 | if ( (GNUNET_YES == friends_only) || | 931 | GNUNET_SCHEDULER_add_delayed (sched, |
888 | (friend_count < minimum_friend_count) ) | 932 | BLACKLIST_AFTER_ATTEMPT, |
889 | { | 933 | &discard_old_blacklist_entries, |
890 | try_add_friends (); | 934 | NULL); |
891 | schedule_peer_search (); | ||
892 | return; | ||
893 | } | ||
894 | #if DEBUG_TOPOLOGY | ||
895 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
896 | "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n", | ||
897 | connection_count, | ||
898 | target_connection_count, | ||
899 | friend_count); | ||
900 | #endif | ||
901 | pitr_more = GNUNET_PEERINFO_iterate (cfg, | ||
902 | sched, | ||
903 | NULL, | ||
904 | 0, GNUNET_TIME_UNIT_FOREVER_REL, | ||
905 | &process_peer, NULL); | ||
906 | } | 935 | } |
907 | 936 | ||
908 | 937 | ||
@@ -938,23 +967,14 @@ core_init (void *cls, | |||
938 | "I am peer `%s'\n", | 967 | "I am peer `%s'\n", |
939 | GNUNET_i2s (my_id)); | 968 | GNUNET_i2s (my_id)); |
940 | #endif | 969 | #endif |
941 | if (autoconnect) | 970 | GNUNET_SCHEDULER_add_delayed (sched, |
942 | GNUNET_SCHEDULER_add_delayed (sched, | 971 | BLACKLIST_AFTER_ATTEMPT, |
943 | GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */, | 972 | &discard_old_blacklist_entries, |
944 | &find_more_peers, | 973 | NULL); |
945 | NULL); | ||
946 | } | 974 | } |
947 | 975 | ||
948 | 976 | ||
949 | /** | 977 | /** |
950 | * gnunet-daemon-topology command line options. | ||
951 | */ | ||
952 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
953 | GNUNET_GETOPT_OPTION_END | ||
954 | }; | ||
955 | |||
956 | |||
957 | /** | ||
958 | * Read the friends file. | 978 | * Read the friends file. |
959 | */ | 979 | */ |
960 | static void | 980 | static void |
@@ -963,7 +983,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
963 | char *fn; | 983 | char *fn; |
964 | char *data; | 984 | char *data; |
965 | size_t pos; | 985 | size_t pos; |
966 | GNUNET_HashCode hc; | 986 | struct GNUNET_PeerIdentity pid; |
967 | struct stat frstat; | 987 | struct stat frstat; |
968 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; | 988 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; |
969 | unsigned int entries_found; | 989 | unsigned int entries_found; |
@@ -1031,7 +1051,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1031 | continue; | 1051 | continue; |
1032 | } | 1052 | } |
1033 | enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | 1053 | enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; |
1034 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc)) | 1054 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) |
1035 | { | 1055 | { |
1036 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1056 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1037 | _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), | 1057 | _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), |
@@ -1041,11 +1061,9 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1041 | else | 1061 | else |
1042 | { | 1062 | { |
1043 | entries_found++; | 1063 | entries_found++; |
1044 | fl = GNUNET_malloc (sizeof(struct PeerList)); | 1064 | fl = make_peer (&pid, |
1045 | fl->is_friend = GNUNET_YES; | 1065 | NULL, |
1046 | fl->id.hashPubKey = hc; | 1066 | GNUNET_YES); |
1047 | fl->next = friends; | ||
1048 | friends = fl; | ||
1049 | #if DEBUG_TOPOLOGY | 1067 | #if DEBUG_TOPOLOGY |
1050 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1068 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1051 | "Found friend `%s' in configuration\n", | 1069 | "Found friend `%s' in configuration\n", |
@@ -1104,144 +1122,73 @@ handle_encrypted_hello (void *cls, | |||
1104 | 1122 | ||
1105 | 1123 | ||
1106 | /** | 1124 | /** |
1107 | * Peerinfo calls this function to let us know about a | ||
1108 | * possible peer that we might want to connect to. | ||
1109 | * | ||
1110 | * @param cls unused | ||
1111 | * @param peer NULL for the end of the list, otherwise a peer identity | ||
1112 | * @param hello a HELLO for a peer, or NULL | ||
1113 | * @param trust how much do we trust the given peer? | ||
1114 | */ | ||
1115 | static void | ||
1116 | gather_hello_callback (void *cls, | ||
1117 | const struct GNUNET_PeerIdentity *peer, | ||
1118 | const struct GNUNET_HELLO_Message *hello, | ||
1119 | uint32_t trust) | ||
1120 | { | ||
1121 | if (peer == NULL) | ||
1122 | { | ||
1123 | pitr = NULL; | ||
1124 | return; | ||
1125 | } | ||
1126 | #if DEBUG_TOPOLOGY | ||
1127 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1128 | "Received `%s' for peer `%s'", | ||
1129 | "HELLO", | ||
1130 | GNUNET_i2s (peer)); | ||
1131 | #endif | ||
1132 | if (hello != NULL) | ||
1133 | consider_for_advertising (hello); | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | // FIXME: this no longer works (no solicitation!) | ||
1138 | /** | ||
1139 | * Function to fill send buffer with HELLO. | 1125 | * Function to fill send buffer with HELLO. |
1140 | * | 1126 | * |
1141 | * @param cls unused | 1127 | * @param cls 'struct PeerList' of the target peer |
1142 | * @param receiver the receiver of the message | 1128 | * @param size number of bytes available in buf |
1143 | * @param position is the reference to the | 1129 | * @param buf where the callee should write the message |
1144 | * first unused position in the buffer where GNUnet is building | 1130 | * @return number of bytes written to buf |
1145 | * the message | ||
1146 | * @param padding is the number of bytes left in that buffer. | ||
1147 | * @return the number of bytes written to | ||
1148 | * that buffer (must be a positive number). | ||
1149 | */ | 1131 | */ |
1150 | /* static */ unsigned int | 1132 | static size_t |
1151 | hello_advertising (void *cls, | 1133 | hello_advertising_ready (void *cls, |
1152 | const struct GNUNET_PeerIdentity * | 1134 | size_t size, |
1153 | receiver, | 1135 | void *buf) |
1154 | void *position, | ||
1155 | size_t padding) | ||
1156 | { | 1136 | { |
1157 | struct PeerList *pl; | 1137 | struct PeerList *pl = cls; |
1158 | struct HelloList *pos; | 1138 | struct PeerList *pos; |
1159 | struct HelloList *prev; | 1139 | struct PeerList *next; |
1160 | struct HelloList *next; | 1140 | uint16_t want; |
1161 | uint16_t size; | 1141 | size_t hs; |
1162 | 1142 | ||
1143 | pl->hello_req = NULL; | ||
1163 | #if DEBUG_TOPOLOGY | 1144 | #if DEBUG_TOPOLOGY |
1164 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1145 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1165 | "Data solicited for `%s', considering sending `%s's", | 1146 | "Data solicited for `%s', considering sending `%s'", |
1166 | GNUNET_i2s (receiver), | 1147 | GNUNET_i2s (&pl->id), |
1167 | "HELLO"); | 1148 | "HELLO"); |
1168 | #endif | 1149 | #endif |
1169 | pl = friends; | ||
1170 | while (pl != NULL) | ||
1171 | { | ||
1172 | if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity))) | ||
1173 | break; | ||
1174 | pl = pl->next; | ||
1175 | } | ||
1176 | if (pl == NULL) | ||
1177 | { | ||
1178 | GNUNET_break (0); | ||
1179 | return 0; | ||
1180 | } | ||
1181 | /* find applicable HELLOs */ | 1150 | /* find applicable HELLOs */ |
1182 | prev = NULL; | 1151 | next = peers; |
1183 | next = hellos; | ||
1184 | while (NULL != (pos = next)) | 1152 | while (NULL != (pos = next)) |
1185 | { | 1153 | { |
1186 | next = pos->next; | 1154 | next = pos->next; |
1187 | if (GNUNET_NO == | 1155 | if (pos->hello == NULL) |
1188 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | 1156 | continue; |
1189 | &receiver->hashPubKey)) | 1157 | if (0 == GNUNET_TIME_absolute_get_remaining (pos->filter_expiration).value) |
1190 | break; | ||
1191 | if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value) | ||
1192 | { | 1158 | { |
1193 | /* time to discard... */ | 1159 | /* time to discard... */ |
1194 | if (prev != NULL) | ||
1195 | prev->next = next; | ||
1196 | else | ||
1197 | hellos = next; | ||
1198 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | 1160 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); |
1199 | GNUNET_free (pos); | 1161 | setup_filter (pos); |
1200 | } | ||
1201 | else | ||
1202 | { | ||
1203 | prev = pos; | ||
1204 | } | 1162 | } |
1163 | if (GNUNET_NO == | ||
1164 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | ||
1165 | &pl->id.hashPubKey)) | ||
1166 | break; | ||
1205 | } | 1167 | } |
1168 | want = 0; | ||
1206 | if (pos != NULL) | 1169 | if (pos != NULL) |
1207 | { | 1170 | { |
1208 | size = GNUNET_HELLO_size (pos->msg); | 1171 | hs = GNUNET_HELLO_size (pos->hello); |
1209 | if (size < padding) | 1172 | if (hs < size) |
1210 | { | 1173 | { |
1211 | memcpy (position, pos->msg, size); | 1174 | want = hs; |
1175 | memcpy (buf, pos->hello, want); | ||
1212 | GNUNET_CONTAINER_bloomfilter_add (pos->filter, | 1176 | GNUNET_CONTAINER_bloomfilter_add (pos->filter, |
1213 | &receiver->hashPubKey); | 1177 | &pl->id.hashPubKey); |
1214 | } | 1178 | pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); |
1215 | else | ||
1216 | { | ||
1217 | size = 0; | ||
1218 | } | ||
1219 | #if DEBUG_TOPOLOGY | 1179 | #if DEBUG_TOPOLOGY |
1220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1221 | "Sending %u bytes of `%s's", | 1181 | "Sending %u bytes of `%s's", |
1222 | (unsigned int) size, | 1182 | (unsigned int) want, |
1223 | "HELLO"); | 1183 | "HELLO"); |
1224 | #endif | ||
1225 | return size; | ||
1226 | } | ||
1227 | if ( (NULL == pitr) && | ||
1228 | (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value > | ||
1229 | MIN_HELLO_GATHER_DELAY.value) ) | ||
1230 | { | ||
1231 | #if DEBUG_TOPOLOGY | ||
1232 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1233 | "Have no `%s's, trying to get some from `%s' for next time", | ||
1234 | "HELLO", | ||
1235 | "PEERINFO"); | ||
1236 | #endif | 1184 | #endif |
1237 | last_hello_gather_time = GNUNET_TIME_absolute_get(); | 1185 | } |
1238 | pitr = GNUNET_PEERINFO_iterate (cfg, | ||
1239 | sched, | ||
1240 | NULL, | ||
1241 | 0, GNUNET_TIME_UNIT_FOREVER_REL, | ||
1242 | &gather_hello_callback, NULL); | ||
1243 | } | 1186 | } |
1244 | return 0; | 1187 | pl->hello_delay_task |
1188 | = GNUNET_SCHEDULER_add_now (sched, | ||
1189 | &schedule_next_hello, | ||
1190 | pl); | ||
1191 | return want; | ||
1245 | } | 1192 | } |
1246 | 1193 | ||
1247 | 1194 | ||
@@ -1252,7 +1199,6 @@ hello_advertising (void *cls, | |||
1252 | static void | 1199 | static void |
1253 | cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1200 | cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
1254 | { | 1201 | { |
1255 | struct PeerList *pl; | ||
1256 | struct DisconnectList *dl; | 1202 | struct DisconnectList *dl; |
1257 | 1203 | ||
1258 | if (NULL != peerinfo_notify) | 1204 | if (NULL != peerinfo_notify) |
@@ -1260,28 +1206,15 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1260 | GNUNET_PEERINFO_notify_cancel (peerinfo_notify); | 1206 | GNUNET_PEERINFO_notify_cancel (peerinfo_notify); |
1261 | peerinfo_notify = NULL; | 1207 | peerinfo_notify = NULL; |
1262 | } | 1208 | } |
1263 | if (NULL != pitr) | ||
1264 | { | ||
1265 | GNUNET_PEERINFO_iterate_cancel (pitr); | ||
1266 | pitr = NULL; | ||
1267 | } | ||
1268 | if (NULL != pitr_more) | ||
1269 | { | ||
1270 | GNUNET_PEERINFO_iterate_cancel (pitr_more); | ||
1271 | pitr_more = NULL; | ||
1272 | } | ||
1273 | GNUNET_TRANSPORT_disconnect (transport); | 1209 | GNUNET_TRANSPORT_disconnect (transport); |
1274 | transport = NULL; | 1210 | transport = NULL; |
1211 | while (NULL != peers) | ||
1212 | free_peer (peers); | ||
1275 | if (handle != NULL) | 1213 | if (handle != NULL) |
1276 | { | 1214 | { |
1277 | GNUNET_CORE_disconnect (handle); | 1215 | GNUNET_CORE_disconnect (handle); |
1278 | handle = NULL; | 1216 | handle = NULL; |
1279 | } | 1217 | } |
1280 | while (NULL != (pl = friends)) | ||
1281 | { | ||
1282 | friends = pl->next; | ||
1283 | GNUNET_free (pl); | ||
1284 | } | ||
1285 | while (NULL != (dl = disconnect_head)) | 1218 | while (NULL != (dl = disconnect_head)) |
1286 | { | 1219 | { |
1287 | GNUNET_CONTAINER_DLL_remove (disconnect_head, | 1220 | GNUNET_CONTAINER_DLL_remove (disconnect_head, |
@@ -1391,6 +1324,14 @@ run (void *cls, | |||
1391 | 1324 | ||
1392 | 1325 | ||
1393 | /** | 1326 | /** |
1327 | * gnunet-daemon-topology command line options. | ||
1328 | */ | ||
1329 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1330 | GNUNET_GETOPT_OPTION_END | ||
1331 | }; | ||
1332 | |||
1333 | |||
1334 | /** | ||
1394 | * The main function for the topology daemon. | 1335 | * The main function for the topology daemon. |
1395 | * | 1336 | * |
1396 | * @param argc number of arguments from the command line | 1337 | * @param argc number of arguments from the command line |