From: Christian Grothoff Date: Fri, 12 Aug 2011 10:54:28 +0000 (+0000) Subject: initial ATS service refactoring X-Git-Tag: initial-import-from-subversion-38251~17384 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=3d016df6e9f16a224637ae1f525acdcbbce9fbed;p=oweals%2Fgnunet.git initial ATS service refactoring --- diff --git a/configure.ac b/configure.ac index 3e309da16..d21297969 100644 --- a/configure.ac +++ b/configure.ac @@ -741,6 +741,7 @@ m4/Makefile po/Makefile.in src/Makefile src/arm/Makefile +src/ats/Makefile src/block/Makefile src/core/Makefile src/datacache/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index ac08a16a9..044983d60 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ SUBDIRS = \ datacache \ datastore \ template \ + ats \ nat \ fragmentation \ transport \ diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am new file mode 100644 index 000000000..39aa3f87b --- /dev/null +++ b/src/ats/Makefile.am @@ -0,0 +1,38 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +lib_LTLIBRARIES = libgnunetats.la + +libgnunetats_la_SOURCES = \ + ats_api.c + + +#bin_PROGRAMS = \ +# gnunet-service-ats + +#gnunet_service_ats_SOURCES = \ +# gnunet-service-ats.c +#gnunet_service_ats_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(GN_LIBINTL) + + +#check_PROGRAMS = \ +# test_ats_api + +#if ENABLE_TEST_RUN +#TESTS = $(check_PROGRAMS) +#endif + +#test_ats_api_SOURCES = \ +# test_ats_api.c +#test_ats_api_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la + diff --git a/src/ats/ats_api.c b/src/ats/ats_api.c new file mode 100644 index 000000000..8609ac5a5 --- /dev/null +++ b/src/ats/ats_api.c @@ -0,0 +1,793 @@ +/* + 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.c + * @brief automatic transport selection API + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_ats_service.h" + +// 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 +{ + + /** + * Public key of the peer. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + /** + * 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; + + /** + * Bandwidth assigned to this address right now, 0 for none. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth; + + /** + * Set to GNUNET_YES if this is the connected address of a connected peer. + */ + int connected; + +}; + + +/** + * Opaque handle to stop incremental validation address callbacks. + */ +struct GNUNET_ATS_SuggestionContext +{ + + /** + * Function to call with our final suggestion. + */ + GNUNET_ATS_AddressSuggestionCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * Global ATS handle. + */ + struct GNUNET_ATS_Handle *atc; + + /** + * Which peer are we monitoring? + */ + struct GNUNET_PeerIdentity target; + +}; + + +/** + * 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 bandwidth per configuration. + */ + unsigned long long total_bps; +}; + + +/** + * Count number of connected records. + * + * @param cls pointer to counter + * @param key identity of the peer associated with the records + * @param value a 'struct AllocationRecord' + * @return GNUNET_YES (continue iteration) + */ +static int +count_connections (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + unsigned int *ac = cls; + struct AllocationRecord *ar = value; + + if (GNUNET_YES == ar->connected) + (*ac)++; + return GNUNET_YES; +} + +struct SetBandwidthContext +{ + struct GNUNET_ATS_Handle *atc; + struct GNUNET_BANDWIDTH_Value32NBO bw; +}; + +/** + * Set bandwidth based on record. + * + * @param cls 'struct SetBandwidthContext' + * @param key identity of the peer associated with the records + * @param value a 'struct AllocationRecord' + * @return GNUNET_YES (continue iteration) + */ +static int +set_bw_connections (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct SetBandwidthContext *sbc = cls; + struct AllocationRecord *ar = value; + + if (GNUNET_YES == ar->connected) + { + ar->bandwidth = sbc->bw; + sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, + (const struct GNUNET_PeerIdentity*) key, + ar->plugin_name, + ar->session, + ar->plugin_addr, + ar->plugin_addr_len, + ar->bandwidth); + } + else if (ntohl(ar->bandwidth.value__) > 0) + { + ar->bandwidth = GNUNET_BANDWIDTH_value_init (0); + sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, + (const struct GNUNET_PeerIdentity*) key, + ar->plugin_name, + ar->session, + ar->plugin_addr, + ar->plugin_addr_len, + ar->bandwidth); + } + return GNUNET_YES; +} + + +/** + * Task run to update bandwidth assignments. + * + * @param cls the 'struct GNUNET_ATS_Handle' + * @param tc scheduler context + */ +static void +update_bandwidth_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_ATS_Handle *atc = cls; + unsigned int ac; + struct SetBandwidthContext bwc; + + atc->ba_task = GNUNET_SCHEDULER_NO_TASK; + /* FIXME: update calculations NICELY; what follows is a naive version */ + GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &count_connections, + &ac); + bwc.atc = atc; + bwc.bw = GNUNET_BANDWIDTH_value_init (atc->total_bps / ac); + GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &set_bw_connections, + &bwc); +} + + +/** + * Calculate an updated bandwidth assignment and notify. + * + * @param ats handle + * @param change which allocation record changed? + */ +static void +update_bandwidth_assignment (struct GNUNET_ATS_Handle *atc, + struct AllocationRecord *change) +{ + /* FIXME: based on the 'change', update the LP-problem... */ + if (atc->ba_task == GNUNET_SCHEDULER_NO_TASK) + atc->ba_task = GNUNET_SCHEDULER_add_now (&update_bandwidth_task, + atc); +} + + +/** + * Function called with feasbile addresses we might want to suggest. + * + * @param cls the 'struct GNUNET_ATS_SuggestionContext' + * @param key identity of the peer + * @param value a 'struct AllocationRecord' for the peer + * @return GNUNET_NO if we're done, GNUNET_YES if we did not suggest an address yet + */ +static int +suggest_address (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_ATS_SuggestionContest *asc = cls; + struct AllocationRecord *ar = value; + + // FIXME... + return GNUNET_YES; +} + + +/** + * We would like to establish a new connection with a peer. + * ATS should suggest a good address to begin with. + * + * @param atc handle + * @param peer identity of the new peer + * @param cb function to call with the address + * @param cb_cls closure for cb + */ +struct GNUNET_ATS_SuggestionContext * +GNUNET_ATS_suggest_address (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer, + GNUNET_ATS_AddressSuggestionCallback cb, + void *cb_cls) +{ + struct GNUNET_ATS_SuggestionContext *asc; + + asc = GNUNET_malloc (sizeof (struct GNUNET_ATS_SuggestionContext)); + asc->cb = cb; + asc->cb_cls = cb_cls; + asc->atc = atc; + asc->target = *peer; + GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, + &peer->hashPubKey, + &suggest_address, + asc); + if (NULL == asc->cb) + { + GNUNET_free (asc); + return NULL; + } + GNUNET_CONTAINER_multihashmap_put (atc->notify_map, + &peer->hashPubKey, + asc, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + return asc; +} + + +/** + * Cancel suggestion request. + * + * @param asc handle of the request to cancel + */ +void +GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SuggestionContext *asc) +{ + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (asc->atc->notify_map, + &asc->target.hashPubKey, + asc)); + GNUNET_free (asc); +} + + +/** + * Initialize the ATS subsystem. + * + * @param cfg configuration to use + * @param alloc_cb notification to call whenever the allocation changed + * @param alloc_cb_cls closure for 'alloc_cb' + * @return ats context + */ +struct GNUNET_ATS_Handle * +GNUNET_ATS_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb, + void *alloc_cb_cls) +{ + struct GNUNET_ATS_Handle *atc; + + atc = GNUNET_malloc (sizeof (struct GNUNET_ATS_Handle)); + atc->cfg = cfg; + atc->alloc_cb = alloc_cb; + atc->alloc_cb_cls = alloc_cb_cls; + atc->peers = GNUNET_CONTAINER_multihashmap_create (256); + GNUNET_CONFIGURATION_get_value_number (cfg, + "core", + "TOTAL_QUOTA_OUT", + &atc->total_bps); + return atc; +} + + +/** + * Free an allocation record. + * + * @param cls unused + * @param key identity of the peer associated with the record + * @param value the 'struct AllocationRecord' to free + * @return GNUNET_OK (continue to iterate) + */ +static int +destroy_allocation_record (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct AllocationRecord *ar = value; + + GNUNET_array_grow (ar->ats, ar->ats_count, 0); + GNUNET_free (ar->plugin_name); + GNUNET_free (ar); + return GNUNET_OK; +} + + +/** + * Shutdown the ATS subsystem. + * + * @param atc handle + */ +void +GNUNET_ATS_shutdown (struct GNUNET_ATS_Handle *atc) +{ + if (GNUNET_SCHEDULER_NO_TASK != atc->ba_task) + { + GNUNET_SCHEDULER_cancel (atc->ba_task); + atc->ba_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &destroy_allocation_record, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (atc->peers); + GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (atc->notify_map) == 0); + GNUNET_CONTAINER_multihashmap_destroy (atc->notify_map); + atc->notify_map = NULL; + GNUNET_free (atc); +} + + +/** + * Closure for 'update_session' + */ +struct UpdateSessionContext +{ + /** + * Ats handle. + */ + struct GNUNET_ATS_Handle *atc; + + /** + * Allocation record with new information. + */ + struct AllocationRecord *arnew; +}; + + +/** + * Update an allocation record, merging with the new information + * + * @param cls a new 'struct AllocationRecord' + * @param key identity of the peer associated with the records + * @param value the old 'struct AllocationRecord' + * @return GNUNET_YES if the records do not match, + * GNUNET_NO if the record do match and 'old' was updated + */ +static int +update_session (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct UpdateSessionContext *usc = cls; + struct AllocationRecord *arnew = usc->arnew; + struct AllocationRecord *arold = value; + int change; + + if (0 != strcmp (arnew->plugin_name, arold->plugin_name)) + return GNUNET_YES; + if ( (arnew->session == arold->session) || + ( (arold->session == NULL) && + (arold->plugin_addr_len == arnew->plugin_addr_len) && + (0 == memcmp (arold->plugin_addr, + arnew->plugin_addr, + arnew->plugin_addr_len)) ) ) + { + change = GNUNET_NO; + /* records match */ + if (arnew->session != arold->session) + { + arold->session = arnew->session; + change = GNUNET_YES; + } + if ( (arnew->connected == GNUNET_YES) && + (arold->connected == GNUNET_NO) ) + { + arold->connected = GNUNET_YES; + change = GNUNET_YES; + } + // FIXME: merge ats arrays of (arold, arnew); + + if (GNUNET_YES == change) + update_bandwidth_assignment (usc->atc, arold); + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Create an allocation record with the given properties. + * + * @param plugin_name name of the currently used transport plugin + * @param session session in use (if available) + * @param plugin_addr address in use (if available) + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the connection + * @param ats_count number of performance records in 'ats' + */ +static struct AllocationRecord * +create_allocation_record (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count) +{ + struct AllocationRecord *ar; + + ar = GNUNET_malloc (sizeof (struct AllocationRecord) + plugin_addr_len); + ar->public_key = *public_key; + ar->plugin_name = GNUNET_strdup (plugin_name); + ar->plugin_addr = &ar[1]; + memcpy (&ar[1], plugin_addr, plugin_addr_len); + ar->session = session; + ar->plugin_addr_len = plugin_addr_len; + GNUNET_array_grow (ar->ats, + ar->ats_count, + ats_count); + memcpy (ar->ats, + ats, + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)); + return ar; +} + + +/** + * Mark all matching allocation records as not connected. + * + * @param cls 'struct GTS_AtsHandle' + * @param key identity of the peer associated with the record + * @param value the 'struct AllocationRecord' to clear the 'connected' flag + * @return GNUNET_OK (continue to iterate) + */ +static int +disconnect_peer (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_ATS_Handle *atc = cls; + struct AllocationRecord *ar = value; + + if (GNUNET_YES == ar->connected) + { + ar->connected = GNUNET_NO; + update_bandwidth_assignment (atc, ar); + } + return GNUNET_OK; +} + + +/** + * We established a new connection with a peer (for example, because + * core asked for it or because the other peer connected to us). + * Calculate bandwidth assignments including the new peer. + * + * @param atc handle + * @param public_key public key of the peer + * @param peer identity of the new peer + * @param plugin_name name of the currently used transport plugin + * @param session session in use (if available) + * @param plugin_addr address in use (if available) + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the connection + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_peer_connect (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count) +{ + struct AllocationRecord *ar; + struct UpdateSessionContext usc; + + (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &disconnect_peer, + atc); + ar = create_allocation_record (public_key, + plugin_name, + session, + plugin_addr, + plugin_addr_len, + ats, + ats_count); + ar->connected = GNUNET_YES; + usc.atc = atc; + usc.arnew = ar; + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &update_session, + &usc)) + { + destroy_allocation_record (NULL, &peer->hashPubKey, ar); + return; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (atc->peers, + &peer->hashPubKey, + ar, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); +} + + +/** + * We disconnected from the given peer (for example, because ats, core + * or blacklist asked for it or because the other peer disconnected). + * Calculate bandwidth assignments without the peer. + * + * @param atc handle + * @param peer identity of the new peer + */ +void +GNUNET_ATS_peer_disconnect (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer) +{ + (void) GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, + &peer->hashPubKey, + &disconnect_peer, + atc); +} + + +/** + * Closure for 'destroy_allocation_record' + */ +struct SessionDestroyContext +{ + /** + * Ats handle. + */ + struct GNUNET_ATS_Handle *atc; + + /** + * Session being destroyed. + */ + const struct Session *session; +}; + + +/** + * Free an allocation record matching the given session. + * + * @param cls the 'struct SessionDestroyContext' + * @param key identity of the peer associated with the record + * @param value the 'struct AllocationRecord' to free + * @return GNUNET_OK (continue to iterate) + */ +static int +destroy_session (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct SessionDestroyContext *sdc = cls; + struct AllocationRecord *ar = value; + + if (ar->session != sdc->session) + return GNUNET_OK; + ar->session = NULL; + if (ar->plugin_addr != NULL) + return GNUNET_OK; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (sdc->atc->peers, + key, + ar)); + if (GNUNET_YES == ar->connected); + { + /* FIXME: is this supposed to be allowed? What to do then? */ + GNUNET_break (0); + } + destroy_allocation_record (NULL, key, ar); + return GNUNET_OK; +} + + +/** + * A session got destroyed, stop including it as a valid address. + * + * @param atc handle + * @param peer identity of the peer + * @param session session handle that is no longer valid + */ +void +GNUNET_ATS_session_destroyed (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer, + const struct Session *session) +{ + struct SessionDestroyContext sdc; + + sdc.atc = atc; + sdc.session = session; + (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &destroy_session, + &sdc); +} + + +/** + * Notify validation watcher that an entry is now valid + * + * @param cls 'struct ValidationEntry' that is now valid + * @param key peer identity (unused) + * @param value a 'GST_ValidationIteratorContext' to notify + * @return GNUNET_YES (continue to iterate) + */ +static int +notify_valid (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct AllocationRecord *ar = cls; + struct GNUNET_ATS_SuggestionContext *asc = value; + + asc->cb (asc->cb_cls, + &ar->public_key, + &asc->target, + ar->plugin_name, + ar->plugin_addr, + ar->plugin_addr_len, + ar->ats, ar->ats_count); + return GNUNET_OK; +} + + +/** + * We have updated performance statistics for a given address. Note + * that this function can be called for addresses that are currently + * in use as well as addresses that are valid but not actively in use. + * Furthermore, the peer may not even be connected to us right now (in + * which case the call may be ignored or the information may be stored + * for later use). Update bandwidth assignments. + * + * @param atc handle + * @param public_key public key of the peer + * @param peer identity of the peer + * @param plugin_name name of the transport plugin + * @param session session handle (if available) + * @param plugin_addr address (if available) + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the address + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_address_update (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count) +{ + struct AllocationRecord *ar; + struct UpdateSessionContext usc; + + ar = create_allocation_record (public_key, + plugin_name, + session, + plugin_addr, + plugin_addr_len, + ats, + ats_count); + usc.atc = atc; + usc.arnew = ar; + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_iterate (atc->peers, + &update_session, + &usc)) + { + destroy_allocation_record (NULL, &peer->hashPubKey, ar); + return; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (atc->peers, + &peer->hashPubKey, + ar, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + GNUNET_CONTAINER_multihashmap_get_multiple (atc->notify_map, + &peer->hashPubKey, + ¬ify_valid, + ar); +} + +/* end of file gnunet-service-transport_ats.c */ diff --git a/src/include/gnunet_ats_service.h b/src/include/gnunet_ats_service.h new file mode 100644 index 000000000..da54b24be --- /dev/null +++ b/src/include/gnunet_ats_service.h @@ -0,0 +1,230 @@ +/* + 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 include/gnunet_ats_service.h + * @brief automatic transport selection and outbound bandwidth determination + * @author Christian Grothoff + * @author Matthias Wachs + * + * TODO: + * - move GNUNET_TRANSPORT_ATS* in here and rename... + * - extend API to express communication preferences to ATS + * (to be called DIRECTLY from apps, not from transport/core!) + */ +#ifndef GNUNET_ATS_SERVICE_H +#define GNUNET_ATS_SERVICE_H + +#include "gnunet_constants.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" + + +/** + * Handle to the ATS subsystem. + */ +struct GNUNET_ATS_Handle; + + +/** + * Signature of a function called by ATS to notify the callee that the + * assigned bandwidth or address for a given peer was changed. If the + * callback is called with address/bandwidth assignments of zero, the + * ATS disconnect function will still be called once the disconnect + * actually happened. + * + * @param cls closure + * @param peer identity of the peer + * @param plugin_name name of the transport plugin, NULL to disconnect + * @param session session to use (if available) + * @param plugin_addr address to use (if available) + * @param plugin_addr_len number of bytes in addr + * @param bandwidth assigned outbound bandwidth for the connection + */ +typedef void (*GNUNET_TRANSPORT_ATS_AllocationNotification)(void *cls, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth); + + +/** + * Initialize the ATS subsystem. + * + * @param cfg configuration to use + * @param alloc_cb notification to call whenever the allocation changed + * @param alloc_cb_cls closure for 'alloc_cb' + * @return ats context + */ +struct GNUNET_ATS_Handle * +GNUNET_ATS_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb, + void *alloc_cb_cls); + + +/** + * Shutdown the ATS subsystem. + * + * @param atc handle + */ +void +GNUNET_ATS_shutdown (struct GNUNET_ATS_Handle *atc); + + +/** + * Signature of a function that takes an address suggestion + * + * @param cls closure + * @param public_key public key of the peer + * @param peer identity of the new peer + * @param plugin_name name of the plugin, NULL if we have no suggestion + * @param plugin_addr suggested address, NULL if we have no suggestion + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the address (as far as known) + * @param ats_count number of performance records in 'ats' + */ +typedef void (*GNUNET_ATS_AddressSuggestionCallback)(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count); + + +/** + * Handle to cancel suggestion request. + */ +struct GNUNET_ATS_SuggestionContext; + + +/** + * We would like to establish a new connection with a peer. + * ATS should suggest a good address to begin with. + * + * @param atc handle + * @param peer identity of the new peer + * @param cb function to call with the address + * @param cb_cls closure for cb + */ +struct GNUNET_ATS_SuggestionContext * +GNUNET_ATS_suggest_address (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer, + GNUNET_ATS_AddressSuggestionCallback cb, + void *cb_cls); + + +/** + * Cancel suggestion request. + * + * @param asc handle of the request to cancel + */ +void +GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SuggestionContext *asc); + + +/** + * We established a new connection with a peer (for example, because + * core asked for it or because the other peer connected to us). + * Calculate bandwidth assignments including the new peer. + * + * @param atc handle + * @param public_key public key of the peer + * @param peer identity of the new peer + * @param plugin_name name of the currently used transport plugin + * @param session session in use (if available) + * @param plugin_addr address in use (if available) + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the connection + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_peer_connect (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count); + + +/** + * We disconnected from the given peer (for example, because ats, core + * or blacklist asked for it or because the other peer disconnected). + * Calculate bandwidth assignments without the peer. + * + * @param atc handle + * @param peer identity of the peer + */ +void +GNUNET_ATS_peer_disconnect (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer); + + +/** + * A session got destroyed, stop including it as a valid address. + * + * @param atc handle + * @param peer identity of the peer + * @param session session handle that is no longer valid + */ +void +GNUNET_ATS_session_destroyed (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_PeerIdentity *peer, + const struct Session *session); + + +/** + * We have updated performance statistics for a given address. Note + * that this function can be called for addresses that are currently + * in use as well as addresses that are valid but not actively in use. + * Furthermore, the peer may not even be connected to us right now (in + * which case the call may be ignored or the information may be stored + * for later use). Update bandwidth assignments. + * + * @param atc handle + * @param public_key public key of the peer + * @param peer identity of the new peer + * @param plugin_name name of the transport plugin + * @param session session handle (if available) + * @param plugin_addr address (if available) + * @param plugin_addr_len number of bytes in plugin_addr + * @param ats performance data for the address + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_address_update (struct GNUNET_ATS_Handle *atc, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + struct Session *session, + const void *plugin_addr, + size_t plugin_addr_len, + const struct GNUNET_TRANSPORT_ATS_Information *ats, + uint32_t ats_count); + + +#endif +/* end of file gnunet-service-transport_ats.h */ diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index b9ab214e0..372ff115e 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -153,7 +153,6 @@ gnunet_service_transport_LDADD = \ gnunet_service_transport_new_SOURCES = \ gnunet-service-transport-new.c gnunet-service-transport.h \ - gnunet-service-transport_ats-new.h gnunet-service-transport_ats-new.c \ gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ @@ -161,6 +160,7 @@ gnunet_service_transport_new_SOURCES = \ gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ gnunet-service-transport_validation.h gnunet-service-transport_validation.c gnunet_service_transport_new_LDADD = \ + $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ diff --git a/src/transport/gnunet-service-transport-new.c b/src/transport/gnunet-service-transport-new.c index 968145b1e..cd1901a27 100644 --- a/src/transport/gnunet-service-transport-new.c +++ b/src/transport/gnunet-service-transport-new.c @@ -28,8 +28,8 @@ #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_peerinfo_service.h" +#include "gnunet_ats_service.h" #include "gnunet-service-transport.h" -#include "gnunet-service-transport_ats-new.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet-service-transport_clients.h" #include "gnunet-service-transport_hello.h" @@ -72,7 +72,7 @@ struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; /** * ATS handle. */ -struct GST_AtsHandle *GST_ats; +struct GNUNET_ATS_Handle *GST_ats; /** @@ -133,7 +133,7 @@ shutdown_task (void *cls, { GST_validation_stop (); GST_neighbours_stop (); - GST_ats_shutdown (GST_ats); GST_ats = NULL; + GNUNET_ATS_shutdown (GST_ats); GST_ats = NULL; GST_clients_stop (); GST_blacklist_stop (); GST_plugins_unload (); @@ -221,7 +221,7 @@ run (void *cls, NULL, // FIXME... NULL, // FIXME... NULL); // FIXME... - GST_ats = GST_ats_init (GST_cfg, + GST_ats = GNUNET_ATS_init (GST_cfg, NULL, // FIXME... NULL); // FIXME... GST_neighbours_start (NULL, // FIXME... diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h index 69cb20e7b..17fcaa0ae 100644 --- a/src/transport/gnunet-service-transport.h +++ b/src/transport/gnunet-service-transport.h @@ -63,7 +63,7 @@ extern struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; /** * ATS handle. */ -extern struct GST_AtsHandle *GST_ats; +extern struct GNUNET_ATS_Handle *GST_ats; #endif diff --git a/src/transport/gnunet-service-transport_ats-new.c b/src/transport/gnunet-service-transport_ats-new.c deleted file mode 100644 index 3a8bc7497..000000000 --- a/src/transport/gnunet-service-transport_ats-new.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - 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 transport/gnunet-service-transport_ats-new.c - * @brief automatic transport selection API - * @author Christian Grothoff - * @author Matthias Wachs - */ -#include "platform.h" -#include "gnunet-service-transport_ats-new.h" - - -/** - * Allocation record for a peer's address. - */ -struct AllocationRecord -{ - - /** - * Public key of the peer. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - - /** - * 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; - - /** - * Bandwidth assigned to this address right now, 0 for none. - */ - struct GNUNET_BANDWIDTH_Value32NBO bandwidth; - - /** - * Set to GNUNET_YES if this is the connected address of a connected peer. - */ - int connected; - -}; - - -/** - * Opaque handle to stop incremental validation address callbacks. - */ -struct GST_AtsSuggestionContext -{ - - /** - * Function to call with our final suggestion. - */ - GST_AtsAddressSuggestionCallback cb; - - /** - * Closure for 'cb'. - */ - void *cb_cls; - - /** - * Global ATS handle. - */ - struct GST_AtsHandle *atc; - - /** - * Which peer are we monitoring? - */ - struct GNUNET_PeerIdentity target; - -}; - - -/** - * Handle to the ATS subsystem. - */ -struct GST_AtsHandle -{ - /** - * 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 GST_AtsSuggestionContext's. - */ - struct GNUNET_CONTAINER_MultiHashMap *notify_map; - - - /** - * Task scheduled to update our bandwidth assignment. - */ - GNUNET_SCHEDULER_TaskIdentifier ba_task; - - /** - * Total bandwidth per configuration. - */ - unsigned long long total_bps; -}; - - -/** - * Count number of connected records. - * - * @param cls pointer to counter - * @param key identity of the peer associated with the records - * @param value a 'struct AllocationRecord' - * @return GNUNET_YES (continue iteration) - */ -static int -count_connections (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - unsigned int *ac = cls; - struct AllocationRecord *ar = value; - - if (GNUNET_YES == ar->connected) - (*ac)++; - return GNUNET_YES; -} - -struct SetBandwidthContext -{ - struct GST_AtsHandle *atc; - struct GNUNET_BANDWIDTH_Value32NBO bw; -}; - -/** - * Set bandwidth based on record. - * - * @param cls 'struct SetBandwidthContext' - * @param key identity of the peer associated with the records - * @param value a 'struct AllocationRecord' - * @return GNUNET_YES (continue iteration) - */ -static int -set_bw_connections (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct SetBandwidthContext *sbc = cls; - struct AllocationRecord *ar = value; - - if (GNUNET_YES == ar->connected) - { - ar->bandwidth = sbc->bw; - sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, - (const struct GNUNET_PeerIdentity*) key, - ar->plugin_name, - ar->session, - ar->plugin_addr, - ar->plugin_addr_len, - ar->bandwidth); - } - else if (ntohl(ar->bandwidth.value__) > 0) - { - ar->bandwidth = GNUNET_BANDWIDTH_value_init (0); - sbc->atc->alloc_cb (sbc->atc->alloc_cb_cls, - (const struct GNUNET_PeerIdentity*) key, - ar->plugin_name, - ar->session, - ar->plugin_addr, - ar->plugin_addr_len, - ar->bandwidth); - } - return GNUNET_YES; -} - - -/** - * Task run to update bandwidth assignments. - * - * @param cls the 'struct GST_AtsHandle' - * @param tc scheduler context - */ -static void -update_bandwidth_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GST_AtsHandle *atc = cls; - unsigned int ac; - struct SetBandwidthContext bwc; - - atc->ba_task = GNUNET_SCHEDULER_NO_TASK; - /* FIXME: update calculations NICELY; what follows is a naive version */ - GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &count_connections, - &ac); - bwc.atc = atc; - bwc.bw = GNUNET_BANDWIDTH_value_init (atc->total_bps / ac); - GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &set_bw_connections, - &bwc); -} - - -/** - * Calculate an updated bandwidth assignment and notify. - * - * @param ats handle - * @param change which allocation record changed? - */ -static void -update_bandwidth_assignment (struct GST_AtsHandle *atc, - struct AllocationRecord *change) -{ - /* FIXME: based on the 'change', update the LP-problem... */ - if (atc->ba_task == GNUNET_SCHEDULER_NO_TASK) - atc->ba_task = GNUNET_SCHEDULER_add_now (&update_bandwidth_task, - atc); -} - - -/** - * Function called with feasbile addresses we might want to suggest. - * - * @param cls the 'struct GST_AtsSuggestionContext' - * @param key identity of the peer - * @param value a 'struct AllocationRecord' for the peer - * @return GNUNET_NO if we're done, GNUNET_YES if we did not suggest an address yet - */ -static int -suggest_address (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct GST_AtsSuggestionContest *asc = cls; - struct AllocationRecord *ar = value; - - // FIXME... - return GNUNET_YES; -} - - -/** - * We would like to establish a new connection with a peer. - * ATS should suggest a good address to begin with. - * - * @param atc handle - * @param peer identity of the new peer - * @param cb function to call with the address - * @param cb_cls closure for cb - */ -struct GST_AtsSuggestionContext * -GST_ats_suggest_address (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer, - GST_AtsAddressSuggestionCallback cb, - void *cb_cls) -{ - struct GST_AtsSuggestionContext *asc; - - asc = GNUNET_malloc (sizeof (struct GST_AtsSuggestionContext)); - asc->cb = cb; - asc->cb_cls = cb_cls; - asc->atc = atc; - asc->target = *peer; - GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, - &peer->hashPubKey, - &suggest_address, - asc); - if (NULL == asc->cb) - { - GNUNET_free (asc); - return NULL; - } - GNUNET_CONTAINER_multihashmap_put (atc->notify_map, - &peer->hashPubKey, - asc, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - return asc; -} - - -/** - * Cancel suggestion request. - * - * @param asc handle of the request to cancel - */ -void -GST_ats_suggest_address_cancel (struct GST_AtsSuggestionContext *asc) -{ - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (asc->atc->notify_map, - &asc->target.hashPubKey, - asc)); - GNUNET_free (asc); -} - - -/** - * Initialize the ATS subsystem. - * - * @param cfg configuration to use - * @param alloc_cb notification to call whenever the allocation changed - * @param alloc_cb_cls closure for 'alloc_cb' - * @return ats context - */ -struct GST_AtsHandle * -GST_ats_init (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb, - void *alloc_cb_cls) -{ - struct GST_AtsHandle *atc; - - atc = GNUNET_malloc (sizeof (struct GST_AtsHandle)); - atc->cfg = cfg; - atc->alloc_cb = alloc_cb; - atc->alloc_cb_cls = alloc_cb_cls; - atc->peers = GNUNET_CONTAINER_multihashmap_create (256); - GNUNET_CONFIGURATION_get_value_number (cfg, - "core", - "TOTAL_QUOTA_OUT", - &atc->total_bps); - return atc; -} - - -/** - * Free an allocation record. - * - * @param cls unused - * @param key identity of the peer associated with the record - * @param value the 'struct AllocationRecord' to free - * @return GNUNET_OK (continue to iterate) - */ -static int -destroy_allocation_record (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct AllocationRecord *ar = value; - - GNUNET_array_grow (ar->ats, ar->ats_count, 0); - GNUNET_free (ar->plugin_name); - GNUNET_free (ar); - return GNUNET_OK; -} - - -/** - * Shutdown the ATS subsystem. - * - * @param atc handle - */ -void -GST_ats_shutdown (struct GST_AtsHandle *atc) -{ - if (GNUNET_SCHEDULER_NO_TASK != atc->ba_task) - { - GNUNET_SCHEDULER_cancel (atc->ba_task); - atc->ba_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &destroy_allocation_record, - NULL); - GNUNET_CONTAINER_multihashmap_destroy (atc->peers); - GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (atc->notify_map) == 0); - GNUNET_CONTAINER_multihashmap_destroy (atc->notify_map); - atc->notify_map = NULL; - GNUNET_free (atc); -} - - -/** - * Closure for 'update_session' - */ -struct UpdateSessionContext -{ - /** - * Ats handle. - */ - struct GST_AtsHandle *atc; - - /** - * Allocation record with new information. - */ - struct AllocationRecord *arnew; -}; - - -/** - * Update an allocation record, merging with the new information - * - * @param cls a new 'struct AllocationRecord' - * @param key identity of the peer associated with the records - * @param value the old 'struct AllocationRecord' - * @return GNUNET_YES if the records do not match, - * GNUNET_NO if the record do match and 'old' was updated - */ -static int -update_session (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct UpdateSessionContext *usc = cls; - struct AllocationRecord *arnew = usc->arnew; - struct AllocationRecord *arold = value; - int change; - - if (0 != strcmp (arnew->plugin_name, arold->plugin_name)) - return GNUNET_YES; - if ( (arnew->session == arold->session) || - ( (arold->session == NULL) && - (arold->plugin_addr_len == arnew->plugin_addr_len) && - (0 == memcmp (arold->plugin_addr, - arnew->plugin_addr, - arnew->plugin_addr_len)) ) ) - { - change = GNUNET_NO; - /* records match */ - if (arnew->session != arold->session) - { - arold->session = arnew->session; - change = GNUNET_YES; - } - if ( (arnew->connected == GNUNET_YES) && - (arold->connected == GNUNET_NO) ) - { - arold->connected = GNUNET_YES; - change = GNUNET_YES; - } - // FIXME: merge ats arrays of (arold, arnew); - - if (GNUNET_YES == change) - update_bandwidth_assignment (usc->atc, arold); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Create an allocation record with the given properties. - * - * @param plugin_name name of the currently used transport plugin - * @param session session in use (if available) - * @param plugin_addr address in use (if available) - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the connection - * @param ats_count number of performance records in 'ats' - */ -static struct AllocationRecord * -create_allocation_record (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) -{ - struct AllocationRecord *ar; - - ar = GNUNET_malloc (sizeof (struct AllocationRecord) + plugin_addr_len); - ar->public_key = *public_key; - ar->plugin_name = GNUNET_strdup (plugin_name); - ar->plugin_addr = &ar[1]; - memcpy (&ar[1], plugin_addr, plugin_addr_len); - ar->session = session; - ar->plugin_addr_len = plugin_addr_len; - GNUNET_array_grow (ar->ats, - ar->ats_count, - ats_count); - memcpy (ar->ats, - ats, - ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)); - return ar; -} - - -/** - * Mark all matching allocation records as not connected. - * - * @param cls 'struct GTS_AtsHandle' - * @param key identity of the peer associated with the record - * @param value the 'struct AllocationRecord' to clear the 'connected' flag - * @return GNUNET_OK (continue to iterate) - */ -static int -disconnect_peer (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct GST_AtsHandle *atc = cls; - struct AllocationRecord *ar = value; - - if (GNUNET_YES == ar->connected) - { - ar->connected = GNUNET_NO; - update_bandwidth_assignment (atc, ar); - } - return GNUNET_OK; -} - - -/** - * We established a new connection with a peer (for example, because - * core asked for it or because the other peer connected to us). - * Calculate bandwidth assignments including the new peer. - * - * @param atc handle - * @param public_key public key of the peer - * @param peer identity of the new peer - * @param plugin_name name of the currently used transport plugin - * @param session session in use (if available) - * @param plugin_addr address in use (if available) - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the connection - * @param ats_count number of performance records in 'ats' - */ -void -GST_ats_peer_connect (struct GST_AtsHandle *atc, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) -{ - struct AllocationRecord *ar; - struct UpdateSessionContext usc; - - (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &disconnect_peer, - atc); - ar = create_allocation_record (public_key, - plugin_name, - session, - plugin_addr, - plugin_addr_len, - ats, - ats_count); - ar->connected = GNUNET_YES; - usc.atc = atc; - usc.arnew = ar; - if (GNUNET_SYSERR == - GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &update_session, - &usc)) - { - destroy_allocation_record (NULL, &peer->hashPubKey, ar); - return; - } - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (atc->peers, - &peer->hashPubKey, - ar, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); -} - - -/** - * We disconnected from the given peer (for example, because ats, core - * or blacklist asked for it or because the other peer disconnected). - * Calculate bandwidth assignments without the peer. - * - * @param atc handle - * @param peer identity of the new peer - */ -void -GST_ats_peer_disconnect (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer) -{ - (void) GNUNET_CONTAINER_multihashmap_get_multiple (atc->peers, - &peer->hashPubKey, - &disconnect_peer, - atc); -} - - -/** - * Closure for 'destroy_allocation_record' - */ -struct SessionDestroyContext -{ - /** - * Ats handle. - */ - struct GST_AtsHandle *atc; - - /** - * Session being destroyed. - */ - const struct Session *session; -}; - - -/** - * Free an allocation record matching the given session. - * - * @param cls the 'struct SessionDestroyContext' - * @param key identity of the peer associated with the record - * @param value the 'struct AllocationRecord' to free - * @return GNUNET_OK (continue to iterate) - */ -static int -destroy_session (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct SessionDestroyContext *sdc = cls; - struct AllocationRecord *ar = value; - - if (ar->session != sdc->session) - return GNUNET_OK; - ar->session = NULL; - if (ar->plugin_addr != NULL) - return GNUNET_OK; - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (sdc->atc->peers, - key, - ar)); - if (GNUNET_YES == ar->connected); - { - /* FIXME: is this supposed to be allowed? What to do then? */ - GNUNET_break (0); - } - destroy_allocation_record (NULL, key, ar); - return GNUNET_OK; -} - - -/** - * A session got destroyed, stop including it as a valid address. - * - * @param atc handle - * @param peer identity of the peer - * @param session session handle that is no longer valid - */ -void -GST_ats_session_destroyed (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer, - const struct Session *session) -{ - struct SessionDestroyContext sdc; - - sdc.atc = atc; - sdc.session = session; - (void) GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &destroy_session, - &sdc); -} - - -/** - * Notify validation watcher that an entry is now valid - * - * @param cls 'struct ValidationEntry' that is now valid - * @param key peer identity (unused) - * @param value a 'GST_ValidationIteratorContext' to notify - * @return GNUNET_YES (continue to iterate) - */ -static int -notify_valid (void *cls, - const GNUNET_HashCode *key, - void *value) -{ - struct AllocationRecord *ar = cls; - struct GST_AtsSuggestionContext *asc = value; - - asc->cb (asc->cb_cls, - &ar->public_key, - &asc->target, - ar->plugin_name, - ar->plugin_addr, - ar->plugin_addr_len, - ar->ats, ar->ats_count); - return GNUNET_OK; -} - - -/** - * We have updated performance statistics for a given address. Note - * that this function can be called for addresses that are currently - * in use as well as addresses that are valid but not actively in use. - * Furthermore, the peer may not even be connected to us right now (in - * which case the call may be ignored or the information may be stored - * for later use). Update bandwidth assignments. - * - * @param atc handle - * @param public_key public key of the peer - * @param peer identity of the peer - * @param plugin_name name of the transport plugin - * @param session session handle (if available) - * @param plugin_addr address (if available) - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the address - * @param ats_count number of performance records in 'ats' - */ -void -GST_ats_address_update (struct GST_AtsHandle *atc, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) -{ - struct AllocationRecord *ar; - struct UpdateSessionContext usc; - - ar = create_allocation_record (public_key, - plugin_name, - session, - plugin_addr, - plugin_addr_len, - ats, - ats_count); - usc.atc = atc; - usc.arnew = ar; - if (GNUNET_SYSERR == - GNUNET_CONTAINER_multihashmap_iterate (atc->peers, - &update_session, - &usc)) - { - destroy_allocation_record (NULL, &peer->hashPubKey, ar); - return; - } - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (atc->peers, - &peer->hashPubKey, - ar, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); - GNUNET_CONTAINER_multihashmap_get_multiple (atc->notify_map, - &peer->hashPubKey, - ¬ify_valid, - ar); -} - -/* end of file gnunet-service-transport_ats.c */ diff --git a/src/transport/gnunet-service-transport_ats-new.h b/src/transport/gnunet-service-transport_ats-new.h deleted file mode 100644 index ed72dd171..000000000 --- a/src/transport/gnunet-service-transport_ats-new.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - 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 transport/gnunet-service-transport_ats-new.h - * @brief automatic transport selection and outbound bandwidth determination - * @author Christian Grothoff - * @author Matthias Wachs - * - * TODO: - * - turn into service - * - extend API to express communication preferences to ATS - * (to be called DIRECTLY from apps, not from transport/core!) - */ -#ifndef GNUNET_SERVICE_TRANSPORT_ATS_H -#define GNUNET_SERVICE_TRANSPORT_ATS_H - -#include "gnunet_constants.h" -#include "gnunet_util_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_transport_plugin.h" - - -/** - * Handle to the ATS subsystem. - */ -struct GST_AtsHandle; - - -/** - * Signature of a function called by ATS to notify the callee that the - * assigned bandwidth or address for a given peer was changed. If the - * callback is called with address/bandwidth assignments of zero, the - * ATS disconnect function will still be called once the disconnect - * actually happened. - * - * @param cls closure - * @param peer identity of the peer - * @param plugin_name name of the transport plugin, NULL to disconnect - * @param session session to use (if available) - * @param plugin_addr address to use (if available) - * @param plugin_addr_len number of bytes in addr - * @param bandwidth assigned outbound bandwidth for the connection - */ -typedef void (*GNUNET_TRANSPORT_ATS_AllocationNotification)(void *cls, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - struct GNUNET_BANDWIDTH_Value32NBO bandwidth); - - -/** - * Initialize the ATS subsystem. - * - * @param cfg configuration to use - * @param alloc_cb notification to call whenever the allocation changed - * @param alloc_cb_cls closure for 'alloc_cb' - * @return ats context - */ -struct GST_AtsHandle * -GST_ats_init (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TRANSPORT_ATS_AllocationNotification alloc_cb, - void *alloc_cb_cls); - - -/** - * Shutdown the ATS subsystem. - * - * @param atc handle - */ -void -GST_ats_shutdown (struct GST_AtsHandle *atc); - - -/** - * Signature of a function that takes an address suggestion - * - * @param cls closure - * @param public_key public key of the peer - * @param peer identity of the new peer - * @param plugin_name name of the plugin, NULL if we have no suggestion - * @param plugin_addr suggested address, NULL if we have no suggestion - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the address (as far as known) - * @param ats_count number of performance records in 'ats' - */ -typedef void (*GST_AtsAddressSuggestionCallback)(void *cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); - - -/** - * Handle to cancel suggestion request. - */ -struct GST_AtsSuggestionContext; - - -/** - * We would like to establish a new connection with a peer. - * ATS should suggest a good address to begin with. - * - * @param atc handle - * @param peer identity of the new peer - * @param cb function to call with the address - * @param cb_cls closure for cb - */ -struct GST_AtsSuggestionContext * -GST_ats_suggest_address (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer, - GST_AtsAddressSuggestionCallback cb, - void *cb_cls); - - -/** - * Cancel suggestion request. - * - * @param asc handle of the request to cancel - */ -void -GST_ats_suggest_address_cancel (struct GST_AtsSuggestionContext *asc); - - -/** - * We established a new connection with a peer (for example, because - * core asked for it or because the other peer connected to us). - * Calculate bandwidth assignments including the new peer. - * - * @param atc handle - * @param public_key public key of the peer - * @param peer identity of the new peer - * @param plugin_name name of the currently used transport plugin - * @param session session in use (if available) - * @param plugin_addr address in use (if available) - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the connection - * @param ats_count number of performance records in 'ats' - */ -void -GST_ats_peer_connect (struct GST_AtsHandle *atc, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); - - -/** - * We disconnected from the given peer (for example, because ats, core - * or blacklist asked for it or because the other peer disconnected). - * Calculate bandwidth assignments without the peer. - * - * @param atc handle - * @param peer identity of the peer - */ -void -GST_ats_peer_disconnect (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer); - - -/** - * A session got destroyed, stop including it as a valid address. - * - * @param atc handle - * @param peer identity of the peer - * @param session session handle that is no longer valid - */ -void -GST_ats_session_destroyed (struct GST_AtsHandle *atc, - const struct GNUNET_PeerIdentity *peer, - const struct Session *session); - - -/** - * We have updated performance statistics for a given address. Note - * that this function can be called for addresses that are currently - * in use as well as addresses that are valid but not actively in use. - * Furthermore, the peer may not even be connected to us right now (in - * which case the call may be ignored or the information may be stored - * for later use). Update bandwidth assignments. - * - * @param atc handle - * @param public_key public key of the peer - * @param peer identity of the new peer - * @param plugin_name name of the transport plugin - * @param session session handle (if available) - * @param plugin_addr address (if available) - * @param plugin_addr_len number of bytes in plugin_addr - * @param ats performance data for the address - * @param ats_count number of performance records in 'ats' - */ -void -GST_ats_address_update (struct GST_AtsHandle *atc, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_PeerIdentity *peer, - const char *plugin_name, - struct Session *session, - const void *plugin_addr, - size_t plugin_addr_len, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); - - -#endif -/* end of file gnunet-service-transport_ats.h */ diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index cff2bb595..2d23ebfa1 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -24,7 +24,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet-service-transport_ats-new.h" +#include "gnunet_ats_service.h" #include "gnunet-service-transport_neighbours.h" #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport.h" @@ -129,7 +129,7 @@ struct NeighbourMapEntry * Context for address suggestion. * NULL after we are connected. */ - struct GST_AtsSuggestionContext *asc; + struct GNUNET_ATS_SuggestionContext *asc; /** * Performance data for the peer. @@ -341,7 +341,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n) } if (NULL != n->asc) { - GST_ats_suggest_address_cancel (n->asc); + GNUNET_ATS_suggest_address_cancel (n->asc); n->asc = NULL; } GNUNET_array_grow (n->ats, @@ -486,10 +486,10 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) } if (n->asc != NULL) return; /* already trying */ - n->asc = GST_ats_suggest_address (GST_ats, - target, - &try_connect_using_address, - n); + n->asc = GNUNET_ATS_suggest_address (GST_ats, + target, + &try_connect_using_address, + n); } diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index 1a619a901..2b03e3805 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c @@ -27,9 +27,9 @@ #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_hello.h" -#include "gnunet-service-transport_ats-new.h" #include "gnunet-service-transport.h" #include "gnunet_hello_lib.h" +#include "gnunet_ats_service.h" #include "gnunet_peerinfo_service.h" #include "gnunet_signatures.h" @@ -418,7 +418,7 @@ add_valid_address (void *cls, ve = find_validation_entry (&public_key, &pid, tname, addr, addrlen); ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); - GST_ats_address_update (GST_ats, + GNUNET_ATS_address_update (GST_ats, &public_key, &pid, tname, @@ -1037,7 +1037,7 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, /* validity achieved, remember it! */ ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); - GST_ats_address_update (GST_ats, + GNUNET_ATS_address_update (GST_ats, &ve->public_key, &ve->pid, ve->transport_name,