diff options
Diffstat (limited to 'src/ats/ats_api_performance.c')
-rw-r--r-- | src/ats/ats_api_performance.c | 294 |
1 files changed, 289 insertions, 5 deletions
diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c index c98e1c2..25b4926 100644 --- a/src/ats/ats_api_performance.c +++ b/src/ats/ats_api_performance.c @@ -106,6 +106,58 @@ struct GNUNET_ATS_ReservationContext /** + * 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_PeerInformationCallback 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 @@ -152,6 +204,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. */ struct GNUNET_CLIENT_TransmitHandle *th; @@ -161,6 +223,10 @@ struct GNUNET_ATS_PerformanceHandle */ GNUNET_SCHEDULER_TaskIdentifier task; + /** + * Request multiplexing + */ + uint32_t id; }; @@ -276,16 +342,12 @@ process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, uint16_t plugin_name_length; uint32_t ats_count; - if (ph->infocb == NULL) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } if (ntohs (msg->size) < sizeof (struct PeerInformationMessage)) { GNUNET_break (0); return GNUNET_SYSERR; } + pi = (const struct PeerInformationMessage *) msg; ats_count = ntohl (pi->ats_count); plugin_address_length = ntohs (pi->address_length); @@ -303,6 +365,11 @@ process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, GNUNET_break (0); return GNUNET_SYSERR; } + if (ph->infocb == NULL) + { + return GNUNET_OK; + } + address.peer = pi->peer; address.address = plugin_address; address.address_length = plugin_address_length; @@ -364,6 +431,110 @@ process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph, /** + * 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->infocb_cls, + NULL, + 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->infocb_cls, + &address, + pi->bandwidth_out, pi->bandwidth_in, + atsi, ats_count); + } + return GNUNET_OK; +} + + +/** * Type of a function to call when we receive a message * from the service. * @@ -387,6 +558,10 @@ process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) if (GNUNET_OK != process_rr_message (ph, msg)) 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); goto reconnect; @@ -395,6 +570,11 @@ process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) GNUNET_TIME_UNIT_FOREVER_REL); return; 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 = @@ -458,6 +638,7 @@ GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, ph->cfg = cfg; ph->infocb = infocb; ph->infocb_cls = infocb_cls; + ph->id = 0; reconnect (ph); return ph; } @@ -473,12 +654,19 @@ 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); } + 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, @@ -560,6 +748,102 @@ 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_PeerInformationCallback 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_malloc (sizeof (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 |