aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-11-07 15:09:25 +0000
committerChristian Grothoff <christian@grothoff.org>2011-11-07 15:09:25 +0000
commit1e672718b471fe766ac72aa96781552d1678986b (patch)
tree75ecf350d399aeebb0cdc88b91865cd8cd12c885 /src/transport
parent20379063dd3ee6f3b7091a3d89e572886b295264 (diff)
downloadgnunet-1e672718b471fe766ac72aa96781552d1678986b.tar.gz
gnunet-1e672718b471fe766ac72aa96781552d1678986b.zip
PING regularly, track latency, towards fixing 1793, 1879
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/gnunet-service-transport_validation.c534
-rw-r--r--src/transport/gnunet-service-transport_validation.h46
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 */
371static int
372cleanup_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 */
407static void
408timeout_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 */
442static void
443transmit_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 */
521static void
522revalidate_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 */
456static int
457cleanup_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 */
483void 696void
@@ -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 */
507static void
508timeout_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 */
741static void
742transmit_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 */
825static int 937static int
826validate_address (void *cls, const char *tname, 938validate_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 */
863static void
864revalidate_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 */
1193void
1194GST_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 */
1219struct GNUNET_TIME_Relative
1220GST_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 */
63void
64GST_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 */
86struct GNUNET_TIME_Relative
87GST_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