diff options
-rw-r--r-- | src/transport/gnunet-service-transport_validation.c | 534 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_validation.h | 46 |
2 files changed, 364 insertions, 216 deletions
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index d7b4929b2..ce2ef76a7 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include "gnunet_peerinfo_service.h" | 34 | #include "gnunet_peerinfo_service.h" |
35 | #include "gnunet_signatures.h" | 35 | #include "gnunet_signatures.h" |
36 | 36 | ||
37 | // TODO: observe latency between PING/PONG and give information to ATS! | ||
38 | 37 | ||
39 | /** | 38 | /** |
40 | * How long is a PONG signature valid? We'll recycle a signature until | 39 | * How long is a PONG signature valid? We'll recycle a signature until |
@@ -53,11 +52,29 @@ | |||
53 | #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) | 52 | #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) |
54 | 53 | ||
55 | /** | 54 | /** |
56 | * How long before an existing address expires should we again try to | 55 | * How often do we allow PINGing an address that we have not yet |
57 | * validate it? Must be (significantly) smaller than | 56 | * validated? This also determines how long we track an address that |
58 | * HELLO_ADDRESS_EXPIRATION. | 57 | * we cannot validate (because after this time we can destroy the |
58 | * validation record). | ||
59 | */ | 59 | */ |
60 | #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) | 60 | #define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) |
61 | |||
62 | /** | ||
63 | * How often do we PING an address that we have successfully validated | ||
64 | * in the past but are not actively using? Should be (significantly) | ||
65 | * smaller than HELLO_ADDRESS_EXPIRATION. | ||
66 | */ | ||
67 | #define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
68 | |||
69 | /** | ||
70 | * How often do we PING an address that we are currently using? | ||
71 | */ | ||
72 | #define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) | ||
73 | |||
74 | /** | ||
75 | * How much delay is acceptable for sending the PING or PONG? | ||
76 | */ | ||
77 | #define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) | ||
61 | 78 | ||
62 | /** | 79 | /** |
63 | * Size of the validation map hashmap. | 80 | * Size of the validation map hashmap. |
@@ -189,7 +206,12 @@ struct ValidationEntry | |||
189 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | 206 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; |
190 | 207 | ||
191 | /** | 208 | /** |
192 | * At what time did we send the latest validation request? | 209 | * ID of task that will trigger address revalidation. |
210 | */ | ||
211 | GNUNET_SCHEDULER_TaskIdentifier revalidation_task; | ||
212 | |||
213 | /** | ||
214 | * At what time did we send the latest validation request (PING)? | ||
193 | */ | 215 | */ |
194 | struct GNUNET_TIME_Absolute send_time; | 216 | struct GNUNET_TIME_Absolute send_time; |
195 | 217 | ||
@@ -205,7 +227,13 @@ struct ValidationEntry | |||
205 | * ZERO if the address is considered valid (no validation needed) | 227 | * ZERO if the address is considered valid (no validation needed) |
206 | * otherwise a time in the future if we're currently denying re-validation | 228 | * otherwise a time in the future if we're currently denying re-validation |
207 | */ | 229 | */ |
208 | struct GNUNET_TIME_Absolute validation_block; | 230 | struct GNUNET_TIME_Absolute revalidation_block; |
231 | |||
232 | /** | ||
233 | * Last observed latency for this address (round-trip), delay between | ||
234 | * last PING sent and PONG received; FOREVER if we never got a PONG. | ||
235 | */ | ||
236 | struct GNUNET_TIME_Relative latency; | ||
209 | 237 | ||
210 | /** | 238 | /** |
211 | * Challenge number we used. | 239 | * Challenge number we used. |
@@ -223,6 +251,11 @@ struct ValidationEntry | |||
223 | */ | 251 | */ |
224 | int copied; | 252 | int copied; |
225 | 253 | ||
254 | /** | ||
255 | * Are we currently using this address for a connection? | ||
256 | */ | ||
257 | int in_use; | ||
258 | |||
226 | }; | 259 | }; |
227 | 260 | ||
228 | 261 | ||
@@ -328,6 +361,213 @@ validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value) | |||
328 | 361 | ||
329 | 362 | ||
330 | /** | 363 | /** |
364 | * Iterate over validation entries and free them. | ||
365 | * | ||
366 | * @param cls (unused) | ||
367 | * @param key peer identity (unused) | ||
368 | * @param value a 'struct ValidationEntry' to clean up | ||
369 | * @return GNUNET_YES (continue to iterate) | ||
370 | */ | ||
371 | static int | ||
372 | cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) | ||
373 | { | ||
374 | struct ValidationEntry *ve = value; | ||
375 | |||
376 | if (NULL != ve->bc) | ||
377 | { | ||
378 | GST_blacklist_test_cancel (ve->bc); | ||
379 | ve->bc = NULL; | ||
380 | } | ||
381 | GNUNET_break (GNUNET_OK == | ||
382 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
383 | &ve->pid.hashPubKey, ve)); | ||
384 | GNUNET_free (ve->transport_name); | ||
385 | if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) | ||
386 | { | ||
387 | GNUNET_SCHEDULER_cancel (ve->timeout_task); | ||
388 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
389 | } | ||
390 | if (GNUNET_SCHEDULER_NO_TASK != ve->revalidation_task) | ||
391 | { | ||
392 | GNUNET_SCHEDULER_cancel (ve->revalidation_task); | ||
393 | ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; | ||
394 | } | ||
395 | GNUNET_free (ve); | ||
396 | return GNUNET_OK; | ||
397 | } | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Address validation cleanup task. Assesses if the record is no | ||
402 | * longer valid and then possibly triggers its removal. | ||
403 | * | ||
404 | * @param cls the 'struct ValidationEntry' | ||
405 | * @param tc scheduler context (unused) | ||
406 | */ | ||
407 | static void | ||
408 | timeout_hello_validation (void *cls, | ||
409 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
410 | { | ||
411 | struct ValidationEntry *ve = cls; | ||
412 | struct GNUNET_TIME_Absolute max; | ||
413 | struct GNUNET_TIME_Relative left; | ||
414 | |||
415 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
416 | max = GNUNET_TIME_absolute_max (ve->valid_until, | ||
417 | ve->revalidation_block); | ||
418 | left = GNUNET_TIME_absolute_get_remaining (max); | ||
419 | if (left.rel_value > 0) | ||
420 | { | ||
421 | /* should wait a bit longer */ | ||
422 | ve->timeout_task = GNUNET_SCHEDULER_add_delayed (left, | ||
423 | &timeout_hello_validation, | ||
424 | ve); | ||
425 | return; | ||
426 | } | ||
427 | GNUNET_STATISTICS_update (GST_stats, | ||
428 | gettext_noop ("# address records discarded"), 1, | ||
429 | GNUNET_NO); | ||
430 | cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve); | ||
431 | } | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Function called with the result from blacklisting. | ||
436 | * Send a PING to the other peer if a communication is allowed. | ||
437 | * | ||
438 | * @param cls our 'struct ValidationEntry' | ||
439 | * @param pid identity of the other peer | ||
440 | * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not | ||
441 | */ | ||
442 | static void | ||
443 | transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, | ||
444 | int result) | ||
445 | { | ||
446 | struct ValidationEntry *ve = cls; | ||
447 | struct TransportPingMessage ping; | ||
448 | struct GNUNET_TRANSPORT_PluginFunctions *papi; | ||
449 | const struct GNUNET_MessageHeader *hello; | ||
450 | ssize_t ret; | ||
451 | size_t tsize; | ||
452 | size_t slen; | ||
453 | uint16_t hsize; | ||
454 | |||
455 | ve->bc = NULL; | ||
456 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", | ||
457 | GNUNET_i2s (pid), GST_plugins_a2s (ve->transport_name, ve->addr, | ||
458 | ve->addrlen)); | ||
459 | |||
460 | slen = strlen (ve->transport_name) + 1; | ||
461 | hello = GST_hello_get (); | ||
462 | hsize = ntohs (hello->size); | ||
463 | tsize = sizeof (struct TransportPingMessage) + ve->addrlen + slen + hsize; | ||
464 | |||
465 | ping.header.size = | ||
466 | htons (sizeof (struct TransportPingMessage) + ve->addrlen + slen); | ||
467 | ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); | ||
468 | ping.challenge = htonl (ve->challenge); | ||
469 | ping.target = *pid; | ||
470 | |||
471 | if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
472 | { | ||
473 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
474 | _ | ||
475 | ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"), | ||
476 | "HELLO", "PING", (unsigned int) tsize); | ||
477 | /* message too big (!?), get rid of HELLO */ | ||
478 | hsize = 0; | ||
479 | tsize = sizeof (struct TransportPingMessage) + ve->addrlen + slen + hsize; | ||
480 | } | ||
481 | { | ||
482 | char message_buf[tsize]; | ||
483 | |||
484 | /* build message with structure: | ||
485 | * [HELLO][TransportPingMessage][Transport name][Address] */ | ||
486 | memcpy (message_buf, hello, hsize); | ||
487 | memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage)); | ||
488 | memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], | ||
489 | ve->transport_name, slen); | ||
490 | memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], | ||
491 | ve->addr, ve->addrlen); | ||
492 | papi = GST_plugins_find (ve->transport_name); | ||
493 | if (papi == NULL) | ||
494 | ret = -1; | ||
495 | else | ||
496 | { | ||
497 | GNUNET_assert (papi->send != NULL); | ||
498 | ret = | ||
499 | papi->send (papi->cls, pid, message_buf, tsize, PING_PRIORITY, | ||
500 | ACCEPTABLE_PING_DELAY, NULL /* no session */ , | ||
501 | ve->addr, ve->addrlen, GNUNET_YES, NULL, NULL); | ||
502 | } | ||
503 | } | ||
504 | if (-1 != ret) | ||
505 | { | ||
506 | ve->send_time = GNUNET_TIME_absolute_get (); | ||
507 | GNUNET_STATISTICS_update (GST_stats, | ||
508 | gettext_noop | ||
509 | ("# PING without HELLO messages sent"), 1, | ||
510 | GNUNET_NO); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | |||
515 | /** | ||
516 | * Do address validation again to keep address valid. | ||
517 | * | ||
518 | * @param cls the 'struct ValidationEntry' | ||
519 | * @param tc scheduler context (unused) | ||
520 | */ | ||
521 | static void | ||
522 | revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
523 | { | ||
524 | struct ValidationEntry *ve = cls; | ||
525 | struct GNUNET_TIME_Relative canonical_delay; | ||
526 | struct GNUNET_TIME_Relative delay; | ||
527 | struct GST_BlacklistCheck *bc; | ||
528 | uint32_t rdelay; | ||
529 | |||
530 | ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; | ||
531 | delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block); | ||
532 | if (delay.rel_value > 0) | ||
533 | { | ||
534 | /* should wait a bit longer */ | ||
535 | ve->revalidation_task = | ||
536 | GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); | ||
537 | return; | ||
538 | } | ||
539 | /* How long until we can possibly permit the next PING? */ | ||
540 | canonical_delay = | ||
541 | (ve->in_use == GNUNET_YES) | ||
542 | ? CONNECTED_PING_FREQUENCY | ||
543 | : ( (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0) | ||
544 | ? VALIDATED_PING_FREQUENCY | ||
545 | : UNVALIDATED_PING_KEEPALIVE); | ||
546 | ve->revalidation_block = | ||
547 | GNUNET_TIME_relative_to_absolute (canonical_delay); | ||
548 | |||
549 | /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */ | ||
550 | rdelay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
551 | canonical_delay.rel_value); | ||
552 | delay = | ||
553 | GNUNET_TIME_relative_add (canonical_delay, | ||
554 | GNUNET_TIME_relative_multiply | ||
555 | (GNUNET_TIME_UNIT_MILLISECONDS, rdelay)); | ||
556 | ve->revalidation_task = | ||
557 | GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); | ||
558 | |||
559 | /* start PINGing by checking blacklist */ | ||
560 | GNUNET_STATISTICS_update (GST_stats, | ||
561 | gettext_noop ("# address revalidations started"), 1, | ||
562 | GNUNET_NO); | ||
563 | bc = GST_blacklist_test_allowed (&ve->pid, ve->transport_name, &transmit_ping_if_allowed, ve); | ||
564 | if (NULL != bc) | ||
565 | ve->bc = bc; /* only set 'bc' if 'transmit_ping_if_allowed' was not already | ||
566 | called... */ | ||
567 | } | ||
568 | |||
569 | |||
570 | /** | ||
331 | * Find a ValidationEntry entry for the given neighbour that matches | 571 | * Find a ValidationEntry entry for the given neighbour that matches |
332 | * the given address and transport. If none exists, create one (but | 572 | * the given address and transport. If none exists, create one (but |
333 | * without starting any validation). | 573 | * without starting any validation). |
@@ -364,10 +604,13 @@ find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded | |||
364 | ve->addr = (void *) &ve[1]; | 604 | ve->addr = (void *) &ve[1]; |
365 | ve->public_key = *public_key; | 605 | ve->public_key = *public_key; |
366 | ve->pid = *neighbour; | 606 | ve->pid = *neighbour; |
607 | ve->latency = GNUNET_TIME_UNIT_FOREVER_REL; | ||
367 | ve->challenge = | 608 | ve->challenge = |
368 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); | 609 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); |
610 | ve->timeout_task = GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE, | ||
611 | &timeout_hello_validation, ve); | ||
369 | memcpy (&ve[1], addr, addrlen); | 612 | memcpy (&ve[1], addr, addrlen); |
370 | ve->addrlen = addrlen; | 613 | ve->addrlen = addrlen; |
371 | GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->hashPubKey, ve, | 614 | GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->hashPubKey, ve, |
372 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | 615 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); |
373 | return ve; | 616 | return ve; |
@@ -405,6 +648,8 @@ add_valid_address (void *cls, const char *tname, | |||
405 | } | 648 | } |
406 | ve = find_validation_entry (&public_key, &pid, tname, addr, addrlen); | 649 | ve = find_validation_entry (&public_key, &pid, tname, addr, addrlen); |
407 | ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); | 650 | ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); |
651 | if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) | ||
652 | ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); | ||
408 | GNUNET_ATS_address_update (GST_ats, &pid, tname, addr, addrlen, NULL, NULL, | 653 | GNUNET_ATS_address_update (GST_ats, &pid, tname, addr, addrlen, NULL, NULL, |
409 | 0); | 654 | 0); |
410 | return GNUNET_OK; | 655 | return GNUNET_OK; |
@@ -446,38 +691,6 @@ GST_validation_start () | |||
446 | 691 | ||
447 | 692 | ||
448 | /** | 693 | /** |
449 | * Iterate over validation entries and free them. | ||
450 | * | ||
451 | * @param cls (unused) | ||
452 | * @param key peer identity (unused) | ||
453 | * @param value a 'struct ValidationEntry' to clean up | ||
454 | * @return GNUNET_YES (continue to iterate) | ||
455 | */ | ||
456 | static int | ||
457 | cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) | ||
458 | { | ||
459 | struct ValidationEntry *ve = value; | ||
460 | |||
461 | if (NULL != ve->bc) | ||
462 | { | ||
463 | GST_blacklist_test_cancel (ve->bc); | ||
464 | ve->bc = NULL; | ||
465 | } | ||
466 | GNUNET_break (GNUNET_OK == | ||
467 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
468 | &ve->pid.hashPubKey, ve)); | ||
469 | GNUNET_free (ve->transport_name); | ||
470 | if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) | ||
471 | { | ||
472 | GNUNET_SCHEDULER_cancel (ve->timeout_task); | ||
473 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
474 | } | ||
475 | GNUNET_free (ve); | ||
476 | return GNUNET_OK; | ||
477 | } | ||
478 | |||
479 | |||
480 | /** | ||
481 | * Stop the validation subsystem. | 694 | * Stop the validation subsystem. |
482 | */ | 695 | */ |
483 | void | 696 | void |
@@ -499,26 +712,6 @@ GST_validation_stop () | |||
499 | 712 | ||
500 | 713 | ||
501 | /** | 714 | /** |
502 | * Address validation cleanup task (record no longer needed). | ||
503 | * | ||
504 | * @param cls the 'struct ValidationEntry' | ||
505 | * @param tc scheduler context (unused) | ||
506 | */ | ||
507 | static void | ||
508 | timeout_hello_validation (void *cls, | ||
509 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
510 | { | ||
511 | struct ValidationEntry *ve = cls; | ||
512 | |||
513 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
514 | GNUNET_STATISTICS_update (GST_stats, | ||
515 | gettext_noop ("# address records discarded"), 1, | ||
516 | GNUNET_NO); | ||
517 | cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve); | ||
518 | } | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Send the given PONG to the given address. | 715 | * Send the given PONG to the given address. |
523 | * | 716 | * |
524 | * @param cls the PONG message | 717 | * @param cls the PONG message |
@@ -550,7 +743,7 @@ multicast_pong (void *cls, | |||
550 | return; | 743 | return; |
551 | (void) papi->send (papi->cls, target, (const char *) pong, | 744 | (void) papi->send (papi->cls, target, (const char *) pong, |
552 | ntohs (pong->header.size), PONG_PRIORITY, | 745 | ntohs (pong->header.size), PONG_PRIORITY, |
553 | HELLO_REVALIDATION_START_TIME, NULL, plugin_address, | 746 | ACCEPTABLE_PING_DELAY, NULL, plugin_address, |
554 | plugin_address_len, GNUNET_YES, NULL, NULL); | 747 | plugin_address_len, GNUNET_YES, NULL, NULL); |
555 | } | 748 | } |
556 | 749 | ||
@@ -687,7 +880,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, | |||
687 | ret = | 880 | ret = |
688 | papi->send (papi->cls, sender, (const char *) pong, | 881 | papi->send (papi->cls, sender, (const char *) pong, |
689 | ntohs (pong->header.size), PONG_PRIORITY, | 882 | ntohs (pong->header.size), PONG_PRIORITY, |
690 | HELLO_REVALIDATION_START_TIME, session, sender_address, | 883 | ACCEPTABLE_PING_DELAY, session, sender_address, |
691 | sender_address_len, GNUNET_SYSERR, NULL, NULL); | 884 | sender_address_len, GNUNET_SYSERR, NULL, NULL); |
692 | if (ret != -1) | 885 | if (ret != -1) |
693 | { | 886 | { |
@@ -731,87 +924,6 @@ struct ValidateAddressContext | |||
731 | 924 | ||
732 | 925 | ||
733 | /** | 926 | /** |
734 | * Function called with the result from blacklisting. | ||
735 | * Send a PING to the other peer if a communication is allowed. | ||
736 | * | ||
737 | * @param cls ou r'struct ValidationEntry' | ||
738 | * @param pid identity of the other peer | ||
739 | * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not | ||
740 | */ | ||
741 | static void | ||
742 | transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, | ||
743 | int result) | ||
744 | { | ||
745 | struct ValidationEntry *ve = cls; | ||
746 | struct TransportPingMessage ping; | ||
747 | struct GNUNET_TRANSPORT_PluginFunctions *papi; | ||
748 | const struct GNUNET_MessageHeader *hello; | ||
749 | ssize_t ret; | ||
750 | size_t tsize; | ||
751 | size_t slen; | ||
752 | uint16_t hsize; | ||
753 | |||
754 | ve->bc = NULL; | ||
755 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", | ||
756 | GNUNET_i2s (pid), GST_plugins_a2s (ve->transport_name, ve->addr, | ||
757 | ve->addrlen)); | ||
758 | |||
759 | slen = strlen (ve->transport_name) + 1; | ||
760 | hello = GST_hello_get (); | ||
761 | hsize = ntohs (hello->size); | ||
762 | tsize = sizeof (struct TransportPingMessage) + ve->addrlen + slen + hsize; | ||
763 | |||
764 | ping.header.size = | ||
765 | htons (sizeof (struct TransportPingMessage) + ve->addrlen + slen); | ||
766 | ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); | ||
767 | ping.challenge = htonl (ve->challenge); | ||
768 | ping.target = *pid; | ||
769 | |||
770 | if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
771 | { | ||
772 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
773 | _ | ||
774 | ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"), | ||
775 | "HELLO", "PING", (unsigned int) tsize); | ||
776 | /* message too big (!?), get rid of HELLO */ | ||
777 | hsize = 0; | ||
778 | tsize = sizeof (struct TransportPingMessage) + ve->addrlen + slen + hsize; | ||
779 | } | ||
780 | { | ||
781 | char message_buf[tsize]; | ||
782 | |||
783 | /* build message with structure: | ||
784 | * [HELLO][TransportPingMessage][Transport name][Address] */ | ||
785 | memcpy (message_buf, hello, hsize); | ||
786 | memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage)); | ||
787 | memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], | ||
788 | ve->transport_name, slen); | ||
789 | memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], | ||
790 | ve->addr, ve->addrlen); | ||
791 | papi = GST_plugins_find (ve->transport_name); | ||
792 | if (papi == NULL) | ||
793 | ret = -1; | ||
794 | else | ||
795 | { | ||
796 | GNUNET_assert (papi->send != NULL); | ||
797 | ret = | ||
798 | papi->send (papi->cls, pid, message_buf, tsize, PING_PRIORITY, | ||
799 | HELLO_REVALIDATION_START_TIME, NULL /* no session */ , | ||
800 | ve->addr, ve->addrlen, GNUNET_YES, NULL, NULL); | ||
801 | } | ||
802 | } | ||
803 | if (-1 != ret) | ||
804 | { | ||
805 | ve->send_time = GNUNET_TIME_absolute_get (); | ||
806 | GNUNET_STATISTICS_update (GST_stats, | ||
807 | gettext_noop | ||
808 | ("# PING without HELLO messages sent"), 1, | ||
809 | GNUNET_NO); | ||
810 | } | ||
811 | } | ||
812 | |||
813 | |||
814 | /** | ||
815 | * Iterator callback to go over all addresses and try to validate them | 927 | * Iterator callback to go over all addresses and try to validate them |
816 | * (unless blocked or already validated). | 928 | * (unless blocked or already validated). |
817 | * | 929 | * |
@@ -823,70 +935,25 @@ transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, | |||
823 | * @return GNUNET_OK (keep the address) | 935 | * @return GNUNET_OK (keep the address) |
824 | */ | 936 | */ |
825 | static int | 937 | static int |
826 | validate_address (void *cls, const char *tname, | 938 | validate_address_iterator (void *cls, const char *tname, |
827 | struct GNUNET_TIME_Absolute expiration, const void *addr, | 939 | struct GNUNET_TIME_Absolute expiration, const void *addr, |
828 | uint16_t addrlen) | 940 | uint16_t addrlen) |
829 | { | 941 | { |
830 | const struct ValidateAddressContext *vac = cls; | 942 | const struct ValidateAddressContext *vac = cls; |
831 | const struct GNUNET_PeerIdentity *pid = &vac->pid; | 943 | const struct GNUNET_PeerIdentity *pid = &vac->pid; |
832 | struct ValidationEntry *ve; | 944 | struct ValidationEntry *ve; |
833 | struct GST_BlacklistCheck *bc; | ||
834 | 945 | ||
835 | if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) | 946 | if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) |
836 | return GNUNET_OK; /* expired */ | 947 | return GNUNET_OK; /* expired */ |
837 | ve = find_validation_entry (&vac->public_key, pid, tname, addr, addrlen); | 948 | ve = find_validation_entry (&vac->public_key, pid, tname, addr, addrlen); |
838 | if (GNUNET_TIME_absolute_get_remaining (ve->validation_block).rel_value > 0) | 949 | if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) |
839 | return GNUNET_OK; /* blocked */ | 950 | ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, |
840 | if ((GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) && | 951 | ve); |
841 | (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0)) | ||
842 | return GNUNET_OK; /* revalidation task already scheduled & still valid */ | ||
843 | ve->validation_block = | ||
844 | GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME); | ||
845 | if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) | ||
846 | GNUNET_SCHEDULER_cancel (ve->timeout_task); | ||
847 | ve->timeout_task = | ||
848 | GNUNET_SCHEDULER_add_delayed (HELLO_REVALIDATION_START_TIME, | ||
849 | &timeout_hello_validation, ve); | ||
850 | bc = GST_blacklist_test_allowed (pid, tname, &transmit_ping_if_allowed, ve); | ||
851 | if (NULL != bc) | ||
852 | ve->bc = bc; | ||
853 | return GNUNET_OK; | 952 | return GNUNET_OK; |
854 | } | 953 | } |
855 | 954 | ||
856 | 955 | ||
857 | /** | 956 | /** |
858 | * Do address validation again to keep address valid. | ||
859 | * | ||
860 | * @param cls the 'struct ValidationEntry' | ||
861 | * @param tc scheduler context (unused) | ||
862 | */ | ||
863 | static void | ||
864 | revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
865 | { | ||
866 | struct ValidationEntry *ve = cls; | ||
867 | struct GNUNET_TIME_Relative delay; | ||
868 | struct ValidateAddressContext vac; | ||
869 | |||
870 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
871 | delay = GNUNET_TIME_absolute_get_remaining (ve->validation_block); | ||
872 | if (delay.rel_value > 0) | ||
873 | { | ||
874 | /* should wait a bit longer */ | ||
875 | ve->timeout_task = | ||
876 | GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); | ||
877 | return; | ||
878 | } | ||
879 | GNUNET_STATISTICS_update (GST_stats, | ||
880 | gettext_noop ("# address revalidations started"), 1, | ||
881 | GNUNET_NO); | ||
882 | vac.pid = ve->pid; | ||
883 | vac.public_key = ve->public_key; | ||
884 | validate_address (&vac, ve->transport_name, ve->valid_until, ve->addr, | ||
885 | (uint16_t) ve->addrlen); | ||
886 | } | ||
887 | |||
888 | |||
889 | /** | ||
890 | * Add the validated peer address to the HELLO. | 957 | * Add the validated peer address to the HELLO. |
891 | * | 958 | * |
892 | * @param cls the 'struct ValidationEntry' with the validated address | 959 | * @param cls the 'struct ValidationEntry' with the validated address |
@@ -926,8 +993,6 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, | |||
926 | size_t addrlen; | 993 | size_t addrlen; |
927 | size_t slen; | 994 | size_t slen; |
928 | size_t size; | 995 | size_t size; |
929 | uint32_t rdelay; | ||
930 | struct GNUNET_TIME_Relative delay; | ||
931 | struct GNUNET_HELLO_Message *hello; | 996 | struct GNUNET_HELLO_Message *hello; |
932 | 997 | ||
933 | if (ntohs (hdr->size) < sizeof (struct TransportPongMessage)) | 998 | if (ntohs (hdr->size) < sizeof (struct TransportPongMessage)) |
@@ -953,7 +1018,6 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, | |||
953 | addrlen = size - slen; | 1018 | addrlen = size - slen; |
954 | 1019 | ||
955 | ve = find_validation_entry (NULL, sender, tname, addr, addrlen); | 1020 | ve = find_validation_entry (NULL, sender, tname, addr, addrlen); |
956 | |||
957 | if (NULL == ve) | 1021 | if (NULL == ve) |
958 | { | 1022 | { |
959 | GNUNET_STATISTICS_update (GST_stats, | 1023 | GNUNET_STATISTICS_update (GST_stats, |
@@ -995,34 +1059,20 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, | |||
995 | 1059 | ||
996 | /* validity achieved, remember it! */ | 1060 | /* validity achieved, remember it! */ |
997 | ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); | 1061 | ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); |
1062 | ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); | ||
998 | { | 1063 | { |
999 | struct GNUNET_ATS_Information ats; | 1064 | struct GNUNET_ATS_Information ats; |
1000 | 1065 | ||
1001 | ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); | 1066 | ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); |
1002 | ats.value = | 1067 | ats.value = htonl ((uint32_t) ve->latency.rel_value); |
1003 | htonl ((uint32_t) | ||
1004 | GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value); | ||
1005 | GNUNET_ATS_address_update (GST_ats, &ve->pid, ve->transport_name, ve->addr, | 1068 | GNUNET_ATS_address_update (GST_ats, &ve->pid, ve->transport_name, ve->addr, |
1006 | ve->addrlen, NULL, &ats, 1); | 1069 | ve->addrlen, NULL, &ats, 1); |
1007 | } | 1070 | } |
1008 | |||
1009 | /* build HELLO to store in PEERINFO */ | 1071 | /* build HELLO to store in PEERINFO */ |
1010 | ve->copied = GNUNET_NO; | 1072 | ve->copied = GNUNET_NO; |
1011 | hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); | 1073 | hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); |
1012 | GNUNET_PEERINFO_add_peer (GST_peerinfo, hello); | 1074 | GNUNET_PEERINFO_add_peer (GST_peerinfo, hello); |
1013 | GNUNET_free (hello); | 1075 | GNUNET_free (hello); |
1014 | |||
1015 | if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) | ||
1016 | GNUNET_SCHEDULER_cancel (ve->timeout_task); | ||
1017 | |||
1018 | /* randomly delay by up to 1h to avoid synchronous validations */ | ||
1019 | rdelay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 60 * 60); | ||
1020 | delay = | ||
1021 | GNUNET_TIME_relative_add (HELLO_REVALIDATION_START_TIME, | ||
1022 | GNUNET_TIME_relative_multiply | ||
1023 | (GNUNET_TIME_UNIT_SECONDS, rdelay)); | ||
1024 | ve->timeout_task = | ||
1025 | GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); | ||
1026 | } | 1076 | } |
1027 | 1077 | ||
1028 | 1078 | ||
@@ -1059,10 +1109,9 @@ GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) | |||
1059 | GNUNET_i2s (&vac.pid)); | 1109 | GNUNET_i2s (&vac.pid)); |
1060 | #endif | 1110 | #endif |
1061 | GNUNET_free (h); | 1111 | GNUNET_free (h); |
1062 | |||
1063 | GNUNET_assert (NULL == | 1112 | GNUNET_assert (NULL == |
1064 | GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, | 1113 | GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, |
1065 | &validate_address, &vac)); | 1114 | &validate_address_iterator, &vac)); |
1066 | } | 1115 | } |
1067 | 1116 | ||
1068 | 1117 | ||
@@ -1099,7 +1148,7 @@ iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value) | |||
1099 | struct ValidationEntry *ve = value; | 1148 | struct ValidationEntry *ve = value; |
1100 | 1149 | ||
1101 | ic->cb (ic->cb_cls, &ve->public_key, &ve->pid, ve->valid_until, | 1150 | ic->cb (ic->cb_cls, &ve->public_key, &ve->pid, ve->valid_until, |
1102 | ve->validation_block, ve->transport_name, ve->addr, ve->addrlen); | 1151 | ve->revalidation_block, ve->transport_name, ve->addr, ve->addrlen); |
1103 | return GNUNET_OK; | 1152 | return GNUNET_OK; |
1104 | } | 1153 | } |
1105 | 1154 | ||
@@ -1126,4 +1175,57 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, | |||
1126 | } | 1175 | } |
1127 | 1176 | ||
1128 | 1177 | ||
1178 | /** | ||
1179 | * Update if we are using an address for a connection actively right now. | ||
1180 | * Based on this, the validation module will measure latency for the | ||
1181 | * address more or less often. | ||
1182 | * | ||
1183 | * @param sender peer sending the PING | ||
1184 | * @param hdr the PING | ||
1185 | * @param plugin_name name of plugin that received the PING | ||
1186 | * @param session session we got the PING from | ||
1187 | * @param sender_address address of the sender as known to the plugin, NULL | ||
1188 | * if we did not initiate the connection | ||
1189 | * @param sender_address_len number of bytes in sender_address | ||
1190 | * @param in_use GNUNET_YES if we are now using the address for a connection, | ||
1191 | * GNUNET_NO if we are no longer using the address for a connection | ||
1192 | */ | ||
1193 | void | ||
1194 | GST_validation_set_address_use (const struct GNUNET_PeerIdentity *sender, | ||
1195 | const struct GNUNET_MessageHeader *hdr, | ||
1196 | const char *plugin_name, struct Session *session, | ||
1197 | const void *sender_address, | ||
1198 | size_t sender_address_len, | ||
1199 | int in_use) | ||
1200 | { | ||
1201 | // FIXME: lookup address, update flag, re-schedule validation task | ||
1202 | } | ||
1203 | |||
1204 | |||
1205 | /** | ||
1206 | * Query validation about the latest observed latency on a given | ||
1207 | * address. | ||
1208 | * | ||
1209 | * @param sender peer sending the PING | ||
1210 | * @param hdr the PING | ||
1211 | * @param plugin_name name of plugin that received the PING | ||
1212 | * @param session session we got the PING from | ||
1213 | * @param sender_address address of the sender as known to the plugin, NULL | ||
1214 | * if we did not initiate the connection | ||
1215 | * @param sender_address_len number of bytes in sender_address | ||
1216 | * @return observed latency of the address, FOREVER if the address was | ||
1217 | * never successfully validated | ||
1218 | */ | ||
1219 | struct GNUNET_TIME_Relative | ||
1220 | GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, | ||
1221 | const struct GNUNET_MessageHeader *hdr, | ||
1222 | const char *plugin_name, struct Session *session, | ||
1223 | const void *sender_address, | ||
1224 | size_t sender_address_len) | ||
1225 | { | ||
1226 | // FIXME: lookup address, return latency field... | ||
1227 | return GNUNET_TIME_UNIT_ZERO; | ||
1228 | } | ||
1229 | |||
1230 | |||
1129 | /* end of file gnunet-service-transport_validation.c */ | 1231 | /* end of file gnunet-service-transport_validation.c */ |
diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h index 06370161c..0e3c5e96d 100644 --- a/src/transport/gnunet-service-transport_validation.h +++ b/src/transport/gnunet-service-transport_validation.h | |||
@@ -46,6 +46,52 @@ GST_validation_stop (void); | |||
46 | 46 | ||
47 | 47 | ||
48 | /** | 48 | /** |
49 | * Update if we are using an address for a connection actively right now. | ||
50 | * Based on this, the validation module will measure latency for the | ||
51 | * address more or less often. | ||
52 | * | ||
53 | * @param sender peer sending the PING | ||
54 | * @param hdr the PING | ||
55 | * @param plugin_name name of plugin that received the PING | ||
56 | * @param session session we got the PING from | ||
57 | * @param sender_address address of the sender as known to the plugin, NULL | ||
58 | * if we did not initiate the connection | ||
59 | * @param sender_address_len number of bytes in sender_address | ||
60 | * @param in_use GNUNET_YES if we are now using the address for a connection, | ||
61 | * GNUNET_NO if we are no longer using the address for a connection | ||
62 | */ | ||
63 | void | ||
64 | GST_validation_set_address_use (const struct GNUNET_PeerIdentity *sender, | ||
65 | const struct GNUNET_MessageHeader *hdr, | ||
66 | const char *plugin_name, struct Session *session, | ||
67 | const void *sender_address, | ||
68 | size_t sender_address_len, | ||
69 | int in_use); | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Query validation about the latest observed latency on a given | ||
74 | * address. | ||
75 | * | ||
76 | * @param sender peer sending the PING | ||
77 | * @param hdr the PING | ||
78 | * @param plugin_name name of plugin that received the PING | ||
79 | * @param session session we got the PING from | ||
80 | * @param sender_address address of the sender as known to the plugin, NULL | ||
81 | * if we did not initiate the connection | ||
82 | * @param sender_address_len number of bytes in sender_address | ||
83 | * @return observed latency of the address, FOREVER if the address was | ||
84 | * never successfully validated | ||
85 | */ | ||
86 | struct GNUNET_TIME_Relative | ||
87 | GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, | ||
88 | const struct GNUNET_MessageHeader *hdr, | ||
89 | const char *plugin_name, struct Session *session, | ||
90 | const void *sender_address, | ||
91 | size_t sender_address_len); | ||
92 | |||
93 | |||
94 | /** | ||
49 | * We've received a PING. If appropriate, generate a PONG. | 95 | * We've received a PING. If appropriate, generate a PONG. |
50 | * | 96 | * |
51 | * @param sender peer sending the PING | 97 | * @param sender peer sending the PING |