From 107b3a706cf4d2f0276fb7534a846de5d36a73a9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 10 Oct 2011 10:59:00 +0000 Subject: [PATCH] adding change preference API to ATS --- src/ats/Makefile.am | 3 +- src/ats/ats_api.c | 115 +-------- src/ats/ats_api.h | 138 ++++++++++ src/ats/ats_api_peer_change_preference.c | 310 +++++++++++++++++++++++ src/include/gnunet_ats_service.h | 72 ++++++ 5 files changed, 535 insertions(+), 103 deletions(-) create mode 100644 src/ats/ats_api.h create mode 100644 src/ats/ats_api_peer_change_preference.c diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am index fbb20f66e..22e8de8aa 100644 --- a/src/ats/Makefile.am +++ b/src/ats/Makefile.am @@ -11,7 +11,8 @@ endif lib_LTLIBRARIES = libgnunetats.la libgnunetats_la_SOURCES = \ - ats_api.c + ats_api.c ats_api.h \ + ats_api_peer_change_preference.c libgnunetats_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/ats/ats_api.c b/src/ats/ats_api.c index ce598c4e3..48f15a73f 100644 --- a/src/ats/ats_api.c +++ b/src/ats/ats_api.c @@ -32,67 +32,22 @@ */ #include "platform.h" #include "gnunet_ats_service.h" +#include "ats_api.h" #define DEBUG_ATS GNUNET_EXTRA_LOGGING +/** + * Receive and send buffer windows grow over time. For + * how long can 'unused' bandwidth accumulate before we + * need to cap it? (specified in seconds). + */ +#define MAX_WINDOW_TIME_S (5 * 60) + // NOTE: this implementation is simply supposed // to implement a simplistic strategy in-process; // in the future, we plan to replace it with a real // service implementation -/** - * Allocation record for a peer's address. - */ -struct AllocationRecord -{ - - /** - * Performance information associated with this address (array). - */ - struct GNUNET_TRANSPORT_ATS_Information *ats; - - /** - * Name of the plugin - */ - char *plugin_name; - - /** - * Address this record represents, allocated at the end of this struct. - */ - const void *plugin_addr; - - /** - * Session associated with this record. - */ - struct Session *session; - - /** - * Number of bytes in plugin_addr. - */ - size_t plugin_addr_len; - - /** - * Number of entries in 'ats'. - */ - uint32_t ats_count; - - /** - * Inbound bandwidth assigned to this address right now, 0 for none. - */ - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; - - /** - * Outbound bandwidth assigned to this address right now, 0 for none. - */ - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; - - /** - * Set to GNUNET_YES if this is the connected address of a connected peer. - */ - int connected; - -}; - /** * Opaque handle to obtain address suggestions. @@ -123,55 +78,6 @@ struct GNUNET_ATS_SuggestionContext }; -/** - * Handle to the ATS subsystem. - */ -struct GNUNET_ATS_Handle -{ - /** - * Configuration. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Function to call when the allocation changes. - */ - GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb; - - /** - * Closure for 'alloc_cb'. - */ - void *alloc_cb_cls; - - /** - * Information about all connected peers. Maps peer identities - * to one or more 'struct AllocationRecord' values. - */ - struct GNUNET_CONTAINER_MultiHashMap *peers; - - /** - * Map of PeerIdentities to 'struct GNUNET_ATS_SuggestionContext's. - */ - struct GNUNET_CONTAINER_MultiHashMap *notify_map; - - - /** - * Task scheduled to update our bandwidth assignment. - */ - GNUNET_SCHEDULER_TaskIdentifier ba_task; - - /** - * Total inbound bandwidth per configuration. - */ - unsigned long long total_bps_in; - - /** - * Total outbound bandwidth per configuration. - */ - unsigned long long total_bps_out; -}; - - /** * Count number of connected records. * @@ -232,6 +138,8 @@ set_bw_connections (void *cls, const GNUNET_HashCode * key, void *value) { ar->bandwidth_in = sbc->bw_in; ar->bandwidth_out = sbc->bw_out; + GNUNET_BANDWIDTH_tracker_update_quota (&ar->available_recv_window, + ar->bandwidth_in); sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, (const struct GNUNET_PeerIdentity *) key, ar->plugin_name, ar->session, ar->plugin_addr, @@ -609,6 +517,9 @@ create_allocation_record (const char *plugin_name, struct Session *session, memcpy (&ar[1], plugin_addr, plugin_addr_len); ar->session = session; ar->plugin_addr_len = plugin_addr_len; + GNUNET_BANDWIDTH_tracker_init (&ar->available_recv_window, + ar->bandwidth_in, + MAX_WINDOW_TIME_S); GNUNET_assert (ats_count > 0); GNUNET_array_grow (ar->ats, ar->ats_count, ats_count); memcpy (ar->ats, ats, diff --git a/src/ats/ats_api.h b/src/ats/ats_api.h new file mode 100644 index 000000000..c3ae24885 --- /dev/null +++ b/src/ats/ats_api.h @@ -0,0 +1,138 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/ats_api.h + * @brief automatic transport selection API common includes + * @author Christian Grothoff + * @author Matthias Wachs + */ +#ifndef ATS_API_H +#define ATS_API_H + +#include "gnunet_util_lib.h" + +/** + * Allocation record for a peer's address. + */ +struct AllocationRecord +{ + + /** + * Performance information associated with this address (array). + */ + struct GNUNET_TRANSPORT_ATS_Information *ats; + + /** + * Name of the plugin + */ + char *plugin_name; + + /** + * Address this record represents, allocated at the end of this struct. + */ + const void *plugin_addr; + + /** + * Session associated with this record. + */ + struct Session *session; + + /** + * Number of bytes in plugin_addr. + */ + size_t plugin_addr_len; + + /** + * Number of entries in 'ats'. + */ + uint32_t ats_count; + + /** + * Inbound bandwidth assigned to this address right now, 0 for none. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /** + * Outbound bandwidth assigned to this address right now, 0 for none. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + /** + * Tracking bandwidth for receiving from this peer. Used for + * applications that want to 'reserve' bandwidth for replies. + */ + struct GNUNET_BANDWIDTH_Tracker available_recv_window; + + /** + * Set to GNUNET_YES if this is the connected address of a connected peer. + */ + int connected; + +}; + + +/** + * Handle to the ATS subsystem. + */ +struct GNUNET_ATS_Handle +{ + /** + * Configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call when the allocation changes. + */ + GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb; + + /** + * Closure for 'alloc_cb'. + */ + void *alloc_cb_cls; + + /** + * Information about all connected peers. Maps peer identities + * to one or more 'struct AllocationRecord' values. + */ + struct GNUNET_CONTAINER_MultiHashMap *peers; + + /** + * Map of PeerIdentities to 'struct GNUNET_ATS_SuggestionContext's. + */ + struct GNUNET_CONTAINER_MultiHashMap *notify_map; + + /** + * Task scheduled to update our bandwidth assignment. + */ + GNUNET_SCHEDULER_TaskIdentifier ba_task; + + /** + * Total inbound bandwidth per configuration. + */ + unsigned long long total_bps_in; + + /** + * Total outbound bandwidth per configuration. + */ + unsigned long long total_bps_out; +}; + +#endif diff --git a/src/ats/ats_api_peer_change_preference.c b/src/ats/ats_api_peer_change_preference.c new file mode 100644 index 000000000..84fc2bf6c --- /dev/null +++ b/src/ats/ats_api_peer_change_preference.c @@ -0,0 +1,310 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/ats_api_peer_change_preference.c + * @brief automatic transport selection API, preference management + * @author Christian Grothoff + * @author Matthias Wachs + * + * TODO: + * - write test case + * - extend API to get performance data + * - implement simplistic strategy based on say 'lowest latency' or strict ordering + * - extend API to get peer preferences, implement proportional bandwidth assignment + * - re-implement API against a real ATS service (!) + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "ats_api.h" + +struct GNUNET_ATS_InformationRequestContext +{ + + /** + * Our connection to the service. + */ + struct GNUNET_ATS_Handle *h; + + /** + * Link to peer record. + */ + struct AllocationRecord *ar; + + int32_t amount; + + uint64_t preference; + + GNUNET_ATS_PeerConfigurationInfoCallback info; + + void *info_cls; + + struct GNUNET_PeerIdentity peer; + + GNUNET_SCHEDULER_TaskIdentifier task; + +}; + + +static void +exec_pcp (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_ATS_InformationRequestContext *irc = cls; + int32_t want_reserv; + int32_t got_reserv; + struct GNUNET_TIME_Relative rdelay; + + rdelay = GNUNET_TIME_UNIT_ZERO; + want_reserv = irc->amount; + if (want_reserv < 0) + { + got_reserv = want_reserv; + } + else if (want_reserv > 0) + { + rdelay = + GNUNET_BANDWIDTH_tracker_get_delay (&irc->ar->available_recv_window, + want_reserv); + if (rdelay.rel_value == 0) + got_reserv = want_reserv; + else + got_reserv = 0; /* all or nothing */ + } + else + got_reserv = 0; + GNUNET_BANDWIDTH_tracker_consume (&irc->ar->available_recv_window, got_reserv); + + irc->info (irc->info_cls, + &irc->peer, + got_reserv, + rdelay); + GNUNET_free (irc); +} + + +/** + * Obtain statistics and/or change preferences for the given peer. + * + * @param h core handle + * @param peer identifies the peer + * @param amount reserve N bytes for receiving, negative + * amounts can be used to undo a (recent) reservation; + * @param preference increase incoming traffic share preference by this amount; + * in the absence of "amount" reservations, we use this + * preference value to assign proportional bandwidth shares + * to all connected peers + * @param info function to call with the resulting configuration information + * @param info_cls closure for info + * @return NULL on error + */ +struct GNUNET_ATS_InformationRequestContext * +GNUNET_ATS_peer_change_preference (struct GNUNET_ATS_Handle *h, + const struct GNUNET_PeerIdentity *peer, + int32_t amount, uint64_t preference, + GNUNET_ATS_PeerConfigurationInfoCallback + info, void *info_cls) +{ + struct GNUNET_ATS_InformationRequestContext *irc; + struct AllocationRecord *ar; + + ar = GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey); + if (NULL == ar) + { + /* attempt to change preference on peer that is not connected */ + GNUNET_assert (0); + return NULL; + } + irc = GNUNET_malloc (sizeof (struct GNUNET_ATS_InformationRequestContext)); + irc->h = h; + irc->peer = *peer; + irc->ar = ar; + irc->amount = amount; + irc->preference = preference; + irc->info = info; + irc->info_cls = info_cls; + irc->task = GNUNET_SCHEDULER_add_now (&exec_pcp, irc); + return irc; +} + + +/** + * Cancel request for getting information about a peer. + * Note that an eventual change in preference, trust or bandwidth + * assignment MAY have already been committed at the time, + * so cancelling a request is NOT sure to undo the original + * request. The original request may or may not still commit. + * The only thing cancellation ensures is that the callback + * from the original request will no longer be called. + * + * @param irc context returned by the original GNUNET_ATS_peer_get_info call + */ +void +GNUNET_ATS_peer_change_preference_cancel (struct + GNUNET_ATS_InformationRequestContext + *irc) +{ + GNUNET_SCHEDULER_cancel (irc->task); + GNUNET_free (irc); +} + + +#if 0 +/* old CORE API implementation follows for future reference */ +struct GNUNET_ATS_InformationRequestContext +{ + + /** + * Our connection to the service. + */ + struct GNUNET_ATS_Handle *h; + + /** + * Link to control message, NULL if CM was sent. + */ + struct ControlMessage *cm; + + /** + * Link to peer record. + */ + struct PeerRecord *pr; +}; + + +/** + * CM was sent, remove link so we don't double-free. + * + * @param cls the 'struct GNUNET_ATS_InformationRequestContext' + * @param success were we successful? + */ +static void +change_preference_send_continuation (void *cls, int success) +{ + struct GNUNET_ATS_InformationRequestContext *irc = cls; + + irc->cm = NULL; +} + + +/** + * Obtain statistics and/or change preferences for the given peer. + * + * @param h core handle + * @param peer identifies the peer + * @param amount reserve N bytes for receiving, negative + * amounts can be used to undo a (recent) reservation; + * @param preference increase incoming traffic share preference by this amount; + * in the absence of "amount" reservations, we use this + * preference value to assign proportional bandwidth shares + * to all connected peers + * @param info function to call with the resulting configuration information + * @param info_cls closure for info + * @return NULL on error + */ +struct GNUNET_ATS_InformationRequestContext * +GNUNET_ATS_peer_change_preference (struct GNUNET_ATS_Handle *h, + const struct GNUNET_PeerIdentity *peer, + int32_t amount, uint64_t preference, + GNUNET_ATS_PeerConfigurationInfoCallback + info, void *info_cls) +{ + struct GNUNET_ATS_InformationRequestContext *irc; + struct PeerRecord *pr; + struct RequestInfoMessage *rim; + struct ControlMessage *cm; + + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey); + if (NULL == pr) + { + /* attempt to change preference on peer that is not connected */ + GNUNET_assert (0); + return NULL; + } + if (pr->pcic != NULL) + { + /* second change before first one is done */ + GNUNET_break (0); + return NULL; + } + irc = GNUNET_malloc (sizeof (struct GNUNET_ATS_InformationRequestContext)); + irc->h = h; + irc->pr = pr; + cm = GNUNET_malloc (sizeof (struct ControlMessage) + + sizeof (struct RequestInfoMessage)); + cm->cont = &change_preference_send_continuation; + cm->cont_cls = irc; + irc->cm = cm; + rim = (struct RequestInfoMessage *) &cm[1]; + rim->header.size = htons (sizeof (struct RequestInfoMessage)); + rim->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_INFO); + rim->rim_id = htonl (pr->rim_id = h->rim_id_gen++); + rim->reserved = htonl (0); + rim->reserve_inbound = htonl (amount); + rim->preference_change = GNUNET_htonll (preference); + rim->peer = *peer; +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queueing CHANGE PREFERENCE request for peer `%s' with RIM %u\n", + GNUNET_i2s (peer), (unsigned int) pr->rim_id); +#endif + GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, + h->control_pending_tail, cm); + pr->pcic = info; + pr->pcic_cls = info_cls; + pr->pcic_ptr = irc; /* for free'ing irc */ + if (NULL != h->client) + trigger_next_request (h, GNUNET_NO); + return irc; +} + + +/** + * Cancel request for getting information about a peer. + * Note that an eventual change in preference, trust or bandwidth + * assignment MAY have already been committed at the time, + * so cancelling a request is NOT sure to undo the original + * request. The original request may or may not still commit. + * The only thing cancellation ensures is that the callback + * from the original request will no longer be called. + * + * @param irc context returned by the original GNUNET_ATS_peer_get_info call + */ +void +GNUNET_ATS_peer_change_preference_cancel (struct + GNUNET_ATS_InformationRequestContext + *irc) +{ + struct GNUNET_ATS_Handle *h = irc->h; + struct PeerRecord *pr = irc->pr; + + GNUNET_assert (pr->pcic_ptr == irc); + if (irc->cm != NULL) + { + GNUNET_CONTAINER_DLL_remove (h->control_pending_head, + h->control_pending_tail, irc->cm); + GNUNET_free (irc->cm); + } + pr->pcic = NULL; + pr->pcic_cls = NULL; + pr->pcic_ptr = NULL; + GNUNET_free (irc); +} +#endif + +/* end of ats_api_peer_change_preference.c */ diff --git a/src/include/gnunet_ats_service.h b/src/include/gnunet_ats_service.h index 5e302da5c..eb785afdd 100644 --- a/src/include/gnunet_ats_service.h +++ b/src/include/gnunet_ats_service.h @@ -243,5 +243,77 @@ GNUNET_ATS_address_update (struct GNUNET_ATS_Handle *atc, uint32_t ats_count); + +/** + * Function called with perference change information about the given peer. + * + * @param cls closure + * @param peer identifies the peer + * @param amount set to the amount that was actually reserved or unreserved; + * either the full requested amount or zero (no partial reservations) + * @param res_delay if the reservation could not be satisfied (amount was 0), how + * long should the client wait until re-trying? + */ +typedef void (*GNUNET_ATS_PeerConfigurationInfoCallback) (void *cls, + const struct + GNUNET_PeerIdentity * + peer, + int32_t amount, + struct + GNUNET_TIME_Relative + res_delay); + + + +/** + * Context that can be used to cancel a peer information request. + */ +struct GNUNET_ATS_InformationRequestContext; + + +/** + * Obtain statistics and/or change preferences for the given peer. + * You can only have one such pending request per peer. + * + * @param h core handle + * @param peer identifies the peer + * @param amount reserve N bytes for receiving, negative + * amounts can be used to undo a (recent) reservation; + * @param preference increase incoming traffic share preference by this amount; + * in the absence of "amount" reservations, we use this + * preference value to assign proportional bandwidth shares + * to all connected peers + * @param info function to call with the resulting configuration information + * @param info_cls closure for info + * @return NULL on error + * @deprecated will be replaced soon + */ +struct GNUNET_ATS_InformationRequestContext * +GNUNET_ATS_peer_change_preference (struct GNUNET_ATS_Handle *h, + const struct GNUNET_PeerIdentity *peer, + int32_t amount, uint64_t preference, + GNUNET_ATS_PeerConfigurationInfoCallback + info, void *info_cls); + + +/** + * Cancel request for getting information about a peer. + * Note that an eventual change in preference, trust or bandwidth + * assignment MAY have already been committed at the time, + * so cancelling a request is NOT sure to undo the original + * request. The original request may or may not still commit. + * The only thing cancellation ensures is that the callback + * from the original request will no longer be called. + * + * @param irc context returned by the original GNUNET_ATS_peer_get_info call + * @deprecated will be replaced soon + */ +void +GNUNET_ATS_peer_change_preference_cancel (struct + GNUNET_ATS_InformationRequestContext + *irc); + + + #endif /* end of file gnunet-service-transport_ats.h */ -- 2.25.1