diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-04-17 20:55:37 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-04-17 20:55:37 +0000 |
commit | 3c8c69ae5071745d3d1e810001404f752cf559c3 (patch) | |
tree | 1400a9b0ba55353b01a89b45a7ab03db586b0363 /src/topology | |
parent | 6032eb391ed917368d05d697aa2e441e0908d8bb (diff) | |
download | gnunet-3c8c69ae5071745d3d1e810001404f752cf559c3.tar.gz gnunet-3c8c69ae5071745d3d1e810001404f752cf559c3.zip |
working on topology
Diffstat (limited to 'src/topology')
-rw-r--r-- | src/topology/gnunet-daemon-topology.c | 818 |
1 files changed, 469 insertions, 349 deletions
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c index 57f88c980..3aa518fa1 100644 --- a/src/topology/gnunet-daemon-topology.c +++ b/src/topology/gnunet-daemon-topology.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include "platform.h" | 28 | #include "platform.h" |
29 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_core_service.h" | 30 | #include "gnunet_core_service.h" |
30 | #include "gnunet_protocols.h" | 31 | #include "gnunet_protocols.h" |
31 | #include "gnunet_peerinfo_service.h" | 32 | #include "gnunet_peerinfo_service.h" |
@@ -40,13 +41,13 @@ | |||
40 | * For how long do we blacklist a peer after a failed connection | 41 | * For how long do we blacklist a peer after a failed connection |
41 | * attempt? | 42 | * attempt? |
42 | */ | 43 | */ |
43 | #define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS | 44 | #define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS |
44 | 45 | ||
45 | /** | 46 | /** |
46 | * For how long do we blacklist a friend after a failed connection | 47 | * For how long do we blacklist a friend after a failed connection |
47 | * attempt? | 48 | * attempt? |
48 | */ | 49 | */ |
49 | #define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | 50 | #define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) |
50 | 51 | ||
51 | /** | 52 | /** |
52 | * How often do we at most advertise any HELLO to a peer? | 53 | * How often do we at most advertise any HELLO to a peer? |
@@ -60,15 +61,14 @@ | |||
60 | 61 | ||
61 | 62 | ||
62 | /** | 63 | /** |
63 | * List of neighbours, friends and blacklisted peers. | 64 | * Record for neighbours, friends and blacklisted peers. |
64 | */ | 65 | */ |
65 | struct PeerList | 66 | struct Peer |
66 | { | 67 | { |
67 | |||
68 | /** | 68 | /** |
69 | * This is a linked list. | 69 | * Which peer is this entry about? |
70 | */ | 70 | */ |
71 | struct PeerList *next; | 71 | struct GNUNET_PeerIdentity pid; |
72 | 72 | ||
73 | /** | 73 | /** |
74 | * Our handle for the request to transmit HELLOs to this peer; NULL | 74 | * Our handle for the request to transmit HELLOs to this peer; NULL |
@@ -100,25 +100,10 @@ struct PeerList | |||
100 | struct GNUNET_TRANSPORT_BlacklistRequest *wh; | 100 | struct GNUNET_TRANSPORT_BlacklistRequest *wh; |
101 | 101 | ||
102 | /** | 102 | /** |
103 | * Is this peer listed here because he is a friend? | ||
104 | */ | ||
105 | int is_friend; | ||
106 | |||
107 | /** | ||
108 | * Are we connected to this peer right now? | ||
109 | */ | ||
110 | int is_connected; | ||
111 | |||
112 | /** | ||
113 | * Are we currently blocking this peer (via blacklist)? | ||
114 | */ | ||
115 | int is_blocked; | ||
116 | |||
117 | /** | ||
118 | * Until what time should we not try to connect again | 103 | * Until what time should we not try to connect again |
119 | * to this peer? | 104 | * to this peer? |
120 | */ | 105 | */ |
121 | struct GNUNET_TIME_Absolute blacklisted_until; | 106 | struct GNUNET_TIME_Absolute greylisted_until; |
122 | 107 | ||
123 | /** | 108 | /** |
124 | * Next time we are allowed to transmit a HELLO to this peer? | 109 | * Next time we are allowed to transmit a HELLO to this peer? |
@@ -137,9 +122,24 @@ struct PeerList | |||
137 | GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; | 122 | GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; |
138 | 123 | ||
139 | /** | 124 | /** |
140 | * ID of the peer. | 125 | * ID of task we use to clear peers from the greylist. |
141 | */ | 126 | */ |
142 | struct GNUNET_PeerIdentity id; | 127 | GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task; |
128 | |||
129 | /** | ||
130 | * Is this peer listed here because he is a friend? | ||
131 | */ | ||
132 | int is_friend; | ||
133 | |||
134 | /** | ||
135 | * Are we connected to this peer right now? | ||
136 | */ | ||
137 | int is_connected; | ||
138 | |||
139 | /** | ||
140 | * Are we currently blocking this peer (via blacklist)? | ||
141 | */ | ||
142 | int is_blocked; | ||
143 | 143 | ||
144 | }; | 144 | }; |
145 | 145 | ||
@@ -204,10 +204,11 @@ static struct GNUNET_TRANSPORT_Handle *transport; | |||
204 | static struct GNUNET_PeerIdentity my_identity; | 204 | static struct GNUNET_PeerIdentity my_identity; |
205 | 205 | ||
206 | /** | 206 | /** |
207 | * Linked list of all of our friends, all of our current neighbours | 207 | * All of our friends, all of our current neighbours and all peers for |
208 | * and all peers for which we have HELLOs. So pretty much everyone. | 208 | * which we have HELLOs. So pretty much everyone. Maps peer identities |
209 | * to 'struct Peer *' values. | ||
209 | */ | 210 | */ |
210 | static struct PeerList *peers; | 211 | static struct GNUNET_CONTAINER_MultiHashMap *peers; |
211 | 212 | ||
212 | /** | 213 | /** |
213 | * Handle for reporting statistics. | 214 | * Handle for reporting statistics. |
@@ -282,11 +283,13 @@ disconnect_done (void *cls, | |||
282 | 283 | ||
283 | /** | 284 | /** |
284 | * Force a disconnect from the specified peer. | 285 | * Force a disconnect from the specified peer. |
286 | * | ||
287 | * @param pl peer to disconnect | ||
285 | */ | 288 | */ |
286 | static void | 289 | static void |
287 | force_disconnect (struct PeerList *pl) | 290 | force_disconnect (struct Peer *pl) |
288 | { | 291 | { |
289 | const struct GNUNET_PeerIdentity *peer = &pl->id; | 292 | const struct GNUNET_PeerIdentity *peer = &pl->pid; |
290 | struct DisconnectList *dl; | 293 | struct DisconnectList *dl; |
291 | 294 | ||
292 | if (NULL != pl->wh) | 295 | if (NULL != pl->wh) |
@@ -314,14 +317,14 @@ force_disconnect (struct PeerList *pl) | |||
314 | * Function called once our request to 'whitelist' a peer | 317 | * Function called once our request to 'whitelist' a peer |
315 | * has completed. | 318 | * has completed. |
316 | * | 319 | * |
317 | * @param cls our 'struct PeerList' | 320 | * @param cls our 'struct Peer' |
318 | * @param tc unused | 321 | * @param tc unused |
319 | */ | 322 | */ |
320 | static void | 323 | static void |
321 | whitelist_done (void *cls, | 324 | whitelist_done (void *cls, |
322 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 325 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
323 | { | 326 | { |
324 | struct PeerList *pl = cls; | 327 | struct Peer *pl = cls; |
325 | 328 | ||
326 | pl->wh = NULL; | 329 | pl->wh = NULL; |
327 | GNUNET_STATISTICS_update (stats, | 330 | GNUNET_STATISTICS_update (stats, |
@@ -332,13 +335,40 @@ whitelist_done (void *cls, | |||
332 | 335 | ||
333 | 336 | ||
334 | /** | 337 | /** |
338 | * Whitelist the given peer (if it was blacklisted before). | ||
339 | * | ||
340 | * @param cls closure (not used) | ||
341 | * @param pid identity of the peer | ||
342 | * @param value peer to free | ||
343 | * @return GNUNET_YES (always: continue to iterate) | ||
344 | */ | ||
345 | static int | ||
346 | whitelist_peer (void *cls, | ||
347 | const GNUNET_HashCode *pid, | ||
348 | void *value) | ||
349 | { | ||
350 | struct Peer *pl = value; | ||
351 | |||
352 | if (! pl->is_blocked) | ||
353 | return GNUNET_YES; | ||
354 | pl->wh = GNUNET_TRANSPORT_blacklist (sched, cfg, | ||
355 | &pl->pid, | ||
356 | GNUNET_TIME_UNIT_ZERO, | ||
357 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
358 | &whitelist_done, | ||
359 | pl); | ||
360 | pl->is_blocked = GNUNET_NO; | ||
361 | return GNUNET_YES; | ||
362 | } | ||
363 | |||
364 | |||
365 | /** | ||
335 | * Whitelist all peers that we blacklisted; we've passed | 366 | * Whitelist all peers that we blacklisted; we've passed |
336 | * the minimum number of friends. | 367 | * the minimum number of friends. |
337 | */ | 368 | */ |
338 | static void | 369 | static void |
339 | whitelist_peers () | 370 | whitelist_peers () |
340 | { | 371 | { |
341 | struct PeerList *pl; | ||
342 | struct DisconnectList *dl; | 372 | struct DisconnectList *dl; |
343 | 373 | ||
344 | /* first, cancel all blacklisting requests */ | 374 | /* first, cancel all blacklisting requests */ |
@@ -352,53 +382,150 @@ whitelist_peers () | |||
352 | } | 382 | } |
353 | /* then, specifically whitelist all peers that we | 383 | /* then, specifically whitelist all peers that we |
354 | know to have blacklisted */ | 384 | know to have blacklisted */ |
355 | pl = peers; | 385 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
356 | while (pl != NULL) | 386 | &whitelist_peer, |
357 | { | 387 | NULL); |
358 | if (pl->is_blocked) | ||
359 | { | ||
360 | pl->wh = GNUNET_TRANSPORT_blacklist (sched, cfg, | ||
361 | &pl->id, | ||
362 | GNUNET_TIME_UNIT_ZERO, | ||
363 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
364 | &whitelist_done, | ||
365 | pl); | ||
366 | pl->is_blocked = GNUNET_NO; | ||
367 | } | ||
368 | pl = pl->next; | ||
369 | } | ||
370 | } | 388 | } |
371 | 389 | ||
372 | 390 | ||
373 | /** | 391 | /** |
374 | * Function called by core when our attempt to connect succeeded. | 392 | * Function called by core when our attempt to connect succeeded. |
393 | * | ||
394 | * @param cls the 'struct Peer' for which we issued the connect request | ||
395 | * @param tc scheduler context | ||
375 | */ | 396 | */ |
376 | static void | 397 | static void |
377 | connect_completed_callback (void *cls, | 398 | connect_completed_callback (void *cls, |
378 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 399 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
379 | { | 400 | { |
380 | struct PeerList *pos = cls; | 401 | struct Peer *pos = cls; |
381 | 402 | ||
382 | pos->connect_req = NULL; | 403 | pos->connect_req = NULL; |
383 | } | 404 | } |
384 | 405 | ||
385 | 406 | ||
386 | /** | 407 | /** |
408 | * Check if an additional connection from the given peer is allowed. | ||
409 | * | ||
410 | * @param peer connection to check | ||
411 | * @return GNUNET_OK if the connection is allowed | ||
412 | */ | ||
413 | static int | ||
414 | is_connection_allowed (struct Peer *peer) | ||
415 | { | ||
416 | if (0 == memcmp (&my_identity, | ||
417 | &peer->pid, | ||
418 | sizeof (struct GNUNET_PeerIdentity))) | ||
419 | return GNUNET_SYSERR; /* disallow connections to self */ | ||
420 | if (peer->is_friend) | ||
421 | return GNUNET_OK; | ||
422 | if (GNUNET_YES == friends_only) | ||
423 | { | ||
424 | #if DEBUG_TOPOLOGY | ||
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
426 | "Determined that `%s' is not allowed to connect (not a friend)\n", | ||
427 | GNUNET_i2s (&peer->pid)); | ||
428 | #endif | ||
429 | return GNUNET_SYSERR; | ||
430 | } | ||
431 | if (friend_count >= minimum_friend_count) | ||
432 | return GNUNET_OK; | ||
433 | #if DEBUG_TOPOLOGY | ||
434 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "Determined that `%s' is not allowed to connect (not enough connected friends)\n", | ||
436 | GNUNET_i2s (&peer->pid)); | ||
437 | #endif | ||
438 | return GNUNET_SYSERR; | ||
439 | } | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Free all resources associated with the given peer. | ||
444 | * | ||
445 | * @param cls closure (not used) | ||
446 | * @param pid identity of the peer | ||
447 | * @param value peer to free | ||
448 | * @return GNUNET_YES (always: continue to iterate) | ||
449 | */ | ||
450 | static int | ||
451 | free_peer (void *cls, | ||
452 | const GNUNET_HashCode *pid, | ||
453 | void *value) | ||
454 | { | ||
455 | struct Peer *pos = value; | ||
456 | |||
457 | GNUNET_break (GNUNET_OK == | ||
458 | GNUNET_CONTAINER_multihashmap_remove (peers, | ||
459 | pid, | ||
460 | pos)); | ||
461 | if (pos->hello_req != NULL) | ||
462 | GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); | ||
463 | if (pos->wh != NULL) | ||
464 | GNUNET_TRANSPORT_blacklist_cancel (pos->wh); | ||
465 | if (pos->connect_req != NULL) | ||
466 | GNUNET_CORE_peer_request_connect_cancel (pos->connect_req); | ||
467 | if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
468 | GNUNET_SCHEDULER_cancel (sched, | ||
469 | pos->hello_delay_task); | ||
470 | GNUNET_free_non_null (pos->hello); | ||
471 | if (pos->filter != NULL) | ||
472 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | ||
473 | GNUNET_free (pos); | ||
474 | return GNUNET_YES; | ||
475 | } | ||
476 | |||
477 | |||
478 | /** | ||
479 | * Discard peer entries for greylisted peers | ||
480 | * where the greylisting has expired. | ||
481 | * | ||
482 | * @param cls 'struct Peer' to greylist | ||
483 | * @param tc scheduler context | ||
484 | */ | ||
485 | static void | ||
486 | remove_from_greylist (void *cls, | ||
487 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
488 | |||
489 | |||
490 | /** | ||
387 | * Try to connect to the specified peer. | 491 | * Try to connect to the specified peer. |
388 | * | 492 | * |
389 | * @param pos peer to connect to | 493 | * @param pos peer to connect to |
390 | */ | 494 | */ |
391 | static void | 495 | static void |
392 | attempt_connect (struct PeerList *pos) | 496 | attempt_connect (struct Peer *pos) |
393 | { | 497 | { |
498 | struct GNUNET_TIME_Relative rem; | ||
499 | |||
500 | if ( (connection_count >= target_connection_count) && | ||
501 | (friend_count >= minimum_friend_count) ) | ||
502 | return; | ||
503 | if (GNUNET_YES == pos->is_connected) | ||
504 | return; | ||
505 | if (GNUNET_OK != is_connection_allowed (pos)) | ||
506 | return; | ||
507 | if (GNUNET_YES == pos->is_blocked) | ||
508 | return; | ||
509 | if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value > 0) | ||
510 | return; | ||
394 | if (GNUNET_YES == pos->is_friend) | 511 | if (GNUNET_YES == pos->is_friend) |
395 | pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND); | 512 | rem = GREYLIST_AFTER_ATTEMPT_FRIEND; |
396 | else | 513 | else |
397 | pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT); | 514 | rem = GREYLIST_AFTER_ATTEMPT; |
515 | /* FIXME: do exponential back-off? */ | ||
516 | pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem); | ||
517 | if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) | ||
518 | GNUNET_SCHEDULER_cancel (sched, | ||
519 | pos->greylist_clean_task); | ||
520 | pos->greylist_clean_task | ||
521 | = GNUNET_SCHEDULER_add_delayed (sched, | ||
522 | rem, | ||
523 | &remove_from_greylist, | ||
524 | pos); | ||
398 | #if DEBUG_TOPOLOGY | 525 | #if DEBUG_TOPOLOGY |
399 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 526 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
400 | "Asking core to connect to `%s'\n", | 527 | "Asking to connect to `%s'\n", |
401 | GNUNET_i2s (&pos->id)); | 528 | GNUNET_i2s (&pos->pid)); |
402 | #endif | 529 | #endif |
403 | GNUNET_STATISTICS_update (stats, | 530 | GNUNET_STATISTICS_update (stats, |
404 | gettext_noop ("# connect requests issued to core"), | 531 | gettext_noop ("# connect requests issued to core"), |
@@ -406,59 +533,47 @@ attempt_connect (struct PeerList *pos) | |||
406 | GNUNET_NO); | 533 | GNUNET_NO); |
407 | pos->connect_req = GNUNET_CORE_peer_request_connect (sched, cfg, | 534 | pos->connect_req = GNUNET_CORE_peer_request_connect (sched, cfg, |
408 | GNUNET_TIME_UNIT_MINUTES, | 535 | GNUNET_TIME_UNIT_MINUTES, |
409 | &pos->id, | 536 | &pos->pid, |
410 | &connect_completed_callback, | 537 | &connect_completed_callback, |
411 | pos); | 538 | pos); |
412 | } | 539 | } |
413 | 540 | ||
414 | 541 | ||
415 | /** | 542 | /** |
416 | * Find a peer in our linked list. | 543 | * Discard peer entries for greylisted peers |
417 | * FIXME: should probably use a hash map instead. | 544 | * where the greylisting has expired. |
545 | * | ||
546 | * @param cls 'struct Peer' to greylist | ||
547 | * @param tc scheduler context | ||
418 | */ | 548 | */ |
419 | struct PeerList * | 549 | static void |
420 | find_peer (const struct GNUNET_PeerIdentity * peer) | 550 | remove_from_greylist (void *cls, |
551 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
421 | { | 552 | { |
422 | struct PeerList *pos; | 553 | struct Peer *pos = cls; |
554 | struct GNUNET_TIME_Relative rem; | ||
423 | 555 | ||
424 | pos = peers; | 556 | pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK; |
425 | while (pos != NULL) | 557 | rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until); |
558 | if (rem.value == 0) | ||
426 | { | 559 | { |
427 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) | 560 | attempt_connect (pos); |
428 | return pos; | ||
429 | pos = pos->next; | ||
430 | } | 561 | } |
431 | return NULL; | 562 | else |
432 | } | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Check if an additional connection from the given peer is allowed. | ||
437 | */ | ||
438 | static int | ||
439 | is_connection_allowed (struct PeerList *peer) | ||
440 | { | ||
441 | if (0 == memcmp (&my_identity, &peer->id, sizeof (struct GNUNET_PeerIdentity))) | ||
442 | return GNUNET_SYSERR; /* disallow connections to self */ | ||
443 | if (peer->is_friend) | ||
444 | return GNUNET_OK; | ||
445 | if (GNUNET_YES == friends_only) | ||
446 | { | 563 | { |
447 | #if DEBUG_TOPOLOGY | 564 | pos->greylist_clean_task |
448 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 565 | = GNUNET_SCHEDULER_add_delayed (sched, |
449 | "Determined that `%s' is not allowed to connect (not a friend)\n", | 566 | rem, |
450 | GNUNET_i2s (&peer->id)); | 567 | &remove_from_greylist, |
451 | #endif | 568 | pos); |
452 | return GNUNET_SYSERR; | 569 | } |
570 | if ( (GNUNET_NO == pos->is_friend) && | ||
571 | (GNUNET_NO == pos->is_blocked) && | ||
572 | (GNUNET_NO == pos->is_connected) ) | ||
573 | { | ||
574 | free_peer (NULL, &pos->pid.hashPubKey, pos); | ||
575 | return; | ||
453 | } | 576 | } |
454 | if (friend_count >= minimum_friend_count) | ||
455 | return GNUNET_OK; | ||
456 | #if DEBUG_TOPOLOGY | ||
457 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
458 | "Determined that `%s' is not allowed to connect (not enough connected friends)\n", | ||
459 | GNUNET_i2s (&peer->id)); | ||
460 | #endif | ||
461 | return GNUNET_SYSERR; | ||
462 | } | 577 | } |
463 | 578 | ||
464 | 579 | ||
@@ -470,16 +585,16 @@ is_connection_allowed (struct PeerList *peer) | |||
470 | * @param is_friend is the new entry for a friend? | 585 | * @param is_friend is the new entry for a friend? |
471 | * @return the new entry | 586 | * @return the new entry |
472 | */ | 587 | */ |
473 | static struct PeerList * | 588 | static struct Peer * |
474 | make_peer (const struct | 589 | make_peer (const struct |
475 | GNUNET_PeerIdentity * peer, | 590 | GNUNET_PeerIdentity * peer, |
476 | const struct GNUNET_HELLO_Message *hello, | 591 | const struct GNUNET_HELLO_Message *hello, |
477 | int is_friend) | 592 | int is_friend) |
478 | { | 593 | { |
479 | struct PeerList *ret; | 594 | struct Peer *ret; |
480 | 595 | ||
481 | ret = GNUNET_malloc (sizeof (struct PeerList)); | 596 | ret = GNUNET_malloc (sizeof (struct Peer)); |
482 | ret->id = *peer; | 597 | ret->pid = *peer; |
483 | ret->is_friend = is_friend; | 598 | ret->is_friend = is_friend; |
484 | if (hello != NULL) | 599 | if (hello != NULL) |
485 | { | 600 | { |
@@ -487,58 +602,21 @@ make_peer (const struct | |||
487 | memcpy (ret->hello, hello, | 602 | memcpy (ret->hello, hello, |
488 | GNUNET_HELLO_size (hello)); | 603 | GNUNET_HELLO_size (hello)); |
489 | } | 604 | } |
490 | ret->next = peers; | 605 | GNUNET_CONTAINER_multihashmap_put (peers, |
491 | peers = ret; | 606 | &peer->hashPubKey, |
607 | ret, | ||
608 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
492 | return ret; | 609 | return ret; |
493 | } | 610 | } |
494 | 611 | ||
495 | 612 | ||
496 | /** | 613 | /** |
497 | * Free all resources associated with the given peer. | ||
498 | * | ||
499 | * @param peer peer to free | ||
500 | */ | ||
501 | static void | ||
502 | free_peer (struct PeerList *peer) | ||
503 | { | ||
504 | struct PeerList *pos; | ||
505 | struct PeerList *prev; | ||
506 | |||
507 | prev = NULL; | ||
508 | pos = peers; | ||
509 | while (peer != pos) | ||
510 | { | ||
511 | prev = pos; | ||
512 | pos = pos->next; | ||
513 | } | ||
514 | GNUNET_assert (pos != NULL); | ||
515 | if (prev == NULL) | ||
516 | peers = pos->next; | ||
517 | else | ||
518 | prev->next = pos->next; | ||
519 | if (pos->hello_req != NULL) | ||
520 | GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); | ||
521 | if (pos->wh != NULL) | ||
522 | GNUNET_TRANSPORT_blacklist_cancel (pos->wh); | ||
523 | if (pos->connect_req != NULL) | ||
524 | GNUNET_CORE_peer_request_connect_cancel (pos->connect_req); | ||
525 | if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
526 | GNUNET_SCHEDULER_cancel (sched, | ||
527 | pos->hello_delay_task); | ||
528 | GNUNET_free_non_null (pos->hello); | ||
529 | if (pos->filter != NULL) | ||
530 | GNUNET_CONTAINER_bloomfilter_free (peer->filter); | ||
531 | GNUNET_free (pos); | ||
532 | } | ||
533 | |||
534 | |||
535 | /** | ||
536 | * Setup bloom filter for the given peer entry. | 614 | * Setup bloom filter for the given peer entry. |
537 | * | 615 | * |
538 | * @param peer entry to initialize | 616 | * @param peer entry to initialize |
539 | */ | 617 | */ |
540 | static void | 618 | static void |
541 | setup_filter (struct PeerList *peer) | 619 | setup_filter (struct Peer *peer) |
542 | { | 620 | { |
543 | /* 2^{-5} chance of not sending a HELLO to a peer is | 621 | /* 2^{-5} chance of not sending a HELLO to a peer is |
544 | acceptably small (if the filter is 50% full); | 622 | acceptably small (if the filter is 50% full); |
@@ -550,14 +628,14 @@ setup_filter (struct PeerList *peer) | |||
550 | peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5); | 628 | peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5); |
551 | peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); | 629 | peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); |
552 | /* never send a peer its own HELLO */ | 630 | /* never send a peer its own HELLO */ |
553 | GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->id.hashPubKey); | 631 | GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey); |
554 | } | 632 | } |
555 | 633 | ||
556 | 634 | ||
557 | /** | 635 | /** |
558 | * Function to fill send buffer with HELLO. | 636 | * Function to fill send buffer with HELLO. |
559 | * | 637 | * |
560 | * @param cls 'struct PeerList' of the target peer | 638 | * @param cls 'struct Peer' of the target peer |
561 | * @param size number of bytes available in buf | 639 | * @param size number of bytes available in buf |
562 | * @param buf where the callee should write the message | 640 | * @param buf where the callee should write the message |
563 | * @return number of bytes written to buf | 641 | * @return number of bytes written to buf |
@@ -568,6 +646,74 @@ hello_advertising_ready (void *cls, | |||
568 | void *buf); | 646 | void *buf); |
569 | 647 | ||
570 | 648 | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Closure for 'find_advertisable_hello'. | ||
653 | */ | ||
654 | struct FindAdvHelloContext { | ||
655 | |||
656 | /** | ||
657 | * Peer we want to advertise to. | ||
658 | */ | ||
659 | struct Peer *peer; | ||
660 | |||
661 | /** | ||
662 | * Where to store the result (peer selected for advertising). | ||
663 | */ | ||
664 | struct Peer *result; | ||
665 | |||
666 | /** | ||
667 | * Maximum HELLO size we can use right now. | ||
668 | */ | ||
669 | size_t max_size; | ||
670 | |||
671 | struct GNUNET_TIME_Relative next_adv; | ||
672 | }; | ||
673 | |||
674 | |||
675 | /** | ||
676 | * Find a peer that would be reasonable for advertising. | ||
677 | * | ||
678 | * @param cls closure | ||
679 | * @param pid identity of a peer | ||
680 | * @param value 'struct Peer*' for the peer we are considering | ||
681 | * @return GNUNET_YES (continue iteration) | ||
682 | */ | ||
683 | static int | ||
684 | find_advertisable_hello (void *cls, | ||
685 | const GNUNET_HashCode *pid, | ||
686 | void *value) | ||
687 | { | ||
688 | struct FindAdvHelloContext *fah = cls; | ||
689 | struct Peer *pos = value; | ||
690 | struct GNUNET_TIME_Relative rst_time; | ||
691 | size_t hs; | ||
692 | |||
693 | if (pos == fah->peer) | ||
694 | return GNUNET_YES; | ||
695 | if (pos->hello == NULL) | ||
696 | return GNUNET_YES; | ||
697 | rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); | ||
698 | if (0 == rst_time.value) | ||
699 | { | ||
700 | /* time to discard... */ | ||
701 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | ||
702 | setup_filter (pos); | ||
703 | } | ||
704 | fah->next_adv = GNUNET_TIME_relative_min (rst_time, | ||
705 | fah->next_adv); | ||
706 | hs = GNUNET_HELLO_size (pos->hello); | ||
707 | if (hs > fah->max_size) | ||
708 | return GNUNET_YES; | ||
709 | if (GNUNET_NO == | ||
710 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | ||
711 | &fah->peer->pid.hashPubKey)) | ||
712 | fah->result = pos; | ||
713 | return GNUNET_YES; | ||
714 | } | ||
715 | |||
716 | |||
571 | /** | 717 | /** |
572 | * Calculate when we would like to send the next HELLO to this | 718 | * Calculate when we would like to send the next HELLO to this |
573 | * peer and ask for it. | 719 | * peer and ask for it. |
@@ -579,62 +725,44 @@ static void | |||
579 | schedule_next_hello (void *cls, | 725 | schedule_next_hello (void *cls, |
580 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 726 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
581 | { | 727 | { |
582 | struct PeerList *pl = cls; | 728 | struct Peer *pl = cls; |
583 | struct PeerList *pos; | 729 | struct FindAdvHelloContext fah; |
584 | struct PeerList *next; | 730 | size_t next_want; |
585 | uint16_t next_want; | 731 | struct GNUNET_TIME_Relative delay; |
586 | struct GNUNET_TIME_Relative next_adv; | 732 | |
587 | struct GNUNET_TIME_Relative rst_time; | ||
588 | |||
589 | pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; | 733 | pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; |
590 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 734 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
591 | return; /* we're out of here */ | 735 | return; /* we're out of here */ |
592 | next_want = 0; | 736 | if (pl->hello_req != NULL) |
593 | next_adv = GNUNET_TIME_UNIT_FOREVER_REL; | 737 | return; /* did not finish sending the previous one */ |
594 | /* find applicable HELLOs */ | 738 | /* find applicable HELLOs */ |
595 | next = peers; | 739 | fah.peer = pl; |
596 | while (NULL != (pos = next)) | 740 | fah.result = NULL; |
597 | { | 741 | fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE; |
598 | next = pos->next; | 742 | fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; |
599 | if (pos->hello == NULL) | 743 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
600 | continue; | 744 | &find_advertisable_hello, |
601 | rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); | 745 | &fah); |
602 | if (0 == rst_time.value) | 746 | pl->hello_delay_task |
603 | { | 747 | = GNUNET_SCHEDULER_add_delayed (sched, |
604 | /* time to discard... */ | 748 | fah.next_adv, |
605 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | 749 | &schedule_next_hello, |
606 | setup_filter (pos); | 750 | pl); |
607 | } | 751 | if (fah.result == NULL) |
608 | else | 752 | return; |
609 | { | 753 | next_want = GNUNET_HELLO_size (fah.result->hello); |
610 | if (rst_time.value < next_adv.value) | 754 | delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); |
611 | next_want = GNUNET_HELLO_size (pos->hello); | 755 | if (delay.value == 0) |
612 | next_adv = GNUNET_TIME_relative_min (rst_time, | ||
613 | next_adv); | ||
614 | } | ||
615 | if (GNUNET_NO == | ||
616 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | ||
617 | &pl->id.hashPubKey)) | ||
618 | break; | ||
619 | } | ||
620 | if (pos != NULL) | ||
621 | next_adv = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); | ||
622 | if (next_adv.value == 0) | ||
623 | { | 756 | { |
624 | /* now! */ | 757 | /* now! */ |
625 | pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0, | 758 | pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0, |
626 | next_adv, | 759 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, |
627 | &pl->id, | 760 | &pl->pid, |
628 | next_want, | 761 | next_want, |
629 | &hello_advertising_ready, | 762 | &hello_advertising_ready, |
630 | pl); | 763 | pl); |
631 | return; | 764 | return; |
632 | } | 765 | } |
633 | pl->hello_delay_task | ||
634 | = GNUNET_SCHEDULER_add_delayed (sched, | ||
635 | next_adv, | ||
636 | &schedule_next_hello, | ||
637 | pl); | ||
638 | } | 766 | } |
639 | 767 | ||
640 | 768 | ||
@@ -642,25 +770,40 @@ schedule_next_hello (void *cls, | |||
642 | * Cancel existing requests for sending HELLOs to this peer | 770 | * Cancel existing requests for sending HELLOs to this peer |
643 | * and recalculate when we should send HELLOs to it based | 771 | * and recalculate when we should send HELLOs to it based |
644 | * on our current state (something changed!). | 772 | * on our current state (something changed!). |
773 | * | ||
774 | * @param cls closure, 'struct Peer' to skip, or NULL | ||
775 | * @param pid identity of a peer | ||
776 | * @param value 'struct Peer*' for the peer | ||
777 | * @return GNUNET_YES (always) | ||
645 | */ | 778 | */ |
646 | static void | 779 | static int |
647 | reschedule_hellos (struct PeerList *peer) | 780 | reschedule_hellos (void *cls, |
781 | const GNUNET_HashCode *pid, | ||
782 | void *value) | ||
648 | { | 783 | { |
784 | struct Peer *peer = value; | ||
785 | struct Peer *skip = cls; | ||
786 | |||
787 | if (skip == peer) | ||
788 | return GNUNET_YES; | ||
789 | if (! peer->is_connected) | ||
790 | return GNUNET_YES; | ||
649 | if (peer->hello_req != NULL) | 791 | if (peer->hello_req != NULL) |
650 | { | 792 | { |
651 | GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req); | 793 | GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req); |
652 | peer->hello_req = NULL; | 794 | peer->hello_req = NULL; |
653 | } | 795 | } |
654 | if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) | 796 | if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) |
655 | { | 797 | { |
656 | GNUNET_SCHEDULER_cancel (sched, | 798 | GNUNET_SCHEDULER_cancel (sched, |
657 | peer->hello_delay_task); | 799 | peer->hello_delay_task); |
658 | peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; | 800 | peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; |
659 | } | 801 | } |
660 | peer->hello_delay_task | 802 | peer->hello_delay_task |
661 | = GNUNET_SCHEDULER_add_now (sched, | 803 | = GNUNET_SCHEDULER_add_now (sched, |
662 | &schedule_next_hello, | 804 | &schedule_next_hello, |
663 | peer); | 805 | peer); |
806 | return GNUNET_YES; | ||
664 | } | 807 | } |
665 | 808 | ||
666 | 809 | ||
@@ -679,7 +822,7 @@ connect_notify (void *cls, | |||
679 | struct GNUNET_TIME_Relative latency, | 822 | struct GNUNET_TIME_Relative latency, |
680 | uint32_t distance) | 823 | uint32_t distance) |
681 | { | 824 | { |
682 | struct PeerList *pos; | 825 | struct Peer *pos; |
683 | 826 | ||
684 | #if DEBUG_TOPOLOGY | 827 | #if DEBUG_TOPOLOGY |
685 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -691,7 +834,7 @@ connect_notify (void *cls, | |||
691 | gettext_noop ("# peers connected"), | 834 | gettext_noop ("# peers connected"), |
692 | connection_count, | 835 | connection_count, |
693 | GNUNET_NO); | 836 | GNUNET_NO); |
694 | pos = find_peer (peer); | 837 | pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); |
695 | if (pos == NULL) | 838 | if (pos == NULL) |
696 | { | 839 | { |
697 | pos = make_peer (peer, NULL, GNUNET_NO); | 840 | pos = make_peer (peer, NULL, GNUNET_NO); |
@@ -711,7 +854,7 @@ connect_notify (void *cls, | |||
711 | else | 854 | else |
712 | { | 855 | { |
713 | GNUNET_assert (GNUNET_NO == pos->is_connected); | 856 | GNUNET_assert (GNUNET_NO == pos->is_connected); |
714 | pos->blacklisted_until.value = 0; /* remove blacklisting */ | 857 | pos->greylisted_until.value = 0; /* remove greylisting */ |
715 | } | 858 | } |
716 | pos->is_connected = GNUNET_YES; | 859 | pos->is_connected = GNUNET_YES; |
717 | if (pos->is_friend) | 860 | if (pos->is_friend) |
@@ -725,54 +868,56 @@ connect_notify (void *cls, | |||
725 | connection_count, | 868 | connection_count, |
726 | GNUNET_NO); | 869 | GNUNET_NO); |
727 | } | 870 | } |
728 | reschedule_hellos (pos); | 871 | reschedule_hellos (NULL, &peer->hashPubKey, pos); |
729 | } | 872 | } |
730 | 873 | ||
731 | 874 | ||
732 | /** | 875 | /** |
733 | * Disconnect from all non-friends (we're below quota). | 876 | * Disconnect from all non-friends (we're below quota). |
877 | * | ||
878 | * @param cls closure, not used | ||
879 | * @param pid identity of a peer | ||
880 | * @param value 'struct Peer*' for the peer | ||
881 | * @return GNUNET_YES (continue to iterate) | ||
734 | */ | 882 | */ |
735 | static void | 883 | static int |
736 | drop_non_friends () | 884 | drop_non_friends (void *cls, |
885 | const GNUNET_HashCode *pid, | ||
886 | void *value) | ||
737 | { | 887 | { |
738 | struct PeerList *pos; | 888 | struct Peer *pos = value; |
739 | 889 | ||
740 | pos = peers; | 890 | if ( (GNUNET_NO == pos->is_friend) && |
741 | while (pos != NULL) | 891 | (GNUNET_YES == pos->is_connected) ) |
742 | { | 892 | { |
743 | if ( (GNUNET_NO == pos->is_friend) && | ||
744 | (GNUNET_YES == pos->is_connected) ) | ||
745 | { | ||
746 | #if DEBUG_TOPOLOGY | 893 | #if DEBUG_TOPOLOGY |
747 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 894 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
748 | "Connection to `%s' is not from a friend, forcing disconnect!\n", | 895 | "Connection to `%s' is not from a friend, forcing disconnect!\n", |
749 | GNUNET_i2s (&pos->id)); | 896 | GNUNET_i2s (&pos->pid)); |
750 | #endif | 897 | #endif |
751 | force_disconnect (pos); | 898 | force_disconnect (pos); |
752 | } | ||
753 | pos = pos->next; | ||
754 | } | 899 | } |
900 | return GNUNET_YES; | ||
755 | } | 901 | } |
756 | 902 | ||
757 | 903 | ||
758 | /** | 904 | /** |
759 | * Try to add more peers to our connection set. | 905 | * Try to add more peers to our connection set. |
906 | * | ||
907 | * @param cls closure, not used | ||
908 | * @param pid identity of a peer | ||
909 | * @param value 'struct Peer*' for the peer | ||
910 | * @return GNUNET_YES (continue to iterate) | ||
760 | */ | 911 | */ |
761 | static void | 912 | static int |
762 | try_add_peers () | 913 | try_add_peers (void *cls, |
914 | const GNUNET_HashCode *pid, | ||
915 | void *value) | ||
763 | { | 916 | { |
764 | struct PeerList *pos; | 917 | struct Peer *pos = value; |
765 | 918 | ||
766 | pos = peers; | 919 | attempt_connect (pos); |
767 | while (pos != NULL) | 920 | return GNUNET_YES; |
768 | { | ||
769 | if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) && | ||
770 | ( (GNUNET_YES == pos->is_friend) || | ||
771 | (friend_count >= minimum_friend_count) ) && | ||
772 | (GNUNET_YES != pos->is_connected) ) | ||
773 | attempt_connect (pos); | ||
774 | pos = pos->next; | ||
775 | } | ||
776 | } | 921 | } |
777 | 922 | ||
778 | 923 | ||
@@ -787,14 +932,15 @@ disconnect_notify (void *cls, | |||
787 | const struct | 932 | const struct |
788 | GNUNET_PeerIdentity * peer) | 933 | GNUNET_PeerIdentity * peer) |
789 | { | 934 | { |
790 | struct PeerList *pos; | 935 | struct Peer *pos; |
791 | 936 | ||
792 | #if DEBUG_TOPOLOGY | 937 | #if DEBUG_TOPOLOGY |
793 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 938 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
794 | "Core told us that we disconnected from `%s'\n", | 939 | "Core told us that we disconnected from `%s'\n", |
795 | GNUNET_i2s (peer)); | 940 | GNUNET_i2s (peer)); |
796 | #endif | 941 | #endif |
797 | pos = find_peer (peer); | 942 | pos = GNUNET_CONTAINER_multihashmap_get (peers, |
943 | &peer->hashPubKey); | ||
798 | if (pos == NULL) | 944 | if (pos == NULL) |
799 | { | 945 | { |
800 | GNUNET_break (0); | 946 | GNUNET_break (0); |
@@ -820,7 +966,9 @@ disconnect_notify (void *cls, | |||
820 | } | 966 | } |
821 | if ( (connection_count < target_connection_count) || | 967 | if ( (connection_count < target_connection_count) || |
822 | (friend_count < minimum_friend_count) ) | 968 | (friend_count < minimum_friend_count) ) |
823 | try_add_peers (); | 969 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
970 | &try_add_peers, | ||
971 | NULL); | ||
824 | if (friend_count < minimum_friend_count) | 972 | if (friend_count < minimum_friend_count) |
825 | { | 973 | { |
826 | /* disconnect from all non-friends */ | 974 | /* disconnect from all non-friends */ |
@@ -828,7 +976,9 @@ disconnect_notify (void *cls, | |||
828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 976 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
829 | "Not enough friendly connections, dropping all non-friend connections\n"); | 977 | "Not enough friendly connections, dropping all non-friend connections\n"); |
830 | #endif | 978 | #endif |
831 | drop_non_friends (); | 979 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
980 | &drop_non_friends, | ||
981 | NULL); | ||
832 | } | 982 | } |
833 | } | 983 | } |
834 | 984 | ||
@@ -858,14 +1008,15 @@ address_iterator (void *cls, | |||
858 | /** | 1008 | /** |
859 | * We've gotten a HELLO from another peer. Consider it for | 1009 | * We've gotten a HELLO from another peer. Consider it for |
860 | * advertising. | 1010 | * advertising. |
1011 | * | ||
1012 | * @param hello the HELLO we got | ||
861 | */ | 1013 | */ |
862 | static void | 1014 | static void |
863 | consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | 1015 | consider_for_advertising (const struct GNUNET_HELLO_Message *hello) |
864 | { | 1016 | { |
865 | int have_address; | 1017 | int have_address; |
866 | struct GNUNET_PeerIdentity pid; | 1018 | struct GNUNET_PeerIdentity pid; |
867 | struct PeerList *peer; | 1019 | struct Peer *peer; |
868 | struct PeerList *pos; | ||
869 | uint16_t size; | 1020 | uint16_t size; |
870 | 1021 | ||
871 | GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid)); | 1022 | GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid)); |
@@ -880,7 +1031,8 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | |||
880 | &have_address); | 1031 | &have_address); |
881 | if (GNUNET_NO == have_address) | 1032 | if (GNUNET_NO == have_address) |
882 | return; /* no point in advertising this one... */ | 1033 | return; /* no point in advertising this one... */ |
883 | peer = find_peer (&pid); | 1034 | peer = GNUNET_CONTAINER_multihashmap_get (peers, |
1035 | &pid.hashPubKey); | ||
884 | if (peer == NULL) | 1036 | if (peer == NULL) |
885 | peer = make_peer (&pid, hello, GNUNET_NO); | 1037 | peer = make_peer (&pid, hello, GNUNET_NO); |
886 | #if DEBUG_TOPOLOGY | 1038 | #if DEBUG_TOPOLOGY |
@@ -898,23 +1050,20 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello) | |||
898 | setup_filter (peer); | 1050 | setup_filter (peer); |
899 | /* since we have a new HELLO to pick from, re-schedule all | 1051 | /* since we have a new HELLO to pick from, re-schedule all |
900 | HELLO requests that are not bound by the HELLO send rate! */ | 1052 | HELLO requests that are not bound by the HELLO send rate! */ |
901 | pos = peers; | 1053 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
902 | while (NULL != pos) | 1054 | &reschedule_hellos, |
903 | { | 1055 | peer); |
904 | if (pos != peer) | ||
905 | { | ||
906 | if ( (pos->is_connected) && | ||
907 | (GNUNET_TIME_absolute_get_remaining (pos->next_hello_allowed).value <= HELLO_ADVERTISEMENT_MIN_FREQUENCY.value) ) | ||
908 | reschedule_hellos (pos); | ||
909 | } | ||
910 | pos = pos->next; | ||
911 | } | ||
912 | } | 1056 | } |
913 | 1057 | ||
914 | 1058 | ||
915 | /** | 1059 | /** |
916 | * Peerinfo calls this function to let us know about a possible peer | 1060 | * PEERINFO calls this function to let us know about a possible peer |
917 | * that we might want to connect to. | 1061 | * that we might want to connect to. |
1062 | * | ||
1063 | * @param cls closure (not used) | ||
1064 | * @param peer potential peer to connect to | ||
1065 | * @param hello HELLO for this peer (or NULL) | ||
1066 | * @param trust how much we trust the peer (not used) | ||
918 | */ | 1067 | */ |
919 | static void | 1068 | static void |
920 | process_peer (void *cls, | 1069 | process_peer (void *cls, |
@@ -922,7 +1071,7 @@ process_peer (void *cls, | |||
922 | const struct GNUNET_HELLO_Message *hello, | 1071 | const struct GNUNET_HELLO_Message *hello, |
923 | uint32_t trust) | 1072 | uint32_t trust) |
924 | { | 1073 | { |
925 | struct PeerList *pos; | 1074 | struct Peer *pos; |
926 | 1075 | ||
927 | GNUNET_assert (peer != NULL); | 1076 | GNUNET_assert (peer != NULL); |
928 | if (0 == memcmp (&my_identity, | 1077 | if (0 == memcmp (&my_identity, |
@@ -931,7 +1080,9 @@ process_peer (void *cls, | |||
931 | if (hello == NULL) | 1080 | if (hello == NULL) |
932 | { | 1081 | { |
933 | /* free existing HELLO, if any */ | 1082 | /* free existing HELLO, if any */ |
934 | if (NULL != (pos = find_peer (peer))) | 1083 | pos = GNUNET_CONTAINER_multihashmap_get (peers, |
1084 | &peer->hashPubKey); | ||
1085 | if (NULL != pos) | ||
935 | { | 1086 | { |
936 | GNUNET_free_non_null (pos->hello); | 1087 | GNUNET_free_non_null (pos->hello); |
937 | pos->hello = NULL; | 1088 | pos->hello = NULL; |
@@ -942,21 +1093,17 @@ process_peer (void *cls, | |||
942 | } | 1093 | } |
943 | if ( (! pos->is_connected) && | 1094 | if ( (! pos->is_connected) && |
944 | (! pos->is_friend) && | 1095 | (! pos->is_friend) && |
945 | (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) | 1096 | (0 == GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value) ) |
946 | free_peer (pos); | 1097 | free_peer (NULL, &pos->pid.hashPubKey, pos); |
947 | } | 1098 | } |
948 | return; | 1099 | return; |
949 | } | 1100 | } |
950 | consider_for_advertising (hello); | 1101 | consider_for_advertising (hello); |
951 | pos = find_peer (peer); | 1102 | pos = GNUNET_CONTAINER_multihashmap_get (peers, |
1103 | &peer->hashPubKey); | ||
952 | if (pos == NULL) | 1104 | if (pos == NULL) |
953 | pos = make_peer (peer, hello, GNUNET_NO); | 1105 | pos = make_peer (peer, hello, GNUNET_NO); |
954 | GNUNET_assert (NULL != pos); | 1106 | GNUNET_assert (NULL != pos); |
955 | #if DEBUG_TOPOLOGY | ||
956 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
957 | "Considering connecting to peer `%s'\n", | ||
958 | GNUNET_i2s (peer)); | ||
959 | #endif | ||
960 | if (GNUNET_YES == pos->is_connected) | 1107 | if (GNUNET_YES == pos->is_connected) |
961 | { | 1108 | { |
962 | #if DEBUG_TOPOLOGY | 1109 | #if DEBUG_TOPOLOGY |
@@ -966,49 +1113,21 @@ process_peer (void *cls, | |||
966 | #endif | 1113 | #endif |
967 | return; | 1114 | return; |
968 | } | 1115 | } |
969 | if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0) | 1116 | if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value > 0) |
970 | { | 1117 | { |
971 | #if DEBUG_TOPOLOGY | 1118 | #if DEBUG_TOPOLOGY |
972 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1119 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
973 | "Already tried peer `%s' recently\n", | 1120 | "Already tried peer `%s' recently\n", |
974 | GNUNET_i2s (peer)); | 1121 | GNUNET_i2s (peer)); |
975 | #endif | 1122 | #endif |
976 | return; /* peer still blacklisted */ | 1123 | return; /* peer still greylisted */ |
977 | } | 1124 | } |
978 | if ( (GNUNET_YES == pos->is_friend) || | 1125 | #if DEBUG_TOPOLOGY |
979 | (GNUNET_YES != friends_only) || | 1126 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
980 | (friend_count >= minimum_friend_count) ) | 1127 | "Considering connecting to peer `%s'\n", |
981 | attempt_connect (pos); | 1128 | GNUNET_i2s (peer)); |
982 | } | 1129 | #endif |
983 | 1130 | attempt_connect (pos); | |
984 | |||
985 | /** | ||
986 | * Discard peer entries for blacklisted peers | ||
987 | * where the blacklisting has expired. | ||
988 | */ | ||
989 | static void | ||
990 | discard_old_blacklist_entries (void *cls, | ||
991 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
992 | { | ||
993 | struct PeerList *pos; | ||
994 | struct PeerList *next; | ||
995 | |||
996 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
997 | return; | ||
998 | next = peers; | ||
999 | while (NULL != (pos = next)) | ||
1000 | { | ||
1001 | next = pos->next; | ||
1002 | if ( (GNUNET_NO == pos->is_friend) && | ||
1003 | (GNUNET_NO == pos->is_connected) && | ||
1004 | (GNUNET_NO == pos->is_blocked) && | ||
1005 | (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) | ||
1006 | free_peer (pos); | ||
1007 | } | ||
1008 | GNUNET_SCHEDULER_add_delayed (sched, | ||
1009 | BLACKLIST_AFTER_ATTEMPT, | ||
1010 | &discard_old_blacklist_entries, | ||
1011 | NULL); | ||
1012 | } | 1131 | } |
1013 | 1132 | ||
1014 | 1133 | ||
@@ -1044,10 +1163,6 @@ core_init (void *cls, | |||
1044 | "I am peer `%s'\n", | 1163 | "I am peer `%s'\n", |
1045 | GNUNET_i2s (my_id)); | 1164 | GNUNET_i2s (my_id)); |
1046 | #endif | 1165 | #endif |
1047 | GNUNET_SCHEDULER_add_delayed (sched, | ||
1048 | BLACKLIST_AFTER_ATTEMPT, | ||
1049 | &discard_old_blacklist_entries, | ||
1050 | NULL); | ||
1051 | peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched, | 1166 | peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched, |
1052 | &process_peer, | 1167 | &process_peer, |
1053 | NULL); | 1168 | NULL); |
@@ -1067,7 +1182,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1067 | struct stat frstat; | 1182 | struct stat frstat; |
1068 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; | 1183 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; |
1069 | unsigned int entries_found; | 1184 | unsigned int entries_found; |
1070 | struct PeerList *fl; | 1185 | struct Peer *fl; |
1071 | 1186 | ||
1072 | if (GNUNET_OK != | 1187 | if (GNUNET_OK != |
1073 | GNUNET_CONFIGURATION_get_value_filename (cfg, | 1188 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
@@ -1150,7 +1265,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1150 | GNUNET_YES); | 1265 | GNUNET_YES); |
1151 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1266 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1152 | _("Found friend `%s' in configuration\n"), | 1267 | _("Found friend `%s' in configuration\n"), |
1153 | GNUNET_i2s (&fl->id)); | 1268 | GNUNET_i2s (&fl->pid)); |
1154 | } | 1269 | } |
1155 | else | 1270 | else |
1156 | { | 1271 | { |
@@ -1205,16 +1320,35 @@ handle_encrypted_hello (void *cls, | |||
1205 | struct GNUNET_TIME_Relative latency, | 1320 | struct GNUNET_TIME_Relative latency, |
1206 | uint32_t distance) | 1321 | uint32_t distance) |
1207 | { | 1322 | { |
1323 | struct Peer *peer; | ||
1324 | struct GNUNET_PeerIdentity pid; | ||
1325 | |||
1208 | #if DEBUG_TOPOLOGY | 1326 | #if DEBUG_TOPOLOGY |
1209 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1210 | "Received encrypted `%s' from peer `%s'", | 1328 | "Received encrypted `%s' from peer `%s'", |
1211 | "HELLO", | 1329 | "HELLO", |
1212 | GNUNET_i2s (other)); | 1330 | GNUNET_i2s (other)); |
1213 | #endif | 1331 | #endif |
1332 | if (GNUNET_OK != | ||
1333 | GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message*) message, | ||
1334 | &pid)) | ||
1335 | { | ||
1336 | GNUNET_break_op (0); | ||
1337 | return GNUNET_SYSERR; | ||
1338 | } | ||
1214 | GNUNET_STATISTICS_update (stats, | 1339 | GNUNET_STATISTICS_update (stats, |
1215 | gettext_noop ("# HELLO messages received"), | 1340 | gettext_noop ("# HELLO messages received"), |
1216 | 1, | 1341 | 1, |
1217 | GNUNET_NO); | 1342 | GNUNET_NO); |
1343 | peer = GNUNET_CONTAINER_multihashmap_get (peers, | ||
1344 | &pid.hashPubKey); | ||
1345 | if ( (peer != NULL) && | ||
1346 | (peer->is_blocked) ) | ||
1347 | return GNUNET_OK; /* ignore: currently blocked */ | ||
1348 | if ( (GNUNET_YES == friends_only) && | ||
1349 | ( (peer == NULL) || | ||
1350 | (GNUNET_YES != peer->is_friend) ) ) | ||
1351 | return GNUNET_OK; /* ignore: not a friend */ | ||
1218 | if (transport != NULL) | 1352 | if (transport != NULL) |
1219 | GNUNET_TRANSPORT_offer_hello (transport, | 1353 | GNUNET_TRANSPORT_offer_hello (transport, |
1220 | message); | 1354 | message); |
@@ -1225,7 +1359,7 @@ handle_encrypted_hello (void *cls, | |||
1225 | /** | 1359 | /** |
1226 | * Function to fill send buffer with HELLO. | 1360 | * Function to fill send buffer with HELLO. |
1227 | * | 1361 | * |
1228 | * @param cls 'struct PeerList' of the target peer | 1362 | * @param cls 'struct Peer' of the target peer |
1229 | * @param size number of bytes available in buf | 1363 | * @param size number of bytes available in buf |
1230 | * @param buf where the callee should write the message | 1364 | * @param buf where the callee should write the message |
1231 | * @return number of bytes written to buf | 1365 | * @return number of bytes written to buf |
@@ -1235,58 +1369,37 @@ hello_advertising_ready (void *cls, | |||
1235 | size_t size, | 1369 | size_t size, |
1236 | void *buf) | 1370 | void *buf) |
1237 | { | 1371 | { |
1238 | struct PeerList *pl = cls; | 1372 | struct Peer *pl = cls; |
1239 | struct PeerList *pos; | 1373 | struct FindAdvHelloContext fah; |
1240 | struct PeerList *next; | 1374 | size_t want; |
1241 | uint16_t want; | ||
1242 | size_t hs; | ||
1243 | 1375 | ||
1244 | pl->hello_req = NULL; | 1376 | pl->hello_req = NULL; |
1245 | #if DEBUG_TOPOLOGY | ||
1246 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1247 | "Data solicited for `%s', considering sending `%s'", | ||
1248 | GNUNET_i2s (&pl->id), | ||
1249 | "HELLO"); | ||
1250 | #endif | ||
1251 | /* find applicable HELLOs */ | 1377 | /* find applicable HELLOs */ |
1252 | next = peers; | 1378 | fah.peer = pl; |
1253 | while (NULL != (pos = next)) | 1379 | fah.result = NULL; |
1254 | { | 1380 | fah.max_size = size; |
1255 | next = pos->next; | 1381 | fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; |
1256 | if (pos->hello == NULL) | 1382 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
1257 | continue; | 1383 | &find_advertisable_hello, |
1258 | if (0 == GNUNET_TIME_absolute_get_remaining (pos->filter_expiration).value) | 1384 | &fah); |
1259 | { | ||
1260 | /* time to discard... */ | ||
1261 | GNUNET_CONTAINER_bloomfilter_free (pos->filter); | ||
1262 | setup_filter (pos); | ||
1263 | } | ||
1264 | if (GNUNET_NO == | ||
1265 | GNUNET_CONTAINER_bloomfilter_test (pos->filter, | ||
1266 | &pl->id.hashPubKey)) | ||
1267 | break; | ||
1268 | } | ||
1269 | want = 0; | 1385 | want = 0; |
1270 | if (pos != NULL) | 1386 | if (fah.result != NULL) |
1271 | { | 1387 | { |
1272 | hs = GNUNET_HELLO_size (pos->hello); | 1388 | want = GNUNET_HELLO_size (fah.result->hello); |
1273 | if (hs < size) | 1389 | GNUNET_assert (want <= size); |
1274 | { | 1390 | memcpy (buf, fah.result->hello, want); |
1275 | want = hs; | 1391 | GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, |
1276 | memcpy (buf, pos->hello, want); | 1392 | &pl->pid.hashPubKey); |
1277 | GNUNET_CONTAINER_bloomfilter_add (pos->filter, | ||
1278 | &pl->id.hashPubKey); | ||
1279 | #if DEBUG_TOPOLOGY | 1393 | #if DEBUG_TOPOLOGY |
1280 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1394 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1281 | "Sending %u bytes of `%s's", | 1395 | "Sending `%s' with %u bytes", |
1282 | (unsigned int) want, | 1396 | "HELLO" |
1283 | "HELLO"); | 1397 | (unsigned int) want); |
1284 | #endif | 1398 | #endif |
1285 | GNUNET_STATISTICS_update (stats, | 1399 | GNUNET_STATISTICS_update (stats, |
1286 | gettext_noop ("# HELLO messages gossipped"), | 1400 | gettext_noop ("# HELLO messages gossipped"), |
1287 | 1, | 1401 | 1, |
1288 | GNUNET_NO); | 1402 | GNUNET_NO); |
1289 | } | ||
1290 | } | 1403 | } |
1291 | pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); | 1404 | pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); |
1292 | pl->hello_delay_task | 1405 | pl->hello_delay_task |
@@ -1300,9 +1413,13 @@ hello_advertising_ready (void *cls, | |||
1300 | /** | 1413 | /** |
1301 | * Last task run during shutdown. Disconnects us from | 1414 | * Last task run during shutdown. Disconnects us from |
1302 | * the transport and core. | 1415 | * the transport and core. |
1416 | * | ||
1417 | * @param cls unused, NULL | ||
1418 | * @param tc scheduler context | ||
1303 | */ | 1419 | */ |
1304 | static void | 1420 | static void |
1305 | cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 1421 | cleaning_task (void *cls, |
1422 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1306 | { | 1423 | { |
1307 | struct DisconnectList *dl; | 1424 | struct DisconnectList *dl; |
1308 | 1425 | ||
@@ -1313,8 +1430,10 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1313 | } | 1430 | } |
1314 | GNUNET_TRANSPORT_disconnect (transport); | 1431 | GNUNET_TRANSPORT_disconnect (transport); |
1315 | transport = NULL; | 1432 | transport = NULL; |
1316 | while (NULL != peers) | 1433 | GNUNET_CONTAINER_multihashmap_iterate (peers, |
1317 | free_peer (peers); | 1434 | &free_peer, |
1435 | NULL); | ||
1436 | GNUNET_CONTAINER_multihashmap_destroy (peers); | ||
1318 | if (handle != NULL) | 1437 | if (handle != NULL) |
1319 | { | 1438 | { |
1320 | GNUNET_CORE_disconnect (handle); | 1439 | GNUNET_CORE_disconnect (handle); |
@@ -1382,6 +1501,7 @@ run (void *cls, | |||
1382 | &opt)) | 1501 | &opt)) |
1383 | opt = 16; | 1502 | opt = 16; |
1384 | target_connection_count = (unsigned int) opt; | 1503 | target_connection_count = (unsigned int) opt; |
1504 | peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2); | ||
1385 | 1505 | ||
1386 | if ( (friends_only == GNUNET_YES) || | 1506 | if ( (friends_only == GNUNET_YES) || |
1387 | (minimum_friend_count > 0) ) | 1507 | (minimum_friend_count > 0) ) |