X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fats%2Fats_api_scheduling.c;h=783b9f59617c8fcaa6c55f1ba5a55e176ad07844;hb=7a5a724a6f96baf80d2226326124aa01c58ad3fe;hp=8d2cdc84e11a1499010c4d82633d87835d89c4c5;hpb=896e28ee7d8aee5fb15c905eef18a6f73e844d7f;p=oweals%2Fgnunet.git diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c index 8d2cdc84e..783b9f596 100644 --- a/src/ats/ats_api_scheduling.c +++ b/src/ats/ats_api_scheduling.c @@ -1,21 +1,19 @@ /* This file is part of GNUnet. - (C) 2010-2015 Christian Grothoff (and other contributing authors) + Copyright (C) 2010-2015 GNUnet e.V. - 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 free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - 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. + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ /** * @file ats/ats_api_scheduling.c @@ -40,6 +38,7 @@ */ #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) +#define LOG(kind,...) GNUNET_log_from(kind, "ats-scheduling-api", __VA_ARGS__) /** * Session ID we use if there is no session / slot. @@ -69,21 +68,16 @@ struct GNUNET_ATS_AddressRecord * Session handle. NULL if we have an address but no * active session for this address. */ - struct Session *session; - - /** - * Array with performance data about the address. - */ - struct GNUNET_ATS_Information *ats; + struct GNUNET_ATS_Session *session; /** - * Number of entries in @e ats. + * Performance data about the address. */ - uint32_t ats_count; + struct GNUNET_ATS_PropertiesNBO properties; /** * Which slot (index) in the session array does - * this record correspond to? FIXME: + * this record correspond to? * FIXME: a linear search on this is really crappy! * Maybe switch to a 64-bit global counter and be * done with it? Or does that then cause too much @@ -91,13 +85,6 @@ struct GNUNET_ATS_AddressRecord */ uint32_t slot; - /** - * Is this address currently in use? In use means - * that the transport service will use this address - * for sending. - */ - int in_use; - /** * We're about to destroy this address record, just ATS does * not know this yet. Once ATS confirms its destruction, @@ -107,56 +94,6 @@ struct GNUNET_ATS_AddressRecord }; -/** - * We keep a list of our local networks so we can answer - * LAN vs. WAN questions. Note: WLAN is not detected yet. - * (maybe we can do that heuristically based on interface - * name in the future?). - * - * FIXME: should this be part of the ATS scheduling API? - * Seems to be more generic and independent of ATS. - */ -struct ATS_Network -{ - /** - * Kept in a DLL. - */ - struct ATS_Network *next; - - /** - * Kept in a DLL. - */ - struct ATS_Network *prev; - - /** - * Network address. - */ - struct sockaddr *network; - - /** - * Netmask to determine what is in the LAN. - */ - struct sockaddr *netmask; - - /** - * How long are @e network and @e netmask? - */ - socklen_t length; -}; - - -/** - * Handle for ATS address suggestion requests. - */ -struct GNUNET_ATS_SuggestHandle -{ - /** - * ID of the peer for which address suggestion was requested. - */ - struct GNUNET_PeerIdentity id; -}; - - /** * Handle to the ATS subsystem for bandwidth/transport scheduling information. */ @@ -178,33 +115,11 @@ struct GNUNET_ATS_SchedulingHandle */ void *suggest_cb_cls; - /** - * Map with the identities of all the peers for which we would - * like to have address suggestions. The key is the PID, the - * value is currently the `struct GNUNET_ATS_SuggestHandle` - */ - struct GNUNET_CONTAINER_MultiPeerMap *sug_requests; - - /** - * Connection to ATS service. - */ - struct GNUNET_CLIENT_Connection *client; - /** * Message queue for sending requests to the ATS service. */ struct GNUNET_MQ_Handle *mq; - /** - * Head of LAN networks list. - */ - struct ATS_Network *net_head; - - /** - * Tail of LAN networks list. - */ - struct ATS_Network *net_tail; - /** * Array of session objects (we need to translate them to numbers and back * for the protocol; the offset in the array is the session number on the @@ -219,9 +134,9 @@ struct GNUNET_ATS_SchedulingHandle struct GNUNET_SCHEDULER_Task *task; /** - * Task for periodically refreshing our LAN network list. + * Reconnect backoff delay. */ - struct GNUNET_SCHEDULER_Task *interface_task; + struct GNUNET_TIME_Relative backoff; /** * Size of the @e session_array. @@ -244,11 +159,9 @@ reconnect (struct GNUNET_ATS_SchedulingHandle *sh); * Re-establish the connection to the ATS service. * * @param cls handle to use to re-connect. - * @param tc scheduler context */ static void -reconnect_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +reconnect_task (void *cls) { struct GNUNET_ATS_SchedulingHandle *sh = cls; @@ -270,12 +183,12 @@ force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh) GNUNET_MQ_destroy (sh->mq); sh->mq = NULL; } - if (NULL != sh->client) - { - GNUNET_CLIENT_disconnect (sh->client); - sh->client = NULL; - } - sh->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + sh->suggest_cb (sh->suggest_cb_cls, + NULL, NULL, NULL, + GNUNET_BANDWIDTH_ZERO, + GNUNET_BANDWIDTH_ZERO); + sh->backoff = GNUNET_TIME_STD_BACKOFF (sh->backoff); + sh->task = GNUNET_SCHEDULER_add_delayed (sh->backoff, &reconnect_task, sh); } @@ -320,7 +233,6 @@ find_session (struct GNUNET_ATS_SchedulingHandle *sh, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); - force_reconnect (sh); return NULL; } return ar; @@ -339,6 +251,7 @@ find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh) static uint32_t off; uint32_t i; + GNUNET_assert (0 != sh->session_array_size); i = 0; while ( ( (NOT_FOUND == off) || (NULL != sh->session_array[off % sh->session_array_size]) ) && @@ -368,7 +281,7 @@ find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh) */ static uint32_t find_session_id (struct GNUNET_ATS_SchedulingHandle *sh, - struct Session *session, + struct GNUNET_ATS_Session *session, const struct GNUNET_HELLO_Address *address) { uint32_t i; @@ -380,8 +293,12 @@ find_session_id (struct GNUNET_ATS_SchedulingHandle *sh, } for (i = 1; i < sh->session_array_size; i++) if ( (NULL != sh->session_array[i]) && + (GNUNET_NO == sh->session_array[i]->in_destroy) && ( (session == sh->session_array[i]->session) || (NULL == sh->session_array[i]->session) ) && + (0 == memcmp (&address->peer, + &sh->session_array[i]->address->peer, + sizeof (struct GNUNET_PeerIdentity))) && (0 == GNUNET_HELLO_address_cmp (address, sh->session_array[i]->address)) ) return i; @@ -429,16 +346,14 @@ release_session (struct GNUNET_ATS_SchedulingHandle *sh, * message from the service. * * @param cls the `struct GNUNET_ATS_SchedulingHandle` - * @param msg message received, NULL on timeout or fatal error + * @param srm message received */ static void -process_ats_session_release_message (void *cls, - const struct GNUNET_MessageHeader *msg) +handle_ats_session_release (void *cls, + const struct GNUNET_ATS_SessionReleaseMessage *srm) { struct GNUNET_ATS_SchedulingHandle *sh = cls; - const struct SessionReleaseMessage *srm; - srm = (const struct SessionReleaseMessage *) msg; /* Note: peer field in srm not necessary right now, but might be good to have in the future */ release_session (sh, @@ -451,18 +366,16 @@ process_ats_session_release_message (void *cls, * message from the service. * * @param cls the `struct GNUNET_ATS_SchedulingHandle` - * @param msg message received, NULL on timeout or fatal error + * @param m message received */ static void -process_ats_address_suggestion_message (void *cls, - const struct GNUNET_MessageHeader *msg) +handle_ats_address_suggestion (void *cls, + const struct AddressSuggestionMessage *m) { struct GNUNET_ATS_SchedulingHandle *sh = cls; - const struct AddressSuggestionMessage *m; struct GNUNET_ATS_AddressRecord *ar; uint32_t session_id; - m = (const struct AddressSuggestionMessage *) msg; session_id = ntohl (m->session_id); if (0 == session_id) { @@ -470,7 +383,9 @@ process_ats_address_suggestion_message (void *cls, force_reconnect (sh); return; } - ar = find_session (sh, session_id, &m->peer); + ar = find_session (sh, + session_id, + &m->peer); if (NULL == ar) { GNUNET_break (0); @@ -481,16 +396,38 @@ process_ats_address_suggestion_message (void *cls, return; if (GNUNET_YES == ar->in_destroy) { - /* ignore suggestion, as this address is dying */ + /* ignore suggestion, as this address is dying, unless BW is 0, + in that case signal 'disconnect' via BW 0 */ + if ( (0 == ntohl (m->bandwidth_out.value__)) && + (0 == ntohl (m->bandwidth_in.value__)) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ATS suggests disconnect from peer `%s' with BW %u/%u\n", + GNUNET_i2s (&ar->address->peer), + (unsigned int) ntohl (m->bandwidth_out.value__), + (unsigned int) ntohl (m->bandwidth_in.value__)); + sh->suggest_cb (sh->suggest_cb_cls, + &m->peer, + NULL, + NULL, + m->bandwidth_out, + m->bandwidth_in); + } return; } if ( (NULL == ar->session) && (GNUNET_HELLO_address_check_option (ar->address, GNUNET_HELLO_ADDRESS_INFO_INBOUND)) ) { - GNUNET_assert (0); + GNUNET_break (0); return; } + sh->backoff = GNUNET_TIME_UNIT_ZERO; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ATS suggests address slot %u for peer `%s' using plugin %s\n", + ar->slot, + GNUNET_i2s (&ar->address->peer), + ar->address->transport_name); sh->suggest_cb (sh->suggest_cb_cls, &m->peer, ar->address, @@ -513,9 +450,9 @@ error_handler (void *cls, { struct GNUNET_ATS_SchedulingHandle *sh = cls; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "ATS connection died (code %d), reconnecting\n", - (int) error); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ATS connection died (code %d), reconnecting\n", + (int) error); force_reconnect (sh); } @@ -533,100 +470,41 @@ send_add_address_message (struct GNUNET_ATS_SchedulingHandle *sh, { struct GNUNET_MQ_Envelope *ev; struct AddressAddMessage *m; - struct GNUNET_ATS_Information *am; char *pm; size_t namelen; size_t msize; if (NULL == sh->mq) return; /* disconnected, skip for now */ - namelen = (NULL == ar->address->transport_name) - ? 0 - : strlen (ar->address->transport_name) + 1; - msize = ar->address->address_length + - ar->ats_count * sizeof (struct GNUNET_ATS_Information) + namelen; - + GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != ar->properties.scope); + namelen = strlen (ar->address->transport_name) + 1; + msize = ar->address->address_length + namelen; ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD); - m->ats_count = htonl (ar->ats_count); m->peer = ar->address->peer; m->address_length = htons (ar->address->address_length); m->address_local_info = htonl ((uint32_t) ar->address->local_info); m->plugin_name_length = htons (namelen); m->session_id = htonl (ar->slot); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding address for peer `%s', plugin `%s', session %p id %u\n", - GNUNET_i2s (&ar->address->peer), - ar->address->transport_name, - ar->session, - ar->slot); - am = (struct GNUNET_ATS_Information *) &m[1]; - memcpy (am, - ar->ats, - ar->ats_count * sizeof (struct GNUNET_ATS_Information)); - pm = (char *) &am[ar->ats_count]; - memcpy (pm, + m->properties = ar->properties; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding address for peer `%s', plugin `%s', session %p slot %u\n", + GNUNET_i2s (&ar->address->peer), + ar->address->transport_name, + ar->session, + ar->slot); + pm = (char *) &m[1]; + GNUNET_memcpy (pm, ar->address->address, ar->address->address_length); if (NULL != ar->address->transport_name) - memcpy (&pm[ar->address->address_length], + GNUNET_memcpy (&pm[ar->address->address_length], ar->address->transport_name, namelen); GNUNET_MQ_send (sh->mq, ev); } -/** - * Transmit request for an address suggestion. - * - * @param cls the `struct GNUNET_ATS_SchedulingHandle` - * @param peer peer to ask for an address suggestion for - * @param value the `struct GNUNET_ATS_SuggestHandle` - * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on - * failure (message queue no longer exists) - */ -static int -transmit_suggestion (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *value) -{ - struct GNUNET_ATS_SchedulingHandle *sh = cls; - struct GNUNET_MQ_Envelope *ev; - struct RequestAddressMessage *m; - - if (NULL == sh->mq) - return GNUNET_SYSERR; - ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS); - m->reserved = htonl (0); - m->peer = *peer; - GNUNET_MQ_send (sh->mq, ev); - return GNUNET_OK; -} - - -/** - * Generate and transmit the `struct AddressUseMessage` for the given - * address record. - * - * @param ar the address to inform the ATS service about - * @param in_use say if it is in use or not - */ -static void -send_in_use_message (struct GNUNET_ATS_AddressRecord *ar, - int in_use) -{ - struct GNUNET_ATS_SchedulingHandle *sh = ar->sh; - struct GNUNET_MQ_Envelope *ev; - struct AddressUseMessage *m; - - ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE); - m->peer = ar->address->peer; - m->in_use = htonl ((uint32_t) in_use); - m->session_id = htonl (ar->slot); - GNUNET_MQ_send (sh->mq, ev); -} - - /** * Re-establish the connection to the ATS service. * @@ -635,30 +513,34 @@ send_in_use_message (struct GNUNET_ATS_AddressRecord *ar, static void reconnect (struct GNUNET_ATS_SchedulingHandle *sh) { - static const struct GNUNET_MQ_MessageHandler handlers[] = - { { &process_ats_session_release_message, - GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE, - sizeof (struct SessionReleaseMessage) }, - { &process_ats_address_suggestion_message, - GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION, - sizeof (struct AddressSuggestionMessage) }, - { NULL, 0, 0 } }; + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_fixed_size (ats_session_release, + GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE, + struct GNUNET_ATS_SessionReleaseMessage, + sh), + GNUNET_MQ_hd_fixed_size (ats_address_suggestion, + GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION, + struct AddressSuggestionMessage, + sh), + GNUNET_MQ_handler_end () + }; struct GNUNET_MQ_Envelope *ev; struct ClientStartMessage *init; unsigned int i; struct GNUNET_ATS_AddressRecord *ar; - GNUNET_assert (NULL == sh->client); - sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg); - if (NULL == sh->client) + GNUNET_assert (NULL == sh->mq); + sh->mq = GNUNET_CLIENT_connect (sh->cfg, + "ats", + handlers, + &error_handler, + sh); + if (NULL == sh->mq) { + GNUNET_break (0); force_reconnect (sh); return; } - sh->mq = GNUNET_MQ_queue_for_connection_client (sh->client, - handlers, - &error_handler, - sh); ev = GNUNET_MQ_msg (init, GNUNET_MESSAGE_TYPE_ATS_START); init->start_flag = htonl (START_FLAG_SCHEDULING); @@ -671,333 +553,9 @@ reconnect (struct GNUNET_ATS_SchedulingHandle *sh) if (NULL == ar) continue; send_add_address_message (sh, ar); - if (ar->in_use) - send_in_use_message (ar, GNUNET_YES); if (NULL == sh->mq) return; } - GNUNET_CONTAINER_multipeermap_iterate (sh->sug_requests, - &transmit_suggestion, - sh); -} - - -/** - * Delete all entries from the current network list. - * - * @param sh scheduling handle to clean up - */ -static void -delete_networks (struct GNUNET_ATS_SchedulingHandle *sh) -{ - struct ATS_Network *cur; - - while (NULL != (cur = sh->net_head)) - { - GNUNET_CONTAINER_DLL_remove (sh->net_head, - sh->net_tail, - cur); - GNUNET_free (cur); - } -} - - -/** - * Function invoked for each interface found. Adds the interface's - * network addresses to the respective DLL, so we can distinguish - * between LAN and WAN. - * - * @param cls closure - * @param name name of the interface (can be NULL for unknown) - * @param isDefault is this presumably the default interface - * @param addr address of this interface (can be NULL for unknown or unassigned) - * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) - * @param netmask the network mask (can be NULL for unknown or unassigned) - * @param addrlen length of the address - * @return #GNUNET_OK to continue iteration - */ -static int -interface_proc (void *cls, - const char *name, - int isDefault, - const struct sockaddr *addr, - const struct sockaddr *broadcast_addr, - const struct sockaddr *netmask, - socklen_t addrlen) -{ - struct GNUNET_ATS_SchedulingHandle *sh = cls; - /* Calculate network */ - struct ATS_Network *net = NULL; - - /* Skipping IPv4 loopback addresses since we have special check */ - if (addr->sa_family == AF_INET) - { - const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; - - if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) - return GNUNET_OK; - } - /* Skipping IPv6 loopback addresses since we have special check */ - if (addr->sa_family == AF_INET6) - { - const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; - if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) - return GNUNET_OK; - } - - if (addr->sa_family == AF_INET) - { - const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr; - const struct sockaddr_in *netmask4 = (const struct sockaddr_in *) netmask; - struct sockaddr_in *tmp; - struct sockaddr_in network4; - - net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in)); - tmp = (struct sockaddr_in *) &net[1]; - net->network = (struct sockaddr *) &tmp[0]; - net->netmask = (struct sockaddr *) &tmp[1]; - net->length = addrlen; - - memset (&network4, 0, sizeof (network4)); - network4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - network4.sin_len = sizeof (network4); -#endif - network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr); - - memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in)); - memcpy (net->network, &network4, sizeof (struct sockaddr_in)); - } - - if (addr->sa_family == AF_INET6) - { - const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr; - const struct sockaddr_in6 *netmask6 = (const struct sockaddr_in6 *) netmask; - struct sockaddr_in6 * tmp; - struct sockaddr_in6 network6; - - net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6)); - tmp = (struct sockaddr_in6 *) &net[1]; - net->network = (struct sockaddr *) &tmp[0]; - net->netmask = (struct sockaddr *) &tmp[1]; - net->length = addrlen; - - memset (&network6, 0, sizeof (network6)); - network6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - network6.sin6_len = sizeof (network6); -#endif - unsigned int c = 0; - uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr; - uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr; - uint32_t *net_elem = (uint32_t *) &network6.sin6_addr; - for (c = 0; c < 4; c++) - net_elem[c] = addr_elem[c] & mask_elem[c]; - - memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); - memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); - } - if (NULL == net) - return GNUNET_OK; /* odd / unsupported address family */ - - /* Store in list */ -#if VERBOSE_ATS - char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding network `%s', netmask `%s'\n", - GNUNET_a2s ((struct sockaddr *) net->network, - addrlen), - netmask); - GNUNET_free (netmask); -#endif - GNUNET_CONTAINER_DLL_insert (sh->net_head, - sh->net_tail, - net); - - return GNUNET_OK; -} - - -/** - * Periodically get list of network addresses from our interfaces. - * - * @param cls closure - * @param tc Task context - */ -static void -get_addresses (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_ATS_SchedulingHandle *sh = cls; - - sh->interface_task = NULL; - delete_networks (sh); - GNUNET_OS_network_interfaces_list (&interface_proc, - sh); - sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL, - &get_addresses, - sh); -} - - -/** - * Convert a `enum GNUNET_ATS_Network_Type` to a string - * - * @param net the network type - * @return a string or NULL if invalid - */ -const char * -GNUNET_ATS_print_network_type (enum GNUNET_ATS_Network_Type net) -{ - switch (net) - { - case GNUNET_ATS_NET_UNSPECIFIED: - return "UNSPECIFIED"; - case GNUNET_ATS_NET_LOOPBACK: - return "LOOPBACK"; - case GNUNET_ATS_NET_LAN: - return "LAN"; - case GNUNET_ATS_NET_WAN: - return "WAN"; - case GNUNET_ATS_NET_WLAN: - return "WLAN"; - case GNUNET_ATS_NET_BT: - return "BLUETOOTH"; - default: - return NULL; - } -} - - -/** - * Convert a ATS property to a string - * - * @param type the property type - * @return a string or NULL if invalid - */ -const char * -GNUNET_ATS_print_property_type (enum GNUNET_ATS_Property type) -{ - switch (type) - { - case GNUNET_ATS_ARRAY_TERMINATOR: - return "TERMINATOR"; - case GNUNET_ATS_UTILIZATION_OUT: - return "UTILIZATION_UP"; - case GNUNET_ATS_UTILIZATION_IN: - return "UTILIZATION_DOWN"; - case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT: - return "UTILIZATION_PAYLOAD_UP"; - case GNUNET_ATS_UTILIZATION_PAYLOAD_IN: - return "UTILIZATION_PAYLOAD_DOWN"; - case GNUNET_ATS_NETWORK_TYPE: - return "NETWORK_TYPE"; - case GNUNET_ATS_QUALITY_NET_DELAY: - return "DELAY"; - case GNUNET_ATS_QUALITY_NET_DISTANCE: - return "DISTANCE"; - case GNUNET_ATS_COST_WAN: - return "COST_WAN"; - case GNUNET_ATS_COST_LAN: - return "COST_LAN"; - case GNUNET_ATS_COST_WLAN: - return "COST_WLAN"; - default: - return NULL; - } -} - - -/** - * Returns where the address is located: LAN or WAN or ... - * - * @param sh the scheduling handle - * @param addr address - * @param addrlen address length - * @return type of the network the address belongs to - */ -enum GNUNET_ATS_Network_Type -GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle *sh, - const struct sockaddr *addr, - socklen_t addrlen) -{ - struct ATS_Network *cur = sh->net_head; - enum GNUNET_ATS_NetworkType type = GNUNET_ATS_NET_UNSPECIFIED; - - switch (addr->sa_family) - { - case AF_UNIX: - type = GNUNET_ATS_NET_LOOPBACK; - break; - case AF_INET: - { - const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; - - if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) - type = GNUNET_ATS_NET_LOOPBACK; - break; - } - case AF_INET6: - { - const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; - - if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) - type = GNUNET_ATS_NET_LOOPBACK; - break; - } - default: - GNUNET_break (0); - break; - } - - /* Check local networks */ - while ((NULL != cur) && (GNUNET_ATS_NET_UNSPECIFIED == type)) - { - if (addrlen != cur->length) - { - cur = cur->next; - continue; - } - if (addr->sa_family == AF_INET) - { - const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr; - const struct sockaddr_in *net4 = (const struct sockaddr_in *) cur->network; - const struct sockaddr_in *mask4 = (const struct sockaddr_in *) cur->netmask; - - if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr) - type = GNUNET_ATS_NET_LAN; - } - if (addr->sa_family == AF_INET6) - { - const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr; - const struct sockaddr_in6 *net6 = (const struct sockaddr_in6 *) cur->network; - const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *) cur->netmask; - - int res = GNUNET_YES; - int c = 0; - uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr; - uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr; - uint32_t *net_elem = (uint32_t *) &net6->sin6_addr; - for (c = 0; c < 4; c++) - if ((addr_elem[c] & mask_elem[c]) != net_elem[c]) - res = GNUNET_NO; - - if (res == GNUNET_YES) - type = GNUNET_ATS_NET_LAN; - } - cur = cur->next; - } - - /* no local network found for this address, default: WAN */ - if (type == GNUNET_ATS_NET_UNSPECIFIED) - type = GNUNET_ATS_NET_WAN; - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "ats-scheduling-api", - "`%s' is in network `%s'\n", - GNUNET_a2s (addr, - addrlen), - GNUNET_ATS_print_network_type (type)); - return type; } @@ -1023,39 +581,11 @@ GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_array_grow (sh->session_array, sh->session_array_size, 4); - sh->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, - GNUNET_YES); - GNUNET_OS_network_interfaces_list (&interface_proc, - sh); - sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL, - &get_addresses, - sh); reconnect (sh); return sh; } -/** - * Function called to free all `struct GNUNET_ATS_SuggestHandles` - * in the map. - * - * @param cls NULL - * @param key the key - * @param value the value to free - * @return #GNUNET_OK (continue to iterate) - */ -static int -free_sug_handle (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct GNUNET_ATS_SuggestHandle *cur = value; - - GNUNET_free (cur); - return GNUNET_OK; -} - - /** * Client is done with ATS scheduling, release resources. * @@ -1064,31 +594,28 @@ free_sug_handle (void *cls, void GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) { + struct GNUNET_ATS_AddressRecord *ar; + unsigned int i; + if (NULL != sh->mq) { GNUNET_MQ_destroy (sh->mq); sh->mq = NULL; } - if (NULL != sh->client) - { - GNUNET_CLIENT_disconnect (sh->client); - sh->client = NULL; - } if (NULL != sh->task) { GNUNET_SCHEDULER_cancel (sh->task); sh->task = NULL; } - GNUNET_CONTAINER_multipeermap_iterate (sh->sug_requests, - &free_sug_handle, - NULL); - GNUNET_CONTAINER_multipeermap_destroy (sh->sug_requests); - if (NULL != sh->interface_task) + for (i=0;isession_array_size;i++) { - GNUNET_SCHEDULER_cancel (sh->interface_task); - sh->interface_task = NULL; + if (NULL != (ar = sh->session_array[i])) + { + GNUNET_HELLO_address_free (ar->address); + GNUNET_free (ar); + sh->session_array[i] = NULL; + } } - delete_networks (sh); GNUNET_array_grow (sh->session_array, sh->session_array_size, 0); @@ -1096,121 +623,6 @@ GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) } -/** - * We would like to reset the address suggestion block time for this - * peer. - * - * @param sh handle - * @param peer identity of the peer we want to reset - */ -void -GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh, - const struct GNUNET_PeerIdentity *peer) -{ - struct GNUNET_MQ_Envelope *ev; - struct ResetBackoffMessage *m; - - ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF); - m->reserved = htonl (0); - m->peer = *peer; - GNUNET_MQ_send (sh->mq, ev); -} - - -/** - * We would like to receive address suggestions for a peer. ATS will - * respond with a call to the continuation immediately containing an address or - * no address if none is available. ATS can suggest more addresses until we call - * #GNUNET_ATS_suggest_address_cancel(). - * - * @param sh handle - * @param peer identity of the peer we need an address for - * @return suggest handle, NULL if a request is already pending - */ -struct GNUNET_ATS_SuggestHandle * -GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh, - const struct GNUNET_PeerIdentity *peer) -{ - struct GNUNET_ATS_SuggestHandle *s; - - s = GNUNET_new (struct GNUNET_ATS_SuggestHandle); - s->id = *peer; - if (GNUNET_OK != - GNUNET_CONTAINER_multipeermap_put (sh->sug_requests, - &s->id, - s, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_break (0); - return NULL; - } - if (NULL == sh->mq) - return s; - (void) transmit_suggestion (sh, - &s->id, - s); - return s; -} - - -/** - * We would like to stop receiving address updates for this peer - * - * @param sh handle - * @param peer identity of the peer - */ -void -GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh, - const struct GNUNET_PeerIdentity *peer) -{ - struct GNUNET_MQ_Envelope *ev; - struct RequestAddressMessage *m; - struct GNUNET_ATS_SuggestHandle *s; - - s = GNUNET_CONTAINER_multipeermap_get (sh->sug_requests, - peer); - if (NULL == s) - { - GNUNET_break (0); - return; - } - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_remove (sh->sug_requests, - &s->id, - s)); - GNUNET_free (s); - if (NULL == sh->mq) - return; - ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL); - m->reserved = htonl (0); - m->peer = *peer; - GNUNET_MQ_send (sh->mq, ev); -} - - -/** - * Test if a address and a session is known to ATS - * - * @param sh the scheduling handle - * @param address the address - * @param session the session - * @return #GNUNET_YES or #GNUNET_NO - */ -int -GNUNET_ATS_session_known (struct GNUNET_ATS_SchedulingHandle *sh, - const struct GNUNET_HELLO_Address *address, - struct Session *session) -{ - if (NULL == session) - return GNUNET_NO; - if (NOT_FOUND != find_session_id (sh, - session, - address)) - return GNUNET_YES; /* Exists */ - return GNUNET_NO; -} - - /** * We have a new address ATS should know. Addresses have to be added * with this function before they can be: updated, set in use and @@ -1219,17 +631,15 @@ GNUNET_ATS_session_known (struct GNUNET_ATS_SchedulingHandle *sh, * @param sh handle * @param address the address * @param session session handle, can be NULL - * @param ats performance data for the address - * @param ats_count number of performance records in @a ats + * @param prop performance data for the address * @return handle to the address representation inside ATS, NULL * on error (i.e. ATS knows this exact address already) */ struct GNUNET_ATS_AddressRecord * GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count) + struct GNUNET_ATS_Session *session, + const struct GNUNET_ATS_Properties *prop) { struct GNUNET_ATS_AddressRecord *ar; size_t namelen; @@ -1242,23 +652,22 @@ GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh, GNUNET_break (0); return NULL; } - namelen = (NULL == address->transport_name) - ? 0 - : strlen (address->transport_name) + 1; - msize = address->address_length + - ats_count * sizeof (struct GNUNET_ATS_Information) + namelen; - if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || - (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || - (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || - (ats_count >= - GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))) + GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope); + namelen = strlen (address->transport_name) + 1; + msize = address->address_length + namelen; + if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_MAX_MESSAGE_SIZE) || + (address->address_length >= GNUNET_MAX_MESSAGE_SIZE) || + (namelen >= GNUNET_MAX_MESSAGE_SIZE) ) { /* address too large for us, this should not happen */ GNUNET_break (0); return NULL; } - if (NOT_FOUND != find_session_id (sh, session, address)) + if (NOT_FOUND != + find_session_id (sh, + session, + address)) { /* Already existing, nothing todo, but this should not happen */ GNUNET_break (0); @@ -1270,12 +679,8 @@ GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh, ar->slot = s; ar->session = session; ar->address = GNUNET_HELLO_address_copy (address); - GNUNET_array_grow (ar->ats, - ar->ats_count, - ats_count); - memcpy (ar->ats, - ats, - ats_count * sizeof (struct GNUNET_ATS_Information)); + GNUNET_ATS_properties_hton (&ar->properties, + prop); sh->session_array[s] = ar; send_add_address_message (sh, ar); return ar; @@ -1290,7 +695,7 @@ GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh, */ void GNUNET_ATS_address_add_session (struct GNUNET_ATS_AddressRecord *ar, - struct Session *session) + struct GNUNET_ATS_Session *session) { GNUNET_break (NULL == ar->session); ar->session = session; @@ -1311,11 +716,10 @@ GNUNET_ATS_address_add_session (struct GNUNET_ATS_AddressRecord *ar, */ int GNUNET_ATS_address_del_session (struct GNUNET_ATS_AddressRecord *ar, - struct Session *session) + struct GNUNET_ATS_Session *session) { - GNUNET_break (session == ar->session); + GNUNET_assert (session == ar->session); ar->session = NULL; - GNUNET_break (GNUNET_NO == ar->in_use); if (GNUNET_HELLO_address_check_option (ar->address, GNUNET_HELLO_ADDRESS_INFO_INBOUND)) { @@ -1335,69 +739,33 @@ GNUNET_ATS_address_del_session (struct GNUNET_ATS_AddressRecord *ar, * for later use). Update bandwidth assignments. * * @param ar address record to update information for - * @param ats performance data for the address - * @param ats_count number of performance records in @a ats + * @param prop performance data for the address */ void GNUNET_ATS_address_update (struct GNUNET_ATS_AddressRecord *ar, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count) + const struct GNUNET_ATS_Properties *prop) { struct GNUNET_ATS_SchedulingHandle *sh = ar->sh; struct GNUNET_MQ_Envelope *ev; struct AddressUpdateMessage *m; - struct GNUNET_ATS_Information *am; - size_t msize; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding address for peer `%s', plugin `%s', session %p id %u\n", - GNUNET_i2s (&ar->address->peer), - ar->address->transport_name, - ar->session, - ar->slot); - GNUNET_array_grow (ar->ats, - ar->ats_count, - ats_count); - memcpy (ar->ats, - ats, - ats_count * sizeof (struct GNUNET_ATS_Information)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Updating address for peer `%s', plugin `%s', session %p slot %u\n", + GNUNET_i2s (&ar->address->peer), + ar->address->transport_name, + ar->session, + ar->slot); + GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope); + GNUNET_ATS_properties_hton (&ar->properties, + prop); if (NULL == sh->mq) return; /* disconnected, skip for now */ - msize = ar->ats_count * sizeof (struct GNUNET_ATS_Information); - ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); - m->ats_count = htonl (ar->ats_count); - m->peer = ar->address->peer; + ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); m->session_id = htonl (ar->slot); - am = (struct GNUNET_ATS_Information *) &m[1]; - memcpy (am, - ar->ats, - ar->ats_count * sizeof (struct GNUNET_ATS_Information)); - GNUNET_MQ_send (sh->mq, ev); -} - - -/** - * An address is now in use or not used any more. - * - * @param ar the address - * @param in_use #GNUNET_YES if this address is now used, #GNUNET_NO - * if address is not used any more - */ -void -GNUNET_ATS_address_set_in_use (struct GNUNET_ATS_AddressRecord *ar, - int in_use) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Setting address used to %s for peer `%s', plugin `%s', session %p\n", - (GNUNET_YES == in_use) ? "YES" : "NO", - GNUNET_i2s (&ar->address->peer), - ar->address->transport_name, - ar->session); - ar->in_use = in_use; - if (NULL == ar->sh->mq) - return; - send_in_use_message (ar, in_use); + m->peer = ar->address->peer; + m->properties = ar->properties; + GNUNET_MQ_send (sh->mq, + ev); } @@ -1413,17 +781,15 @@ GNUNET_ATS_address_destroy (struct GNUNET_ATS_AddressRecord *ar) struct GNUNET_MQ_Envelope *ev; struct AddressDestroyedMessage *m; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Deleting address for peer `%s', plugin `%s', session %p\n", - GNUNET_i2s (&ar->address->peer), - ar->address->transport_name, - ar->session); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Deleting address for peer `%s', plugin `%s', slot %u session %p\n", + GNUNET_i2s (&ar->address->peer), + ar->address->transport_name, + ar->slot, + ar->session); GNUNET_break (NULL == ar->session); ar->session = NULL; ar->in_destroy = GNUNET_YES; - GNUNET_array_grow (ar->ats, - ar->ats_count, - 0); if (NULL == sh->mq) return; ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);