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
*/
#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.
};
-/**
- * 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.
*
{
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,
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,
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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 */
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 */