From d9b68f30f930830b455eea95d0bc619553180136 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 3 Feb 2015 16:11:15 +0000 Subject: add internal API to enable telling ATS about 'failed' suggestions --- src/transport/gnunet-service-transport.c | 11 +- src/transport/gnunet-service-transport_ats.c | 117 ++++++++++++++++++++- src/transport/gnunet-service-transport_ats.h | 19 +++- .../gnunet-service-transport_validation.c | 35 +++--- 4 files changed, 160 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index ef05739c5..e3bbf7167 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -831,6 +831,14 @@ ats_request_address_change (void *cls, uint32_t bw_in = ntohl (bandwidth_in.value__); uint32_t bw_out = ntohl (bandwidth_out.value__); + if (NULL == peer) + { + /* ATS service died, all suggestions become invalid! + (but we'll keep using the allocations for a little + while, to keep going while ATS restarts) */ + // FIXME: do something? + return; + } /* ATS tells me to disconnect from peer */ if ((0 == bw_in) && (0 == bw_out)) { @@ -847,7 +855,8 @@ ats_request_address_change (void *cls, GNUNET_NO); GST_neighbours_switch_to_address (address, session, - bandwidth_in, bandwidth_out); + bandwidth_in, + bandwidth_out); } diff --git a/src/transport/gnunet-service-transport_ats.c b/src/transport/gnunet-service-transport_ats.c index 0d61365d8..0b864f3fb 100644 --- a/src/transport/gnunet-service-transport_ats.c +++ b/src/transport/gnunet-service-transport_ats.c @@ -50,6 +50,29 @@ struct AddressInfo * Record with ATS API for the address. */ struct GNUNET_ATS_AddressRecord *ar; + + /** + * Time until when this address is blocked and should thus not be + * made available to ATS (@e ar should be NULL until this time). + * Used when transport determines that for some reason it + * (temporarily) cannot use an address, even though it has been + * validated. + */ + struct GNUNET_TIME_Absolute blocked; + + /** + * If an address is blocked as part of an exponential back-off, + * we track the current size of the backoff here. + */ + struct GNUNET_TIME_Relative back_off; + + /** + * Task scheduled to unblock an ATS-blocked address at + * @e blocked time, or NULL if the address is not blocked + * (and thus @e ar is non-NULL). + */ + struct GNUNET_SCHEDULER_Task *unblock_task; + }; @@ -219,6 +242,65 @@ GST_ats_is_known (const struct GNUNET_HELLO_Address *address, } +/** + * The blocking time for an address has expired, allow ATS to + * suggest it again. + * + * @param cls the `struct AddressInfo` of the address to unblock + * @param tc unused + */ +static void +unblock_address (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct AddressInfo *ai = cls; + + ai->unblock_task = NULL; + ai->ar = GNUNET_ATS_address_add (GST_ats, + ai->address, + ai->session, + NULL, 0); + /* FIXME: should pass ATS information here! */ +} + + +/** + * Temporarily block a valid address for use by ATS for address + * suggestions. This function should be called if an address was + * suggested by ATS but failed to perform (i.e. failure to establish a + * session or to exchange the PING/PONG). + * + * @param address the address to block + * @param session the session (can be NULL) + */ +void +GST_ats_block_address (const struct GNUNET_HELLO_Address *address, + struct Session *session) +{ + struct AddressInfo *ai; + + ai = find_ai (address, session); + if (NULL == ai) + { + GNUNET_break (0); + return; + } + if (NULL == ai->ar) + { + /* already blocked, how did it get used!? */ + GNUNET_break (0); + return; + } + GNUNET_ATS_address_destroy (ai->ar); + ai->ar = NULL; + ai->back_off = GNUNET_TIME_STD_BACKOFF (ai->back_off); + ai->blocked = GNUNET_TIME_relative_to_absolute (ai->back_off); + ai->unblock_task = GNUNET_SCHEDULER_add_delayed (ai->back_off, + &unblock_address, + ai); +} + + /** * Notify ATS about the new address including the network this address is * located in. @@ -349,8 +431,9 @@ GST_ats_new_session (const struct GNUNET_HELLO_Address *address, "Telling ATS about new session %p for peer %s\n", session, GNUNET_i2s (&address->peer)); - GNUNET_ATS_address_add_session (ai->ar, - session); + if (NULL != ai->ar) + GNUNET_ATS_address_add_session (ai->ar, + session); } @@ -392,6 +475,11 @@ GST_ats_del_session (const struct GNUNET_HELLO_Address *address, "Telling ATS to destroy session %p from peer %s\n", session, GNUNET_i2s (&address->peer)); + if (NULL == ai->ar) + { + GST_ats_expire_address (address); + return; + } if (GNUNET_YES == GNUNET_ATS_address_del_session (ai->ar, session)) { @@ -444,8 +532,10 @@ GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address, session, ats, ats_count); - GNUNET_ATS_address_update (ai->ar, - ats_new, ats_count); + if (NULL != ai->ar) + GNUNET_ATS_address_update (ai->ar, + ats_new, + ats_count); GNUNET_free_non_null (ats_new); } @@ -470,6 +560,7 @@ GST_ats_set_in_use (const struct GNUNET_HELLO_Address *address, GNUNET_break (0); return; } + GNUNET_assert (NULL != ai->ar); GNUNET_ATS_address_set_in_use (ai->ar, in_use); } @@ -503,7 +594,15 @@ GST_ats_expire_address (const struct GNUNET_HELLO_Address *address) "Telling ATS to destroy address from peer %s\n", GNUNET_i2s (&address->peer)); if (NULL != ai->ar) + { GNUNET_ATS_address_destroy (ai->ar); + ai->ar = NULL; + } + if (NULL != ai->unblock_task) + { + GNUNET_SCHEDULER_cancel (ai->unblock_task); + ai->unblock_task = NULL; + } GNUNET_HELLO_address_free (ai->address); GNUNET_free (ai); } @@ -538,6 +637,16 @@ destroy_ai (void *cls, GNUNET_CONTAINER_multipeermap_remove (p2a, key, ai)); + if (NULL != ai->unblock_task) + { + GNUNET_SCHEDULER_cancel (ai->unblock_task); + ai->unblock_task = NULL; + } + if (NULL != ai->ar) + { + GNUNET_ATS_address_destroy (ai->ar); + ai->ar = NULL; + } GNUNET_HELLO_address_free (ai->address); GNUNET_free (ai); return GNUNET_OK; diff --git a/src/transport/gnunet-service-transport_ats.h b/src/transport/gnunet-service-transport_ats.h index b203cc323..53c4caa68 100644 --- a/src/transport/gnunet-service-transport_ats.h +++ b/src/transport/gnunet-service-transport_ats.h @@ -26,10 +26,6 @@ * - add API to give ATS feedback about an address that was * suggested but did not work out (without fully 'deleting' * it forever) - * - improve ATS API to take advantage of this new subsystem - * when calling ATS functions, make ATS API match this API - * more closely - * - combine with API to tell ATS about address "use" */ #ifndef GNUNET_SERVICE_TRANSPORT_ATS_H #define GNUNET_SERVICE_TRANSPORT_ATS_H @@ -61,6 +57,21 @@ int GST_ats_is_known (const struct GNUNET_HELLO_Address *address, struct Session *session); + +/** + * Temporarily block a valid address for use by ATS for address + * suggestions. This function should be called if an address was + * suggested by ATS but failed to perform (i.e. failure to establish a + * session or to exchange the PING/PONG). + * + * @param address the address to block + * @param session the session (can be NULL) + */ +void +GST_ats_block_address (const struct GNUNET_HELLO_Address *address, + struct Session *session); + + /** * Notify ATS about the new address including the network this address is * located in. diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index f0b8d9466..fb2791eba 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c @@ -1519,21 +1519,30 @@ GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) + { + /* got our own HELLO, how boring */ return GNUNET_OK; - /* Add peer identity without addresses to peerinfo service */ - h = GNUNET_HELLO_create (&pid.public_key, NULL, NULL, friend); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Validation received new %s message for peer `%s' with size %u\n"), - "HELLO", - GNUNET_i2s (&pid), - ntohs (hello->size)); - GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", - GNUNET_i2s (&pid)); + } + if (GNUNET_NO == + GNUNET_CONTAINER_multipeermap_contains (validation_map, + &pid)) + { + /* Add peer identity without addresses to peerinfo service */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding HELLO without addresses for peer `%s'\n", + GNUNET_i2s (&pid)); + h = GNUNET_HELLO_create (&pid.public_key, NULL, NULL, friend); + GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); - GNUNET_free (h); + GNUNET_free (h); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validation received HELLO message for peer `%s' with size %u, checking for new addresses\n", + GNUNET_i2s (&pid), + ntohs (hello->size)); + } GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, -- cgit v1.2.3