/* 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 . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file ats/gnunet-service-ats_performance.c * @brief ats service, interaction with 'performance' API * @author Matthias Wachs * @author Christian Grothoff * * TODO: * - simplify functions by passing a `struct GNUNET_HELLO_Address` */ #include "platform.h" #include "gnunet-service-ats.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_performance.h" #include "ats.h" /** * Context for sending messages to performance clients without PIC. */ static struct GNUNET_NotificationContext *nc_no_pic; /** * Context for sending messages to performance clients with PIC. */ static struct GNUNET_NotificationContext *nc_pic; /** * Transmit the given performance information to all performance * clients. * * @param client client to send to, NULL for all * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in plugin_addr * @param active #GNUNET_YES if this address is actively used * to maintain a connection to a peer; * #GNUNET_NO if the address is not actively used; * #GNUNET_SYSERR if this address is no longer available for ATS * @param prop performance data for the address * @param local_address_info information about the local flags for the address * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ static void notify_client (struct GNUNET_SERVICE_Client *client, const struct GNUNET_PeerIdentity *peer, 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 PeerInformationMessage *msg; size_t plugin_name_length = strlen (plugin_name) + 1; size_t msize = sizeof (struct PeerInformationMessage) + plugin_addr_len + plugin_name_length; char buf[msize] GNUNET_ALIGN; char *addrp; if (NULL != prop) GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope); GNUNET_assert (msize < GNUNET_MAX_MESSAGE_SIZE); msg = (struct PeerInformationMessage *) buf; msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION); msg->id = htonl (0); msg->peer = *peer; msg->address_length = htons (plugin_addr_len); msg->address_active = ntohl ((uint32_t) 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); else memset (&msg->properties, 0, sizeof (struct GNUNET_ATS_Properties)); msg->address_local_info = htonl (local_address_info); addrp = (char *) &msg[1]; GNUNET_memcpy (addrp, plugin_addr, plugin_addr_len); strcpy (&addrp[plugin_addr_len], plugin_name); if (NULL == client) { GNUNET_notification_context_broadcast (nc_pic, &msg->header, GNUNET_YES); } else { struct GNUNET_MQ_Envelope *env; env = GNUNET_MQ_msg_copy (&msg->header); GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); } } /** * Transmit the given performance information to all performance * clients. * * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in @a plugin_addr * @param active #GNUNET_YES if this address is actively used * to maintain a connection to a peer; * #GNUNET_NO if the address is not actively used; * #GNUNET_SYSERR if this address is no longer available for ATS * @param prop performance data for the address * @param local_address_info information about the local flags for the address * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ void GAS_performance_notify_all_clients (const struct GNUNET_PeerIdentity *peer, 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) { GNUNET_break ( (NULL == prop) || (GNUNET_NT_UNSPECIFIED != prop->scope) ); notify_client (NULL, peer, plugin_name, plugin_addr, plugin_addr_len, active, prop, local_address_info, bandwidth_out, bandwidth_in); GNUNET_STATISTICS_update (GSA_stats, "# performance updates given to clients", 1, GNUNET_NO); } /** * Iterator for called from #GAS_addresses_get_peer_info() * * @param cls closure with the `struct GNUNET_SERVICE_Client *` to inform. * @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 information about the local flags for the address * @param bandwidth_out current outbound bandwidth assigned to address * @param bandwidth_in current inbound bandwidth assigned to address */ static void 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 GNUNET_SERVICE_Client *client = cls; if (NULL == id) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer `%s' plugin `%s' BW out %u, BW in %u \n", GNUNET_i2s (id), plugin_name, (unsigned int) ntohl (bandwidth_out.value__), (unsigned int) ntohl (bandwidth_in.value__)); GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope); notify_client (client, id, plugin_name, plugin_addr, plugin_addr_len, active, prop, local_address_info, bandwidth_out, bandwidth_in); } /** * Register a new performance client. * * @param client handle of the new client * @param flag flag specifying the type of the client */ void GAS_performance_add_client (struct GNUNET_SERVICE_Client *client, enum StartFlag flag) { struct GNUNET_MQ_Handle *mq; mq = GNUNET_SERVICE_client_get_mq (client); if (START_FLAG_PERFORMANCE_WITH_PIC == flag) { GNUNET_notification_context_add (nc_pic, mq); GAS_addresses_get_peer_info (NULL, &peerinfo_it, client); } else { GNUNET_notification_context_add (nc_no_pic, mq); } } /** * Initialize performance subsystem. * * @param server handle to our server */ void GAS_performance_init () { nc_no_pic = GNUNET_notification_context_create (32); nc_pic = GNUNET_notification_context_create (32); } /** * Shutdown performance subsystem. */ void GAS_performance_done () { GNUNET_notification_context_destroy (nc_no_pic); nc_no_pic = NULL; GNUNET_notification_context_destroy (nc_pic); nc_pic = NULL; } /* end of gnunet-service-ats_performance.c */