123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2011-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 ats/gnunet-service-ats_addresses.c
- * @brief ats service address management
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
- #include "platform.h"
- #include "gnunet-service-ats_addresses.h"
- #include "gnunet-service-ats_performance.h"
- #include "gnunet-service-ats_normalization.h"
- #include "gnunet-service-ats_plugins.h"
- /**
- * A multihashmap to store all addresses
- */
- struct GNUNET_CONTAINER_MultiPeerMap *GSA_addresses;
- /**
- * Update statistic on number of addresses.
- */
- static void
- update_addresses_stat ()
- {
- GNUNET_STATISTICS_set (GSA_stats,
- "# addresses",
- GNUNET_CONTAINER_multipeermap_size (GSA_addresses),
- GNUNET_NO);
- }
- /**
- * Free the given address
- *
- * @param addr address to destroy
- */
- static void
- free_address (struct ATS_Address *addr)
- {
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (GSA_addresses,
- &addr->peer,
- addr));
- update_addresses_stat ();
- GAS_plugin_delete_address (addr);
- GAS_performance_notify_all_clients (&addr->peer,
- addr->plugin,
- addr->addr,
- addr->addr_len,
- GNUNET_NO,
- NULL,
- addr->local_address_info,
- GNUNET_BANDWIDTH_ZERO,
- GNUNET_BANDWIDTH_ZERO);
- GNUNET_free (addr->plugin);
- GNUNET_free (addr);
- }
- /**
- * Initialize @a norm. Sets all historic values to undefined.
- *
- * @param norm normalization data to initialize
- */
- static void
- init_norm (struct GAS_NormalizationInfo *norm)
- {
- unsigned int c;
- for (c = 0; c < GAS_normalization_queue_length; c++)
- norm->atsi_abs[c] = UINT64_MAX;
- }
- /**
- * Create a ATS_address with the given information
- *
- * @param peer peer
- * @param plugin_name plugin
- * @param plugin_addr address
- * @param plugin_addr_len address length
- * @param local_address_info additional local info for the address
- * @param session_id session identifier, can never be 0
- * @return the ATS_Address
- */
- static struct ATS_Address *
- create_address (const struct GNUNET_PeerIdentity *peer,
- const char *plugin_name,
- const void *plugin_addr,
- size_t plugin_addr_len,
- uint32_t local_address_info,
- uint32_t session_id)
- {
- struct ATS_Address *aa;
- aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
- aa->peer = *peer;
- aa->addr_len = plugin_addr_len;
- aa->addr = &aa[1];
- GNUNET_memcpy (&aa[1],
- plugin_addr,
- plugin_addr_len);
- aa->plugin = GNUNET_strdup (plugin_name);
- aa->session_id = session_id;
- aa->local_address_info = local_address_info;
- init_norm (&aa->norm_delay);
- init_norm (&aa->norm_distance);
- init_norm (&aa->norm_utilization_in);
- init_norm (&aa->norm_utilization_out);
- return aa;
- }
- /**
- * Closure for #find_address_cb()
- */
- struct FindAddressContext
- {
- /**
- * Session Id to look for.
- */
- uint32_t session_id;
- /**
- * Where to store matching address result.
- */
- struct ATS_Address *exact_address;
- };
- /**
- * Find session matching given session ID.
- *
- * @param cls a `struct FindAddressContext`
- * @param key peer id
- * @param value the address to compare with
- * @return #GNUNET_YES to continue, #GNUNET_NO if address is found
- */
- static int
- find_address_cb (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct FindAddressContext *fac = cls;
- struct ATS_Address *aa = value;
- if (aa->session_id == fac->session_id)
- {
- fac->exact_address = aa;
- return GNUNET_NO;
- }
- return GNUNET_YES;
- }
- /**
- * Find the exact address
- *
- * @param peer peer
- * @param session_id session id, can never be 0
- * @return an ATS_address or NULL
- */
- static struct ATS_Address *
- find_exact_address (const struct GNUNET_PeerIdentity *peer,
- uint32_t session_id)
- {
- struct FindAddressContext fac;
- fac.exact_address = NULL;
- fac.session_id = session_id;
- GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
- peer,
- &find_address_cb, &fac);
- return fac.exact_address;
- }
- /**
- * Add a new address for a peer.
- *
- * @param peer peer
- * @param plugin_name transport plugin name
- * @param plugin_addr plugin address
- * @param plugin_addr_len length of the plugin address in @a plugin_addr
- * @param local_address_info the local address for the address
- * @param session_id session id, can be 0
- * @param prop performance information for this address
- */
- void
- GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
- const char *plugin_name,
- const void *plugin_addr,
- size_t plugin_addr_len,
- uint32_t local_address_info,
- uint32_t session_id,
- const struct GNUNET_ATS_Properties *prop)
- {
- struct ATS_Address *new_address;
- if (NULL != find_exact_address (peer,
- session_id))
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
- new_address = create_address (peer,
- plugin_name,
- plugin_addr,
- plugin_addr_len,
- local_address_info,
- session_id);
- /* Add a new address */
- new_address->properties = *prop;
- new_address->t_added = GNUNET_TIME_absolute_get();
- new_address->t_last_activity = GNUNET_TIME_absolute_get();
- GNUNET_assert(GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (GSA_addresses,
- peer,
- new_address,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
- update_addresses_stat ();
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Adding new address for peer `%s' slot %u\n",
- GNUNET_i2s (peer),
- session_id);
- /* Tell solver about new address */
- GAS_plugin_solver_lock ();
- GAS_plugin_new_address (new_address);
- GAS_normalization_update_property (new_address); // FIXME: needed?
- GAS_plugin_solver_unlock ();
- /* Notify performance clients about new address */
- GAS_performance_notify_all_clients (&new_address->peer,
- new_address->plugin,
- new_address->addr,
- new_address->addr_len,
- new_address->active,
- &new_address->properties,
- new_address->local_address_info,
- GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_in));
- }
- /**
- * Update an address with new performance information for a peer.
- *
- * @param peer peer
- * @param session_id session id, never 0
- * @param prop performance information for this address
- */
- void
- GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
- uint32_t session_id,
- const struct GNUNET_ATS_Properties *prop)
- {
- struct ATS_Address *aa;
- /* Get existing address */
- aa = find_exact_address (peer,
- session_id);
- if (NULL == aa)
- {
- GNUNET_break (0);
- return;
- }
- if (NULL == aa->solver_information)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ADDRESS_UPDATE for peer `%s' slot %u\n",
- GNUNET_i2s (peer),
- (unsigned int) session_id);
- GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
- /* Update address */
- aa->t_last_activity = GNUNET_TIME_absolute_get();
- aa->properties = *prop;
- /* Notify performance clients about updated address */
- GAS_performance_notify_all_clients (&aa->peer,
- aa->plugin,
- aa->addr,
- aa->addr_len,
- aa->active,
- prop,
- aa->local_address_info,
- GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
- GAS_normalization_update_property (aa);
- }
- /**
- * Remove an address for a peer.
- *
- * @param peer peer
- * @param session_id session id, can never be 0
- */
- void
- GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
- uint32_t session_id)
- {
- struct ATS_Address *ea;
- /* Get existing address */
- ea = find_exact_address (peer,
- session_id);
- if (NULL == ea)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ADDRESS_DESTROYED for peer `%s' session %u\n",
- GNUNET_i2s (peer),
- session_id);
- free_address (ea);
- }
- /**
- * Initialize address subsystem. The addresses subsystem manages the addresses
- * known and current performance information. It has a solver component
- * responsible for the resource allocation. It tells the solver about changes
- * and receives updates when the solver changes the resource allocation.
- */
- void
- GAS_addresses_init ()
- {
- GSA_addresses
- = GNUNET_CONTAINER_multipeermap_create (128,
- GNUNET_NO);
- update_addresses_stat ();
- }
- /**
- * Destroy all addresses iterator
- *
- * @param cls NULL
- * @param key peer identity (unused)
- * @param value the 'struct ATS_Address' to free
- * @return #GNUNET_OK (continue to iterate)
- */
- static int
- destroy_all_address_it (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct ATS_Address *aa = value;
- free_address (aa);
- return GNUNET_OK;
- }
- /**
- * Remove all addresses
- */
- void
- GAS_addresses_destroy_all ()
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Destroying all addresses\n");
- if (0 ==
- GNUNET_CONTAINER_multipeermap_size (GSA_addresses))
- return;
- GAS_plugin_solver_lock ();
- GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
- &destroy_all_address_it,
- NULL);
- GAS_plugin_solver_unlock ();
- }
- /**
- * Shutdown address subsystem.
- */
- void
- GAS_addresses_done ()
- {
- GNUNET_log(GNUNET_ERROR_TYPE_INFO,
- "Shutting down addresses\n");
- GAS_plugin_solver_lock ();
- GAS_addresses_destroy_all ();
- GAS_plugin_solver_unlock ();
- GNUNET_CONTAINER_multipeermap_destroy (GSA_addresses);
- GSA_addresses = NULL;
- }
- /**
- * Closure for #peerinfo_it().
- */
- struct PeerInfoIteratorContext
- {
- /**
- * Function to call for each address.
- */
- GNUNET_ATS_PeerInfo_Iterator it;
- /**
- * Closure for @e it.
- */
- void *it_cls;
- };
- /**
- * Iterator to iterate over a peer's addresses
- *
- * @param cls a `struct PeerInfoIteratorContext`
- * @param key the peer id
- * @param value the `struct ATS_address`
- * @return #GNUNET_OK to continue
- */
- static int
- peerinfo_it (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
- {
- struct PeerInfoIteratorContext *pi_ctx = cls;
- struct ATS_Address *addr = value;
- pi_ctx->it (pi_ctx->it_cls,
- &addr->peer,
- addr->plugin,
- addr->addr,
- addr->addr_len,
- addr->active,
- &addr->properties,
- addr->local_address_info,
- GNUNET_BANDWIDTH_value_init (addr->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (addr->assigned_bw_in));
- return GNUNET_OK;
- }
- /**
- * Return information all peers currently known to ATS
- *
- * @param peer the respective peer, NULL for 'all' peers
- * @param pi_it the iterator to call for every peer
- * @param pi_it_cls the closure for @a pi_it
- */
- void
- GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
- GNUNET_ATS_PeerInfo_Iterator pi_it,
- void *pi_it_cls)
- {
- struct PeerInfoIteratorContext pi_ctx;
- if (NULL == pi_it)
- {
- /* does not make sense without callback */
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Returning information for %s from a total of %u known addresses\n",
- (NULL == peer)
- ? "all peers"
- : GNUNET_i2s (peer),
- (unsigned int) GNUNET_CONTAINER_multipeermap_size (GSA_addresses));
- pi_ctx.it = pi_it;
- pi_ctx.it_cls = pi_it_cls;
- if (NULL == peer)
- GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
- &peerinfo_it,
- &pi_ctx);
- else
- GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
- peer,
- &peerinfo_it, &pi_ctx);
- pi_it (pi_it_cls,
- NULL, NULL, NULL, 0,
- GNUNET_NO,
- NULL,
- GNUNET_HELLO_ADDRESS_INFO_NONE,
- GNUNET_BANDWIDTH_ZERO,
- GNUNET_BANDWIDTH_ZERO);
- }
- /**
- * Information we need for the callbacks to return a list of addresses
- * back to the client.
- */
- struct AddressIteration
- {
- /**
- * Actual handle to the client.
- */
- struct GNUNET_SERVICE_Client *client;
- /**
- * Are we sending all addresses, or only those that are active?
- */
- int all;
- /**
- * Which ID should be included in the response?
- */
- uint32_t id;
- };
- /**
- * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
- * given address details to the client identified in @a ai.
- *
- * @param ai our address information context (identifies the client)
- * @param id the peer id this address is for
- * @param plugin_name name of the plugin that supports this address
- * @param plugin_addr address
- * @param plugin_addr_len length of @a plugin_addr
- * @param active #GNUNET_YES if this address is actively used
- * @param prop performance information
- * @param local_address_info flags for the address
- * @param bandwidth_out current outbound bandwidth assigned to address
- * @param bandwidth_in current inbound bandwidth assigned to address
- */
- static void
- transmit_req_addr (struct AddressIteration *ai,
- const struct GNUNET_PeerIdentity *id,
- const char *plugin_name,
- const void *plugin_addr,
- size_t plugin_addr_len,
- int active,
- const struct GNUNET_ATS_Properties *prop,
- enum GNUNET_HELLO_AddressInfo local_address_info,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
- {
- struct GNUNET_MQ_Envelope *env;
- struct PeerInformationMessage *msg;
- char *addrp;
- size_t plugin_name_length;
- size_t msize;
- if (NULL != plugin_name)
- plugin_name_length = strlen (plugin_name) + 1;
- else
- plugin_name_length = 0;
- msize = plugin_addr_len + plugin_name_length;
- GNUNET_assert (sizeof (struct PeerInformationMessage) + msize
- < GNUNET_MAX_MESSAGE_SIZE);
- env = GNUNET_MQ_msg_extra (msg,
- msize,
- GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
- msg->id = htonl (ai->id);
- if (NULL != id)
- msg->peer = *id;
- msg->address_length = htons (plugin_addr_len);
- msg->address_active = ntohl (active);
- msg->plugin_name_length = htons (plugin_name_length);
- msg->bandwidth_out = bandwidth_out;
- msg->bandwidth_in = bandwidth_in;
- if (NULL != prop)
- GNUNET_ATS_properties_hton (&msg->properties,
- prop);
- msg->address_local_info = htonl ((uint32_t) local_address_info);
- addrp = (char *) &msg[1];
- GNUNET_memcpy (addrp,
- plugin_addr,
- plugin_addr_len);
- if (NULL != plugin_name)
- strcpy (&addrp[plugin_addr_len],
- plugin_name);
- GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (ai->client),
- env);
- }
- /**
- * Iterator for #GAS_addresses_get_peer_info(), called with peer-specific
- * information to be passed back to the client.
- *
- * @param cls closure with our `struct AddressIteration *`
- * @param id the peer id
- * @param plugin_name plugin name
- * @param plugin_addr address
- * @param plugin_addr_len length of @a plugin_addr
- * @param active is address actively used
- * @param prop performance information
- * @param local_address_info additional local info for the address
- * @param bandwidth_out current outbound bandwidth assigned to address
- * @param bandwidth_in current inbound bandwidth assigned to address
- */
- static void
- req_addr_peerinfo_it (void *cls,
- const struct GNUNET_PeerIdentity *id,
- const char *plugin_name,
- const void *plugin_addr,
- size_t plugin_addr_len,
- int active,
- const struct GNUNET_ATS_Properties *prop,
- enum GNUNET_HELLO_AddressInfo local_address_info,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
- {
- struct AddressIteration *ai = cls;
- if ( (NULL == id) &&
- (NULL == plugin_name) &&
- (NULL == plugin_addr) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Address iteration done for one peer\n");
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Callback for %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
- (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
- GNUNET_i2s (id),
- plugin_name,
- (unsigned int) ntohl (bandwidth_out.value__),
- (unsigned int) ntohl (bandwidth_in.value__));
- /* Transmit result (either if address is active, or if
- client wanted all addresses) */
- if ( (GNUNET_YES != ai->all) &&
- (GNUNET_YES != active))
- return;
- transmit_req_addr (ai,
- id,
- plugin_name,
- plugin_addr, plugin_addr_len,
- active,
- prop,
- local_address_info,
- bandwidth_out,
- bandwidth_in);
- }
- /**
- * Handle 'address list request' messages from clients.
- *
- * @param cls client that sent the request
- * @param alrm the request message
- */
- void
- GAS_handle_request_address_list (struct GNUNET_SERVICE_Client *client,
- const struct AddressListRequestMessage *alrm)
- {
- struct AddressIteration ai;
- struct GNUNET_PeerIdentity allzeros;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ADDRESSLIST_REQUEST message\n");
- ai.all = ntohl (alrm->all);
- ai.id = ntohl (alrm->id);
- ai.client = client;
- memset (&allzeros,
- '\0',
- sizeof (struct GNUNET_PeerIdentity));
- if (0 == memcmp (&alrm->peer,
- &allzeros,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- /* Return addresses for all peers */
- GAS_addresses_get_peer_info (NULL,
- &req_addr_peerinfo_it,
- &ai);
- }
- else
- {
- /* Return addresses for a specific peer */
- GAS_addresses_get_peer_info (&alrm->peer,
- &req_addr_peerinfo_it,
- &ai);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finished handling `%s' message\n",
- "ADDRESSLIST_REQUEST");
- transmit_req_addr (&ai,
- NULL, NULL, NULL,
- 0, GNUNET_NO,
- NULL,
- GNUNET_HELLO_ADDRESS_INFO_NONE,
- GNUNET_BANDWIDTH_ZERO,
- GNUNET_BANDWIDTH_ZERO);
- }
- /* end of gnunet-service-ats_addresses.c */
|