123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2015 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file transport/gnunet-service-transport_ats.c
- * @brief interfacing between transport and ATS service
- * @author Christian Grothoff
- */
- #include "platform.h"
- #include "gnunet-service-transport.h"
- #include "gnunet-service-transport_ats.h"
- #include "gnunet-service-transport_manipulation.h"
- #include "gnunet-service-transport_plugins.h"
- #include "gnunet_ats_service.h"
- /**
- * Log convenience function.
- */
- #define LOG(kind, ...) GNUNET_log_from (kind, "transport-ats", __VA_ARGS__)
- /**
- * Information we track for each address known to ATS.
- */
- struct AddressInfo
- {
- /**
- * The address (with peer identity). Must never change
- * while this struct is in the #p2a map.
- */
- struct GNUNET_HELLO_Address *address;
- /**
- * Session (can be NULL)
- */
- struct GNUNET_ATS_Session *session;
- /**
- * Record with ATS API for the address.
- */
- struct GNUNET_ATS_AddressRecord *ar;
- /**
- * Performance properties of this address.
- */
- struct GNUNET_ATS_Properties properties;
- /**
- * 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;
- /**
- * Set to #GNUNET_YES if the address has expired but we could
- * not yet remove it because we still have a valid session.
- */
- int expired;
- };
- /**
- * Map from peer identities to one or more `struct AddressInfo` values
- * for the peer.
- */
- static struct GNUNET_CONTAINER_MultiPeerMap *p2a;
- /**
- * Number of blocked addresses.
- */
- static unsigned int num_blocked;
- /**
- * Closure for #find_ai_cb() and #find_ai_no_session_cb().
- */
- struct FindClosure
- {
- /**
- * Session to look for (only used if the address is inbound).
- */
- struct GNUNET_ATS_Session *session;
- /**
- * Address to look for.
- */
- const struct GNUNET_HELLO_Address *address;
- /**
- * Where to store the result.
- */
- struct AddressInfo *ret;
- };
- /**
- * Provide an update on the `p2a` map size to statistics.
- * This function should be called whenever the `p2a` map
- * is changed.
- */
- static void
- publish_p2a_stat_update ()
- {
- GNUNET_STATISTICS_set (GST_stats,
- gettext_noop ("# Addresses given to ATS"),
- GNUNET_CONTAINER_multipeermap_size (p2a) - num_blocked,
- GNUNET_NO);
- GNUNET_STATISTICS_set (GST_stats,
- "# blocked addresses",
- num_blocked,
- GNUNET_NO);
- }
- /**
- * Find matching address info. Both the address and the session
- * must match; note that expired addresses are still found (as
- * the session kind-of keeps those alive).
- *
- * @param cls the `struct FindClosure`
- * @param key which peer is this about
- * @param value the `struct AddressInfo`
- * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
- */
- static int
- find_ai_cb (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct FindClosure *fc = cls;
- struct AddressInfo *ai = value;
- if ((0 ==
- GNUNET_HELLO_address_cmp (fc->address,
- ai->address)) &&
- (fc->session == ai->session))
- {
- fc->ret = ai;
- return GNUNET_NO;
- }
- return GNUNET_YES;
- }
- /**
- * Find the address information struct for the
- * given @a address and @a session.
- *
- * @param address address to look for
- * @param session session to match for inbound connections
- * @return NULL if this combination is unknown
- */
- static struct AddressInfo *
- find_ai (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session)
- {
- struct FindClosure fc;
- fc.address = address;
- fc.session = session;
- fc.ret = NULL;
- GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
- &address->peer,
- &find_ai_cb,
- &fc);
- return fc.ret;
- }
- /**
- * Find matching address info, ignoring sessions and expired
- * addresses.
- *
- * @param cls the `struct FindClosure`
- * @param key which peer is this about
- * @param value the `struct AddressInfo`
- * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
- */
- static int
- find_ai_no_session_cb (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct FindClosure *fc = cls;
- struct AddressInfo *ai = value;
- if (ai->expired)
- return GNUNET_YES; /* expired do not count here */
- if (0 ==
- GNUNET_HELLO_address_cmp (fc->address,
- ai->address))
- {
- fc->ret = ai;
- return GNUNET_NO;
- }
- return GNUNET_YES;
- }
- /**
- * Find the address information struct for the
- * given address (ignoring sessions)
- *
- * @param address address to look for
- * @return NULL if this combination is unknown
- */
- static struct AddressInfo *
- find_ai_no_session (const struct GNUNET_HELLO_Address *address)
- {
- struct FindClosure fc;
- fc.address = address;
- fc.session = NULL;
- fc.ret = NULL;
- GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
- &address->peer,
- &find_ai_no_session_cb,
- &fc);
- return fc.ret;
- }
- /**
- * Test if ATS knows about this @a address and @a session.
- * Note that even if the address is expired, we return
- * #GNUNET_YES if the respective session matches.
- *
- * @param address the address
- * @param session the session
- * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
- */
- int
- GST_ats_is_known (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session)
- {
- return (NULL != find_ai (address, session)) ? GNUNET_YES : GNUNET_NO;
- }
- /**
- * Test if ATS knows about this @a address. Note that
- * expired addresses do not count.
- *
- * @param address the address
- * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
- */
- int
- GST_ats_is_known_no_session (const struct GNUNET_HELLO_Address *address)
- {
- return (NULL != find_ai_no_session (address))
- ? GNUNET_YES
- : GNUNET_NO;
- }
- /**
- * The blocking time for an address has expired, allow ATS to
- * suggest it again.
- *
- * @param cls the `struct AddressInfo` of the address to unblock
- */
- static void
- unblock_address (void *cls)
- {
- struct AddressInfo *ai = cls;
- ai->unblock_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Unblocking address %s of peer %s\n",
- GST_plugins_a2s (ai->address),
- GNUNET_i2s (&ai->address->peer));
- ai->ar = GNUNET_ATS_address_add (GST_ats,
- ai->address,
- ai->session,
- &ai->properties);
- GNUNET_break (NULL != ai->ar);
- num_blocked--;
- publish_p2a_stat_update ();
- }
- /**
- * 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 GNUNET_ATS_Session *session)
- {
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- ai = find_ai (address,
- session);
- if ((NULL == ai) || (NULL == ai->ar))
- {
- /* The address is already gone/blocked, this can happen during a blacklist
- * callback. */
- return;
- }
- ai->back_off = GNUNET_TIME_STD_BACKOFF (ai->back_off);
- if (GNUNET_YES ==
- GNUNET_HELLO_address_check_option (address,
- GNUNET_HELLO_ADDRESS_INFO_INBOUND))
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Removing address %s of peer %s from use (inbound died)\n",
- GST_plugins_a2s (address),
- GNUNET_i2s (&address->peer));
- else
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Blocking address %s of peer %s from use for %s\n",
- GST_plugins_a2s (address),
- GNUNET_i2s (&address->peer),
- GNUNET_STRINGS_relative_time_to_string (ai->back_off,
- GNUNET_YES));
- /* destroy session and address */
- if ((NULL == session) ||
- (GNUNET_NO ==
- GNUNET_ATS_address_del_session (ai->ar,
- session)))
- {
- GNUNET_ATS_address_destroy (ai->ar);
- }
- /* "ar" has been freed, regardless how the branch
- above played out: it was either freed in
- #GNUNET_ATS_address_del_session() because it was
- incoming, or explicitly in
- #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
- /* determine when the address should come back to life */
- ai->blocked = GNUNET_TIME_relative_to_absolute (ai->back_off);
- ai->unblock_task = GNUNET_SCHEDULER_add_delayed (ai->back_off,
- &unblock_address,
- ai);
- num_blocked++;
- publish_p2a_stat_update ();
- }
- /**
- * Reset address blocking time. Resets the exponential
- * back-off timer for this address to zero. Called when
- * an address was used to create a successful connection.
- *
- * @param address the address to reset the blocking timer
- * @param session the session (can be NULL)
- */
- void
- GST_ats_block_reset (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session)
- {
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- ai = find_ai (address, session);
- if (NULL == ai)
- {
- GNUNET_break (0);
- return;
- }
- /* address is in successful use, so it should not be blocked right now */
- GNUNET_break (NULL == ai->unblock_task);
- ai->back_off = GNUNET_TIME_UNIT_ZERO;
- }
- /**
- * Notify ATS about a new inbound @a address. The @a address in
- * combination with the @a session must be new, but this function will
- * perform a santiy check. If the @a address is indeed new, make it
- * available to ATS.
- *
- * @param address the address
- * @param session the session
- * @param prop performance information
- */
- void
- GST_ats_add_inbound_address (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session,
- const struct GNUNET_ATS_Properties *prop)
- {
- struct GNUNET_ATS_AddressRecord *ar;
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- /* Sanity checks for a valid inbound address */
- if (NULL == address->transport_name)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_HELLO_address_check_option (address,
- GNUNET_HELLO_ADDRESS_INFO_INBOUND));
- GNUNET_assert (NULL != session);
- ai = find_ai (address, session);
- if (NULL != ai)
- {
- /* This should only be called for new sessions, and thus
- we should not already have the address */
- GNUNET_break (0);
- return;
- }
- /* Is indeed new, let's tell ATS */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Notifying ATS about peer `%s''s new inbound address `%s' session %p in network %s\n",
- GNUNET_i2s (&address->peer),
- GST_plugins_a2s (address),
- session,
- GNUNET_NT_to_string (prop->scope));
- ar = GNUNET_ATS_address_add (GST_ats,
- address,
- session,
- prop);
- GNUNET_assert (NULL != ar);
- ai = GNUNET_new (struct AddressInfo);
- ai->address = GNUNET_HELLO_address_copy (address);
- ai->session = session;
- ai->properties = *prop;
- ai->ar = ar;
- (void) GNUNET_CONTAINER_multipeermap_put (p2a,
- &ai->address->peer,
- ai,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- publish_p2a_stat_update ();
- }
- /**
- * Notify ATS about the new address including the network this address is
- * located in. The address must NOT be inbound and must be new to ATS.
- *
- * @param address the address
- * @param prop performance information
- */
- void
- GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
- const struct GNUNET_ATS_Properties *prop)
- {
- struct GNUNET_ATS_AddressRecord *ar;
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- /* validadte address */
- if (NULL == address->transport_name)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_assert (GNUNET_YES !=
- GNUNET_HELLO_address_check_option (address,
- GNUNET_HELLO_ADDRESS_INFO_INBOUND));
- ai = find_ai_no_session (address);
- GNUNET_assert (NULL == ai);
- GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
- /* address seems sane, let's tell ATS */
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Notifying ATS about peer %s's new address `%s'\n",
- GNUNET_i2s (&address->peer),
- GST_plugins_a2s (address));
- ar = GNUNET_ATS_address_add (GST_ats,
- address,
- NULL,
- prop);
- GNUNET_assert (NULL != ar);
- ai = GNUNET_new (struct AddressInfo);
- ai->address = GNUNET_HELLO_address_copy (address);
- ai->ar = ar;
- ai->properties = *prop;
- (void) GNUNET_CONTAINER_multipeermap_put (p2a,
- &ai->address->peer,
- ai,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- publish_p2a_stat_update ();
- }
- /**
- * Notify ATS about a new @a session now existing for the given
- * @a address. Essentially, an outbound @a address was used
- * to establish a @a session. It is safe to call this function
- * repeatedly for the same @a address and @a session pair.
- *
- * @param address the address
- * @param session the session
- */
- void
- GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session)
- {
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- ai = find_ai (address, NULL);
- if (NULL == ai)
- {
- /* We may simply already be aware of the session, even if some
- other part of the code could not tell if it just created a new
- session or just got one recycled from the plugin; hence, we may
- be called with "new" session even for an "old" session; in that
- case, check that this is the case, but just ignore it. */GNUNET_assert (NULL != (find_ai (address, session)));
- return;
- }
- GNUNET_assert (NULL == ai->session);
- ai->session = session;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Telling ATS about new session for peer %s\n",
- GNUNET_i2s (&address->peer));
- /* Note that the address might currently be blocked; we only
- tell ATS about the session if the address is currently not
- blocked; otherwise, ATS will be told about the session on
- unblock. */
- if (NULL != ai->ar)
- GNUNET_ATS_address_add_session (ai->ar,
- session);
- else
- GNUNET_assert (NULL != ai->unblock_task);
- }
- /**
- * Release memory used by the given address data.
- *
- * @param ai the `struct AddressInfo`
- */
- static void
- destroy_ai (struct AddressInfo *ai)
- {
- GNUNET_assert (NULL == ai->session);
- if (NULL != ai->unblock_task)
- {
- GNUNET_SCHEDULER_cancel (ai->unblock_task);
- ai->unblock_task = NULL;
- num_blocked--;
- }
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (p2a,
- &ai->address->peer,
- ai));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Telling ATS to destroy address from peer %s\n",
- GNUNET_i2s (&ai->address->peer));
- if (NULL != ai->ar)
- {
- GNUNET_ATS_address_destroy (ai->ar);
- ai->ar = NULL;
- }
- publish_p2a_stat_update ();
- GNUNET_HELLO_address_free (ai->address);
- GNUNET_free (ai);
- }
- /**
- * Notify ATS that the @a session (but not the @a address) of
- * a given @a address is no longer relevant. (The @a session
- * went down.) This function may be called even if for the
- * respective outbound address #GST_ats_new_session() was
- * never called and thus the pair is unknown to ATS. In this
- * case, the call is simply ignored.
- *
- * @param address the address
- * @param session the session
- */
- void
- GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_ATS_Session *session)
- {
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- if (NULL == session)
- {
- GNUNET_break (0);
- return;
- }
- ai = find_ai (address,
- session);
- if (NULL == ai)
- {
- /* We sometimes create sessions just for sending a PING,
- and if those are destroyed they were never known to
- ATS which means we end up here (however, in this
- case, the address must be an outbound address). */
- GNUNET_break (GNUNET_YES !=
- GNUNET_HELLO_address_check_option (address,
- GNUNET_HELLO_ADDRESS_INFO_INBOUND));
- return;
- }
- GNUNET_assert (session == ai->session);
- ai->session = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Telling ATS to destroy session %p from peer %s\n",
- session,
- GNUNET_i2s (&address->peer));
- if (GNUNET_YES == ai->expired)
- {
- /* last reason to keep this 'ai' around is now gone, the
- session is dead as well, clean up */
- if (NULL != ai->ar)
- {
- /* Address expired but not blocked, and thus 'ar' was still
- live because of the session; deleting just the session
- will do for an inbound session, but for an outbound we
- then also need to destroy the address with ATS. */
- if (GNUNET_NO ==
- GNUNET_ATS_address_del_session (ai->ar,
- session))
- {
- GNUNET_ATS_address_destroy (ai->ar);
- }
- /* "ar" has been freed, regardless how the branch
- above played out: it was either freed in
- #GNUNET_ATS_address_del_session() because it was
- incoming, or explicitly in
- #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
- }
- destroy_ai (ai);
- return;
- }
- if (NULL == ai->ar)
- {
- /* If ATS doesn't know about the address/session, this means
- this address was blocked. */
- if (GNUNET_YES ==
- GNUNET_HELLO_address_check_option (address,
- GNUNET_HELLO_ADDRESS_INFO_INBOUND))
- {
- /* This was a blocked inbound session, which now lost the
- session. But inbound addresses are by themselves useless,
- so we must forget about the address as well. */
- destroy_ai (ai);
- return;
- }
- /* Otherwise, we are done as we have set `ai->session` to NULL
- already and ATS will simply not be told about the session when
- the connection is unblocked and the outbound address becomes
- available again. . */
- return;
- }
- /* This is the "simple" case where ATS knows about the session and
- the address is neither blocked nor expired. Delete the session,
- and if it was inbound, free the address as well. */
- if (GNUNET_YES ==
- GNUNET_ATS_address_del_session (ai->ar,
- session))
- {
- /* This was an inbound address, the session is now gone, so we
- need to also forget about the address itself. */
- ai->ar = NULL;
- destroy_ai (ai);
- }
- }
- /**
- * Notify ATS about DV @a distance change to an @a address.
- * Does nothing if the @a address is not known to us.
- *
- * @param address the address
- * @param distance new distance value
- */
- void
- GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
- uint32_t distance)
- {
- struct AddressInfo *ai;
- ai = find_ai_no_session (address);
- if (NULL == ai)
- {
- /* We do not know about this address, do nothing. */
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Updated distance for peer `%s' to %u\n",
- GNUNET_i2s (&address->peer),
- distance);
- ai->properties.distance = distance;
- /* Give manipulation its chance to change metrics */
- GST_manipulation_manipulate_metrics (address,
- ai->session,
- &ai->properties);
- /* Address may be blocked, only give ATS if address is
- currently active. */
- if (NULL != ai->ar)
- GNUNET_ATS_address_update (ai->ar,
- &ai->properties);
- }
- /**
- * Notify ATS about @a delay changes to properties of an @a address.
- * Does nothing if the @a address is not known to us.
- *
- * @param address the address
- * @param delay new delay value
- */
- void
- GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Relative delay)
- {
- struct AddressInfo *ai;
- ai = find_ai_no_session (address);
- if (NULL == ai)
- {
- /* We do not know about this address, do nothing. */
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Updated latency for peer `%s' to %s\n",
- GNUNET_i2s (&address->peer),
- GNUNET_STRINGS_relative_time_to_string (delay,
- GNUNET_YES));
- ai->properties.delay = delay;
- /* Give manipulation its chance to change metrics */
- GST_manipulation_manipulate_metrics (address,
- ai->session,
- &ai->properties);
- /* Address may be blocked, only give ATS if address is
- currently active. */
- if (NULL != ai->ar)
- GNUNET_ATS_address_update (ai->ar,
- &ai->properties);
- }
- /**
- * Notify ATS about utilization changes to an @a address.
- * Does nothing if the @a address is not known to us.
- *
- * @param address our information about the address
- * @param bps_in new utilization inbound
- * @param bps_out new utilization outbound
- */
- void
- GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
- uint32_t bps_in,
- uint32_t bps_out)
- {
- struct AddressInfo *ai;
- ai = find_ai_no_session (address);
- if (NULL == ai)
- {
- /* We do not know about this address, do nothing. */
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Updating utilization for peer `%s' address %s: %u/%u\n",
- GNUNET_i2s (&address->peer),
- GST_plugins_a2s (address),
- (unsigned int) bps_in,
- (unsigned int) bps_out);
- ai->properties.utilization_in = bps_in;
- ai->properties.utilization_out = bps_out;
- /* Give manipulation its chance to change metrics */
- GST_manipulation_manipulate_metrics (address,
- ai->session,
- &ai->properties);
- /* Address may be blocked, only give ATS if address is
- currently active. */
- if (NULL != ai->ar)
- GNUNET_ATS_address_update (ai->ar,
- &ai->properties);
- }
- /**
- * Notify ATS that the address has expired and thus cannot
- * be used any longer. This function must only be called
- * if the corresponding session is already gone.
- *
- * @param address the address
- */
- void
- GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
- {
- struct AddressInfo *ai;
- if (0 ==
- memcmp (&GST_my_identity,
- &address->peer,
- sizeof(struct GNUNET_PeerIdentity)))
- return; /* our own, ignore! */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Address %s of peer %s expired\n",
- GST_plugins_a2s (address),
- GNUNET_i2s (&address->peer));
- ai = find_ai_no_session (address);
- if (NULL == ai)
- {
- GNUNET_assert (0);
- return;
- }
- if (NULL != ai->session)
- {
- /* Got an active session, just remember the expiration
- and act upon it when the session goes down. */
- ai->expired = GNUNET_YES;
- return;
- }
- /* Address expired, no session, free resources */
- destroy_ai (ai);
- }
- /**
- * Initialize ATS subsystem.
- */
- void
- GST_ats_init ()
- {
- p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
- }
- /**
- * Release memory used by the given address data.
- *
- * @param cls NULL
- * @param key which peer is this about
- * @param value the `struct AddressInfo`
- * @return #GNUNET_OK (continue to iterate)
- */
- static int
- destroy_ai_cb (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct AddressInfo *ai = value;
- destroy_ai (ai);
- return GNUNET_OK;
- }
- /**
- * Shutdown ATS subsystem.
- */
- void
- GST_ats_done ()
- {
- GNUNET_CONTAINER_multipeermap_iterate (p2a,
- &destroy_ai_cb,
- NULL);
- publish_p2a_stat_update ();
- GNUNET_CONTAINER_multipeermap_destroy (p2a);
- p2a = NULL;
- }
- /* end of gnunet-service-transport_ats.c */
|