X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fats%2Fats_api_performance.c;h=90e061c1d2873e62716ff1cb183716dcac7fcb1b;hb=f1ca38573f22205e28ac482efebe463696c9c2c7;hp=f7b9f5d8707cf4fb1c5cb7241c29088e448dbe33;hpb=0418c2046354ff332e9d63d123513087788e5b45;p=oweals%2Fgnunet.git diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c index f7b9f5d87..90e061c1d 100644 --- a/src/ats/ats_api_performance.c +++ b/src/ats/ats_api_performance.c @@ -1,33 +1,32 @@ /* - 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. -*/ + 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_performance.c * @brief automatic transport selection and outbound bandwidth determination * @author Christian Grothoff * @author Matthias Wachs - */ + */ #include "platform.h" #include "gnunet_ats_service.h" #include "ats.h" - /** * Message in linked list we should send to the ATS service. The * actual binary message follows this struct. @@ -37,12 +36,12 @@ struct PendingMessage /** * Kept in a DLL. - */ + */ struct PendingMessage *next; /** * Kept in a DLL. - */ + */ struct PendingMessage *prev; /** @@ -52,11 +51,10 @@ struct PendingMessage /** * Is this the 'ATS_START' message? - */ + */ int is_init; }; - /** * Linked list of pending reservations. */ @@ -65,19 +63,19 @@ struct GNUNET_ATS_ReservationContext /** * Kept in a DLL. - */ + */ struct GNUNET_ATS_ReservationContext *next; /** * Kept in a DLL. - */ + */ struct GNUNET_ATS_ReservationContext *prev; /** * Target peer. */ struct GNUNET_PeerIdentity peer; - + /** * Desired reservation */ @@ -104,27 +102,78 @@ struct GNUNET_ATS_ReservationContext int undo; }; +/** + * Linked list of pending reservations. + */ +struct GNUNET_ATS_AddressListHandle +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_ATS_AddressListHandle *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_ATS_AddressListHandle *prev; + + /** + * Performance handle + */ + struct GNUNET_ATS_PerformanceHandle *ph; + + /** + * Callback + */ + GNUNET_ATS_AddressInformationCallback cb; + + /** + * Callback closure + */ + void *cb_cls; + + /** + * Target peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Return all or specific peer only + */ + int all_peers; + + /** + * Return all or used address only + */ + int all_addresses; + + /** + * Request multiplexing + */ + uint32_t id; +}; /** * ATS Handle to obtain and/or modify performance information. */ struct GNUNET_ATS_PerformanceHandle { - + /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Callback to invoke on performance changes. + * Callback to invoke when an address has performance changes. */ - GNUNET_ATS_PeerInformationCallback infocb; - + GNUNET_ATS_AddressInformationCallback addr_info_cb; + /** - * Closure for 'infocb'. + * Closure for 'addr_info_cb'. */ - void *infocb_cls; + void *addr_info_cb_cls; /** * Connection to ATS service. @@ -151,6 +200,16 @@ struct GNUNET_ATS_PerformanceHandle */ struct GNUNET_ATS_ReservationContext *reservation_tail; + /** + * Head of linked list of pending address list requests. + */ + struct GNUNET_ATS_AddressListHandle *addresslist_head; + + /** + * Tail of linked list of pending address list requests. + */ + struct GNUNET_ATS_AddressListHandle *addresslist_tail; + /** * Current request for transmission to ATS. */ @@ -158,21 +217,28 @@ struct GNUNET_ATS_PerformanceHandle /** * Task to trigger reconnect. - */ + */ GNUNET_SCHEDULER_TaskIdentifier task; - -}; + /** + * Monitor request multiplexing + */ + uint32_t monitor_id; + + /** + * Request multiplexing + */ + uint32_t id; +}; /** * Re-establish the connection to the ATS service. * - * @param sh handle to use to re-connect. + * @param ph handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_PerformanceHandle *ph); - /** * Re-establish the connection to the ATS service. * @@ -180,8 +246,7 @@ reconnect (struct GNUNET_ATS_PerformanceHandle *ph); * @param tc scheduler context */ static void -reconnect_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_ATS_PerformanceHandle *ph = cls; @@ -189,16 +254,24 @@ reconnect_task (void *cls, reconnect (ph); } - /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * - * @param sh handle to use + * @param ph handle to use */ static void do_transmit (struct GNUNET_ATS_PerformanceHandle *ph); +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg); /** * We can now transmit a message to ATS. Do it. @@ -209,9 +282,7 @@ do_transmit (struct GNUNET_ATS_PerformanceHandle *ph); * @return number of bytes copied into buf */ static size_t -transmit_message_to_ats (void *cls, - size_t size, - void *buf) +transmit_message_to_ats (void *cls, size_t size, void *buf) { struct GNUNET_ATS_PerformanceHandle *ph = cls; struct PendingMessage *p; @@ -221,22 +292,18 @@ transmit_message_to_ats (void *cls, ph->th = NULL; ret = 0; cbuf = buf; - while ( (NULL != (p = ph->pending_head)) && - (p->size <= size) ) + while ((NULL != (p = ph->pending_head)) && (p->size <= size)) { - memcpy (&cbuf[ret], &p[1], p->size); + memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; - GNUNET_CONTAINER_DLL_remove (ph->pending_head, - ph->pending_tail, - p); - GNUNET_free (p); + GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p); + GNUNET_free(p); } do_transmit (ph); return ret; } - /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). @@ -252,14 +319,12 @@ do_transmit (struct GNUNET_ATS_PerformanceHandle *ph) return; if (NULL == (p = ph->pending_head)) return; - ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client, - p->size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, - &transmit_message_to_ats, ph); + if (NULL == ph->client) + return; /* currently reconnecting */ + ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size, + GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_message_to_ats, ph); } - /** * We received a peer information message. Validate and process it. * @@ -269,55 +334,57 @@ do_transmit (struct GNUNET_ATS_PerformanceHandle *ph) */ static int process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, - const struct GNUNET_MessageHeader *msg) + const struct GNUNET_MessageHeader *msg) { const struct PeerInformationMessage *pi; const struct GNUNET_ATS_Information *atsi; - const char *address; + const char *plugin_address; const char *plugin_name; - uint16_t address_length; + struct GNUNET_HELLO_Address address; + uint16_t plugin_address_length; uint16_t plugin_name_length; uint32_t ats_count; + int addr_active; - if (ph->infocb == NULL) + if (ntohs (msg->size) < sizeof(struct PeerInformationMessage)) { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (ntohs (msg->size) < sizeof (struct PeerInformationMessage)) - { - GNUNET_break (0); + GNUNET_break(0); return GNUNET_SYSERR; } - pi = (const struct PeerInformationMessage*) msg; + + pi = (const struct PeerInformationMessage *) msg; ats_count = ntohl (pi->ats_count); - address_length = ntohs (pi->address_length); + plugin_address_length = ntohs (pi->address_length); plugin_name_length = ntohs (pi->plugin_name_length); - atsi = (const struct GNUNET_ATS_Information*) &pi[1]; - address = (const char*) &atsi[ats_count]; - plugin_name = &address[address_length]; - if ( (address_length + - plugin_name_length + - ats_count * sizeof (struct GNUNET_ATS_Information) + - sizeof (struct PeerInformationMessage) != ntohs (msg->size)) || - (ats_count > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) || - (plugin_name[plugin_name_length - 1] != '\0') ) + addr_active = ntohl (pi->address_active); + atsi = (const struct GNUNET_ATS_Information *) &pi[1]; + plugin_address = (const char *) &atsi[ats_count]; + plugin_name = &plugin_address[plugin_address_length]; + if ((plugin_address_length + plugin_name_length + + ats_count * sizeof(struct GNUNET_ATS_Information) + + sizeof(struct PeerInformationMessage) != ntohs (msg->size)) + || (ats_count + > GNUNET_SERVER_MAX_MESSAGE_SIZE + / sizeof(struct GNUNET_ATS_Information)) + || (plugin_name[plugin_name_length - 1] != '\0')) { - GNUNET_break (0); + GNUNET_break(0); return GNUNET_SYSERR; } - ph->infocb (ph->infocb_cls, - &pi->peer, - plugin_name, - address, address_length, - pi->bandwidth_out, - pi->bandwidth_in, - atsi, - ats_count); + + if (NULL != ph->addr_info_cb) + { + address.peer = pi->peer; + address.address = plugin_address; + address.address_length = plugin_address_length; + address.transport_name = plugin_name; + + ph->addr_info_cb (ph->addr_info_cb_cls, &address, addr_active, + pi->bandwidth_out, pi->bandwidth_in, atsi, ats_count); + } return GNUNET_OK; } - /** * We received a reservation result message. Validate and process it. * @@ -327,58 +394,145 @@ process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, */ static int process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph, - const struct GNUNET_MessageHeader *msg) + const struct GNUNET_MessageHeader *msg) { const struct ReservationResultMessage *rr; struct GNUNET_ATS_ReservationContext *rc; int32_t amount; - if (ph->infocb == NULL) + if (ntohs (msg->size) < sizeof(struct ReservationResultMessage)) { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (ntohs (msg->size) < sizeof (struct ReservationResultMessage)) - { - GNUNET_break (0); + GNUNET_break(0); return GNUNET_SYSERR; } - rr = (const struct ReservationResultMessage*) msg; + rr = (const struct ReservationResultMessage *) msg; amount = ntohl (rr->amount); rc = ph->reservation_head; - if (0 != memcmp (&rr->peer, - &rc->peer, - sizeof (struct GNUNET_PeerIdentity))) + if (0 != memcmp (&rr->peer, &rc->peer, sizeof(struct GNUNET_PeerIdentity))) { - GNUNET_break (0); + GNUNET_break(0); return GNUNET_SYSERR; } - GNUNET_CONTAINER_DLL_remove (ph->reservation_head, - ph->reservation_tail, - rc); - if ( (amount == 0) || - (rc->rcb != NULL) ) + GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail, rc); + if ((amount == 0) || (rc->rcb != NULL )) { /* tell client if not cancelled */ - if (rc->rcb != NULL) - rc->rcb (rc->rcb_cls, - &rr->peer, - amount, - GNUNET_TIME_relative_ntoh (rr->res_delay)); - GNUNET_free (rc); + if (rc->rcb != NULL ) + rc->rcb (rc->rcb_cls, &rr->peer, amount, + GNUNET_TIME_relative_ntoh (rr->res_delay)); + GNUNET_free(rc); return GNUNET_OK; } /* amount non-zero, but client cancelled, consider undo! */ if (GNUNET_YES != rc->undo) { - GNUNET_free (rc); + GNUNET_free(rc); return GNUNET_OK; /* do not try to undo failed undos or negative amounts */ } - GNUNET_free (rc); - (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL); + GNUNET_free(rc); + (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL ); return GNUNET_OK; } +/** + * We received a reservation result message. Validate and process it. + * + * @param ph our context with the callback + * @param msg the message + * @return GNUNET_OK if the message was well-formed + */ +static int +process_ar_message (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_MessageHeader *msg) +{ + const struct PeerInformationMessage *pi; + struct GNUNET_ATS_AddressListHandle *alh; + struct GNUNET_ATS_AddressListHandle *next; + const struct GNUNET_ATS_Information *atsi; + const char *plugin_address; + const char *plugin_name; + struct GNUNET_HELLO_Address address; + struct GNUNET_PeerIdentity allzeros; + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero; + uint16_t plugin_address_length; + uint16_t plugin_name_length; + uint32_t ats_count; + uint32_t active; + uint32_t id; + + if (ntohs (msg->size) < sizeof(struct PeerInformationMessage)) + { + GNUNET_break(0); + return GNUNET_SYSERR; + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Received %s message\n"), + "ATS_ADDRESSLIST_RESPONSE"); + + pi = (const struct PeerInformationMessage *) msg; + id = ntohl (pi->id); + ats_count = ntohl (pi->ats_count); + active = ntohl (pi->address_active); + plugin_address_length = ntohs (pi->address_length); + plugin_name_length = ntohs (pi->plugin_name_length); + atsi = (const struct GNUNET_ATS_Information *) &pi[1]; + plugin_address = (const char *) &atsi[ats_count]; + plugin_name = &plugin_address[plugin_address_length]; + if ((plugin_address_length + plugin_name_length + + ats_count * sizeof(struct GNUNET_ATS_Information) + + sizeof(struct PeerInformationMessage) != ntohs (msg->size)) + || (ats_count + > GNUNET_SERVER_MAX_MESSAGE_SIZE + / sizeof(struct GNUNET_ATS_Information)) + || (plugin_name[plugin_name_length - 1] != '\0')) + { + GNUNET_break(0); + return GNUNET_SYSERR; + } + + next = ph->addresslist_head; + while (NULL != (alh = next)) + { + next = alh->next; + if (alh->id == id) + break; + } + if (NULL == alh) + { + /* was canceled */ + return GNUNET_SYSERR; + } + + memset (&allzeros, '\0', sizeof(allzeros)); + if ((0 == memcmp (&allzeros, &pi->peer, sizeof(allzeros))) + && (0 == plugin_name_length) && (0 == plugin_address_length) + && (0 == ats_count)) + { + /* Done */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Received last message for %s \n"), + "ATS_ADDRESSLIST_RESPONSE"); + bandwidth_zero.value__ = htonl (0); + if (NULL != alh->cb) + alh->cb (ph->addr_info_cb_cls, NULL, GNUNET_NO, bandwidth_zero, + bandwidth_zero, NULL, 0); + GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail, + alh); + GNUNET_free(alh); + return GNUNET_OK; + } + + address.peer = pi->peer; + address.address = plugin_address; + address.address_length = plugin_address_length; + address.transport_name = plugin_name; + + if ((GNUNET_YES == alh->all_addresses) || (GNUNET_YES == active)) + { + if (NULL != alh->cb) + alh->cb (ph->addr_info_cb_cls, &address, active, pi->bandwidth_out, + pi->bandwidth_in, atsi, ats_count); + } + return GNUNET_OK; +} /** * Type of a function to call when we receive a message @@ -388,12 +542,11 @@ process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph, * @param msg message received, NULL on timeout or fatal error */ static void -process_ats_message (void *cls, - const struct GNUNET_MessageHeader *msg) +process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ATS_PerformanceHandle *ph = cls; - if (NULL == msg) + if (NULL == msg) goto reconnect; switch (ntohs (msg->type)) { @@ -403,25 +556,30 @@ process_ats_message (void *cls, break; case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT: if (GNUNET_OK != process_rr_message (ph, msg)) - goto reconnect; + goto reconnect; + break; + case GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE: + if (GNUNET_OK != process_ar_message (ph, msg)) + goto reconnect; break; default: - GNUNET_break (0); + GNUNET_break(0); goto reconnect; - return; } - GNUNET_CLIENT_receive (ph->client, - &process_ats_message, ph, - GNUNET_TIME_UNIT_FOREVER_REL); + GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, + GNUNET_TIME_UNIT_FOREVER_REL); return; - reconnect: - GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO); + reconnect: if (NULL != ph->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (ph->th); + ph->th = NULL; + } + GNUNET_CLIENT_disconnect (ph->client); ph->client = NULL; ph->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &reconnect_task, ph); + &reconnect_task, ph); } - /** * Re-establish the connection to the ATS service. * @@ -433,58 +591,52 @@ reconnect (struct GNUNET_ATS_PerformanceHandle *ph) struct PendingMessage *p; struct ClientStartMessage *init; - GNUNET_assert (NULL == ph->client); + GNUNET_assert(NULL == ph->client); ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg); - GNUNET_assert (NULL != ph->client); - GNUNET_CLIENT_receive (ph->client, - &process_ats_message, ph, - GNUNET_TIME_UNIT_FOREVER_REL); - if ( (NULL == (p = ph->pending_head)) || - (GNUNET_YES != p->is_init) ) + GNUNET_assert(NULL != ph->client); + GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, + GNUNET_TIME_UNIT_FOREVER_REL); + if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init)) { p = GNUNET_malloc (sizeof (struct PendingMessage) + - sizeof (struct ClientStartMessage)); - p->size = sizeof (struct ClientStartMessage); + sizeof (struct ClientStartMessage)); + p->size = sizeof(struct ClientStartMessage); p->is_init = GNUNET_YES; init = (struct ClientStartMessage *) &p[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START); - init->header.size = htons (sizeof (struct ClientStartMessage)); - init->start_flag = htonl ((ph->infocb == NULL) - ? START_FLAG_PERFORMANCE_NO_PIC - : START_FLAG_PERFORMANCE_WITH_PIC); - GNUNET_CONTAINER_DLL_insert (ph->pending_head, - ph->pending_tail, - p); + init->header.size = htons (sizeof(struct ClientStartMessage)); + init->start_flag = htonl ( + (NULL == ph->addr_info_cb) ? + START_FLAG_PERFORMANCE_NO_PIC : START_FLAG_PERFORMANCE_WITH_PIC); + GNUNET_CONTAINER_DLL_insert(ph->pending_head, ph->pending_tail, p); } do_transmit (ph); } - - /** * Get handle to access performance API of the ATS subsystem. * * @param cfg configuration to use - * @param infocb function to call on allocation changes, can be NULL - * @param infocb_cls closure for infocb + * @param addr_info_cb callback called when performance characteristics for + * an address change + * @param addr_info_cb_cls closure for infocb * @return ats performance context */ struct GNUNET_ATS_PerformanceHandle * GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_ATS_PeerInformationCallback infocb, - void *infocb_cls) + GNUNET_ATS_AddressInformationCallback addr_info_cb, void *addr_info_cb_cls) { struct GNUNET_ATS_PerformanceHandle *ph; - ph = GNUNET_malloc (sizeof (struct GNUNET_ATS_PerformanceHandle)); + ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle); ph->cfg = cfg; - ph->infocb = infocb; - ph->infocb_cls = infocb_cls; + ph->addr_info_cb = addr_info_cb; + ph->addr_info_cb_cls = addr_info_cb_cls; + ph->id = 0; reconnect (ph); return ph; } - /** * Client is done using the ATS performance subsystem, release resources. * @@ -495,32 +647,39 @@ GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph) { struct PendingMessage *p; struct GNUNET_ATS_ReservationContext *rc; - + struct GNUNET_ATS_AddressListHandle *alh; + while (NULL != (p = ph->pending_head)) { - GNUNET_CONTAINER_DLL_remove (ph->pending_head, - ph->pending_tail, - p); - GNUNET_free (p); + GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p); + GNUNET_free(p); + } + while (NULL != (alh = ph->addresslist_head)) + { + GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail, + alh); + GNUNET_free(alh); } while (NULL != (rc = ph->reservation_head)) { - GNUNET_CONTAINER_DLL_remove (ph->reservation_head, - ph->reservation_tail, - rc); - GNUNET_break (NULL == rc->rcb); - GNUNET_free (p); - } + GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail, rc); + GNUNET_break(NULL == rc->rcb); + GNUNET_free(rc); + } + if (GNUNET_SCHEDULER_NO_TASK != ph->task) { GNUNET_SCHEDULER_cancel (ph->task); ph->task = GNUNET_SCHEDULER_NO_TASK; } - GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO); - GNUNET_free (ph); + if (NULL != ph->client) + { + GNUNET_CLIENT_disconnect (ph->client); + ph->client = NULL; + } + GNUNET_free(ph); } - /** * Reserve inbound bandwidth from the given peer. ATS will look at * the current amount of traffic we receive from the peer and ensure @@ -537,67 +696,156 @@ GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph) */ struct GNUNET_ATS_ReservationContext * GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, - const struct GNUNET_PeerIdentity *peer, - int32_t amount, - GNUNET_ATS_ReservationCallback rcb, - void *rcb_cls) + const struct GNUNET_PeerIdentity *peer, int32_t amount, + GNUNET_ATS_ReservationCallback rcb, void *rcb_cls) { struct GNUNET_ATS_ReservationContext *rc; struct PendingMessage *p; struct ReservationRequestMessage *m; - rc = GNUNET_malloc (sizeof (struct GNUNET_ATS_ReservationContext)); + rc = GNUNET_new (struct GNUNET_ATS_ReservationContext); rc->size = amount; rc->peer = *peer; rc->rcb = rcb; rc->rcb_cls = rcb_cls; - if ( (rcb != NULL) && (amount > 0) ) - rc->undo = GNUNET_YES; - GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, - ph->reservation_tail, - rc); - - p = GNUNET_malloc (sizeof (struct PendingMessage) + - sizeof (struct ReservationRequestMessage)); - p->size = sizeof (struct ReservationRequestMessage); + if ((rcb != NULL )&& (amount > 0))rc->undo = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert_tail(ph->reservation_head, ph->reservation_tail, + rc); + + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct ReservationRequestMessage)); + p->size = sizeof(struct ReservationRequestMessage); p->is_init = GNUNET_NO; - m = (struct ReservationRequestMessage*) &p[1]; - m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); - m->header.size = htons (sizeof (struct ReservationRequestMessage)); + m = (struct ReservationRequestMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST); + m->header.size = htons (sizeof(struct ReservationRequestMessage)); m->amount = htonl (amount); m->peer = *peer; - GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, - ph->pending_tail, - p); + GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p); + do_transmit (ph); return rc; } - /** * Cancel request for reserving bandwidth. * * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call */ void -GNUNET_ATS_reserve_bandwidth_cancel (struct - GNUNET_ATS_ReservationContext *rc) +GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc) { rc->rcb = NULL; } +/** + * Get information about addresses known to the ATS subsystem. + * + * @param handle the performance handle to use + * @param peer peer idm can be NULL for all peers + * @param all GNUNET_YES to get information about all addresses or GNUNET_NO to + * get only address currently used + * @param infocb callback to call with the addresses, + * will callback with address == NULL when done + * @param infocb_cls closure for infocb + * @return ats performance context + */ +struct GNUNET_ATS_AddressListHandle* +GNUNET_ATS_performance_list_addresses ( + struct GNUNET_ATS_PerformanceHandle *handle, + const struct GNUNET_PeerIdentity *peer, int all, + GNUNET_ATS_AddressInformationCallback infocb, void *infocb_cls) +{ + struct GNUNET_ATS_AddressListHandle *alh; + struct PendingMessage *p; + struct AddressListRequestMessage *m; + + GNUNET_assert(NULL != handle); + if (NULL == infocb) + return NULL ; + + alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle); + alh->id = handle->id; + handle->id++; + alh->cb = infocb; + alh->cb_cls = infocb_cls; + alh->ph = handle; + alh->all_addresses = all; + if (NULL == peer) + alh->all_peers = GNUNET_YES; + else + { + alh->all_peers = GNUNET_NO; + alh->peer = (*peer); + } + + GNUNET_CONTAINER_DLL_insert(handle->addresslist_head, + handle->addresslist_tail, alh); + + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct AddressListRequestMessage)); + p->size = sizeof(struct AddressListRequestMessage); + m = (struct AddressListRequestMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST); + m->header.size = htons (sizeof(struct AddressListRequestMessage)); + m->all = htonl (all); + m->id = htonl (alh->id); + if (NULL != peer) + m->peer = *peer; + else + { + memset (&m->peer, '\0', sizeof(struct GNUNET_PeerIdentity)); + } + GNUNET_CONTAINER_DLL_insert_tail(handle->pending_head, handle->pending_tail, + p); + + do_transmit (handle); + + return alh; +} + +/** + * Cancel a pending address listing operation + * + * @param handle the GNUNET_ATS_AddressListHandle handle to cancel + */ +void +GNUNET_ATS_performance_list_addresses_cancel ( + struct GNUNET_ATS_AddressListHandle *handle) +{ + GNUNET_assert(NULL != handle); + + GNUNET_CONTAINER_DLL_remove(handle->ph->addresslist_head, + handle->ph->addresslist_tail, handle); + GNUNET_free(handle); +} + +/** + * Convert a GNUNET_ATS_PreferenceType to a string + * + * @param type the preference type + * @return a string or NULL if invalid + */ +const char * +GNUNET_ATS_print_preference_type (uint32_t type) +{ + char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString; + if (type < GNUNET_ATS_PreferenceCount) + return prefs[type]; + return NULL ; +} /** * Change preferences for the given peer. Preference changes are forgotten if peers * disconnect. - * + * * @param ph performance handle * @param peer identifies the peer * @param ... 0-terminated specification of the desired changes */ void -GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, - const struct GNUNET_PeerIdentity *peer, - ...) +GNUNET_ATS_performance_change_preference ( + struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, ...) { struct PendingMessage *p; struct ChangePreferenceMessage *m; @@ -608,60 +856,146 @@ GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, enum GNUNET_ATS_PreferenceKind kind; count = 0; - va_start (ap, peer); - while (GNUNET_ATS_PREFERENCE_END != (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) + va_start(ap, peer); + while (GNUNET_ATS_PREFERENCE_END != (kind = + va_arg (ap, enum GNUNET_ATS_PreferenceKind) )) { switch (kind) { case GNUNET_ATS_PREFERENCE_BANDWIDTH: count++; (void) va_arg (ap, double); + break; case GNUNET_ATS_PREFERENCE_LATENCY: count++; (void) va_arg (ap, double); + break; default: - GNUNET_assert (0); + GNUNET_assert(0); } } - va_end (ap); - msize = count * sizeof (struct PreferenceInformation) + - sizeof (struct ChangePreferenceMessage); - p = GNUNET_malloc (sizeof (struct PendingMessage) + - msize); + va_end(ap); + msize = count * sizeof(struct PreferenceInformation) + + sizeof(struct ChangePreferenceMessage); + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); p->size = msize; p->is_init = GNUNET_NO; - m = (struct ChangePreferenceMessage*) &p[1]; - m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); + m = (struct ChangePreferenceMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE); m->header.size = htons (msize); m->num_preferences = htonl (count); m->peer = *peer; - pi = (struct PreferenceInformation*) &m[1]; + pi = (struct PreferenceInformation *) &m[1]; count = 0; - va_start (ap, peer); - while (GNUNET_ATS_PREFERENCE_END != (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) + va_start(ap, peer); + while (GNUNET_ATS_PREFERENCE_END != (kind = + va_arg (ap, enum GNUNET_ATS_PreferenceKind) )) { pi[count].preference_kind = htonl (kind); switch (kind) { case GNUNET_ATS_PREFERENCE_BANDWIDTH: pi[count].preference_value = (float) va_arg (ap, double); + count++; break; case GNUNET_ATS_PREFERENCE_LATENCY: pi[count].preference_value = (float) va_arg (ap, double); + count++; break; default: - GNUNET_assert (0); + GNUNET_assert(0); } } - va_end (ap); - GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, - ph->pending_tail, - p); + va_end(ap); + GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p); + do_transmit (ph); } -/* end of ats_api_performance.c */ +/** + * Send feedback to ATS on how good a the requirements for a peer and a + * preference is satisfied by ATS + * + * @param ph performance handle + * @param scope the time interval this valid for: [now - scope .. now] + * @param peer identifies the peer + * @param ... 0-terminated specification of the desired changes + */ +void +GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_TIME_Relative scope, ...) +{ + struct PendingMessage *p; + struct FeedbackPreferenceMessage *m; + size_t msize; + uint32_t count; + struct PreferenceInformation *pi; + va_list ap; + enum GNUNET_ATS_PreferenceKind kind; + + count = 0; + va_start(ap, scope); + while (GNUNET_ATS_PREFERENCE_END != (kind = + va_arg (ap, enum GNUNET_ATS_PreferenceKind) )) + { + switch (kind) + { + case GNUNET_ATS_PREFERENCE_BANDWIDTH: + count++; + (void) va_arg (ap, double); + + break; + case GNUNET_ATS_PREFERENCE_LATENCY: + count++; + (void) va_arg (ap, double); + break; + default: + GNUNET_assert(0); + } + } + va_end(ap); + msize = count * sizeof(struct PreferenceInformation) + + sizeof(struct FeedbackPreferenceMessage); + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + p->size = msize; + p->is_init = GNUNET_NO; + m = (struct FeedbackPreferenceMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK); + m->header.size = htons (msize); + m->scope = GNUNET_TIME_relative_hton (scope); + m->num_feedback = htonl (count); + m->peer = *peer; + pi = (struct PreferenceInformation *) &m[1]; + count = 0; + va_start(ap, scope); + while (GNUNET_ATS_PREFERENCE_END != (kind = + va_arg (ap, enum GNUNET_ATS_PreferenceKind) )) + { + pi[count].preference_kind = htonl (kind); + switch (kind) + { + case GNUNET_ATS_PREFERENCE_BANDWIDTH: + pi[count].preference_value = (float) va_arg (ap, double); + + count++; + break; + case GNUNET_ATS_PREFERENCE_LATENCY: + pi[count].preference_value = (float) va_arg (ap, double); + + count++; + break; + default: + GNUNET_assert(0); + } + } + va_end(ap); + GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p); + do_transmit (ph); +} + +/* end of ats_api_performance.c */