X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Ftransport_api_address_lookup.c;h=655be833f239c83ff89038cf3466ea0296aadcbf;hb=56389a7d277b05c9c2968b7ebd529a12f8be15eb;hp=385abd423f3754f923bee5d39bc25e85bfca3251;hpb=ba232c9d203303cd2beb2994fc49c5d5b700d85c;p=oweals%2Fgnunet.git diff --git a/src/transport/transport_api_address_lookup.c b/src/transport/transport_api_address_lookup.c index 385abd423..655be833f 100644 --- a/src/transport/transport_api_address_lookup.c +++ b/src/transport/transport_api_address_lookup.c @@ -19,7 +19,7 @@ */ /** - * @file transport/transport_api_peer_address_lookup.c + * @file transport/transport_api_address_lookup.c * @brief given a peer id, get all known addresses from transport service * * This api provides the ability to query the transport service about @@ -42,12 +42,12 @@ /** * Context for the address lookup. */ -struct GNUNET_TRANSPORT_PeerAddressLookupContext +struct GNUNET_TRANSPORT_PeerIterateContext { /** - * Function to call with the human-readable address. + * Function to call with the binary address. */ - GNUNET_TRANSPORT_AddressLookUpCallback cb; + GNUNET_TRANSPORT_PeerIterateCallback cb; /** * Closure for cb. @@ -59,10 +59,35 @@ struct GNUNET_TRANSPORT_PeerAddressLookupContext */ struct GNUNET_CLIENT_Connection *client; + /** + * Configuration we use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + /** * When should this operation time out? */ struct GNUNET_TIME_Absolute timeout; + + /** + * Backoff for reconnect. + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Task ID for reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Identity of the peer to monitor. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Was this a one-shot request? + */ + int one_shot; }; @@ -75,207 +100,270 @@ struct GNUNET_TRANSPORT_PeerAddressLookupContext */ static void peer_address_response_processor (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_TRANSPORT_PeerAddressLookupContext *alucb = cls; - const struct GNUNET_HELLO_Address *address; - uint16_t size; - - if (msg == NULL) - { - alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); - return; - } - GNUNET_break (ntohs (msg->type) == - GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); - size = ntohs (msg->size); - if (size == sizeof (struct GNUNET_MessageHeader)) - { - /* done! */ - alucb->cb (alucb->cb_cls, NULL ); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); - return; - } - address = (const struct GNUNET_HELLO_Address *) &msg[1]; -#if 0 - if (address[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') - { - /* invalid reply */ - GNUNET_break (0); - alucb->cb (alucb->cb_cls, NULL ); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); - return; - } -#endif - /* expect more replies */ - GNUNET_CLIENT_receive (alucb->client, &peer_address_response_processor, alucb, - GNUNET_TIME_absolute_get_remaining (alucb->timeout)); - - /* REFACTOR FIX THIS */ - alucb->cb (alucb->cb_cls, address ); -} + const struct GNUNET_MessageHeader *msg); /** - * Return all the known addresses for a peer. + * Send our subscription request to the service. * - * @param cfg configuration to use - * @param peer peer identity to look up the addresses of - * @param timeout how long is the lookup allowed to take at most - * @param peer_address_callback function to call with the results - * @param peer_address_callback_cls closure for peer_address_callback - * @return handle to cancel the operation, NULL on error + * @param pal_ctx our context */ -struct GNUNET_TRANSPORT_PeerAddressLookupContext * -GNUNET_TRANSPORT_peer_get_active_addresses (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PeerIdentity *peer, - int one_shot, - struct GNUNET_TIME_Relative timeout, - GNUNET_TRANSPORT_AddressLookUpCallback peer_address_callback, - void *peer_address_callback_cls) +static void +send_request (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) { - struct PeerAddressLookupMessage msg; - struct GNUNET_TRANSPORT_PeerAddressLookupContext *alc; - struct GNUNET_CLIENT_Connection *client; + struct AddressIterateMessage msg; - client = GNUNET_CLIENT_connect ("transport", cfg); - if (client == NULL) - return NULL; - msg.header.size = htons (sizeof (struct PeerAddressLookupMessage)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP); - msg.reserved = htonl (0); - msg.timeout = GNUNET_TIME_relative_hton (timeout); - memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity)); - alc = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerAddressLookupContext)); - alc->cb = peer_address_callback; - alc->cb_cls = peer_address_callback_cls; - alc->timeout = GNUNET_TIME_relative_to_absolute (timeout); - alc->client = client; + msg.header.size = htons (sizeof (struct AddressIterateMessage)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE); + msg.one_shot = htonl (pal_ctx->one_shot); + msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout); + msg.peer = pal_ctx->peer; GNUNET_assert (GNUNET_OK == - GNUNET_CLIENT_transmit_and_get_response (client, &msg.header, - timeout, GNUNET_YES, + GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client, + &msg.header, + GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout), + GNUNET_YES, &peer_address_response_processor, - alc)); - return alc; + pal_ctx)); +} + +/** + * Task run to re-establish the connection. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' + * @param tc scheduler context, unused + */ +static void +do_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; + + pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg); + GNUNET_assert (NULL != pal_ctx->client); + send_request (pal_ctx); } /** - * Cancel request for address conversion. + * Cut the existing connection and reconnect. * - * @param alc handle for the request to cancel + * @param pal_ctx our context */ -void -GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct - GNUNET_TRANSPORT_PeerAddressLookupContext - *alc) +static void +reconnect (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) { - GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO); - GNUNET_free (alc); + GNUNET_assert (GNUNET_NO == pal_ctx->one_shot); + GNUNET_CLIENT_disconnect (pal_ctx->client); + pal_ctx->client = NULL; + pal_ctx->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, + GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (pal_ctx->backoff, 2), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); + pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff, + &do_connect, + pal_ctx); } + /** * Function called with responses from the service. * - * @param cls our 'struct AddressLookupCtx*' + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' * @param msg NULL on timeout or error, otherwise presumably a - * message with the human-readable peer and address + * message with the human-readable address */ static void -peer_address_iteration_response_processor (void *cls, +peer_address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) { - struct GNUNET_TRANSPORT_PeerAddressLookupContext *alucb = cls; - struct AddressIterateResponseMessage *arm; - struct GNUNET_HELLO_Address * address; + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; + struct AddressIterateResponseMessage *air_msg; + struct GNUNET_HELLO_Address *address; + const char *addr; + const char *transport_name; uint16_t size; + size_t alen; + size_t tlen; if (msg == NULL) { - alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } return; } - - GNUNET_break (ntohs (msg->type) == - GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); size = ntohs (msg->size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message type %u size %u\n", - ntohs (msg->type), size); + GNUNET_break (ntohs (msg->type) == + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); if (size == sizeof (struct GNUNET_MessageHeader)) { /* done! */ - alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } return; } - if (size < sizeof (struct AddressIterateResponseMessage)) + + if ((size < sizeof (struct AddressIterateResponseMessage)) || + (ntohs (msg->type) != + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE)) { - /* invalid reply */ GNUNET_break (0); - alucb->cb (alucb->cb_cls, NULL); - GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); - GNUNET_free (alucb); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } return; } - arm = (struct AddressIterateResponseMessage *) &msg[1]; - address = (struct GNUNET_HELLO_Address *) &arm[1]; + air_msg = (struct AddressIterateResponseMessage *) msg; + tlen = ntohl (air_msg->pluginlen); + alen = ntohl (air_msg->addrlen); + + if (size != sizeof (struct AddressIterateResponseMessage) + tlen + alen) + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + if (alen == 0 && tlen == 0) + { + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL); + } + else + { + addr = (const char *) &air_msg[1]; + transport_name = &addr[alen]; + + if (transport_name[tlen - 1] != '\0') + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + /* notify client */ + address = + GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr, + alen); + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address); + GNUNET_HELLO_address_free (address); + } /* expect more replies */ - GNUNET_CLIENT_receive (alucb->client, &peer_address_response_processor, alucb, - GNUNET_TIME_absolute_get_remaining (alucb->timeout)); - alucb->cb (alucb->cb_cls, address); + GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor, + pal_ctx, + GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout)); } /** - * Return all the known addresses for a peer. + * Return all the known addresses for a specific peer or all peers. + * Returns continuously all address if one_shot is set to GNUNET_NO + * + * CHANGE: Returns the address(es) that we are currently using for this + * peer. Upon completion, the 'AddressLookUpCallback' is called one more + * time with 'NULL' for the address and the peer. After this, the operation must no + * longer be explicitly canceled. * * @param cfg configuration to use - * @param timeout how long is the lookup allowed to take at most + * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers + * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), + * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled) + * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO) * @param peer_address_callback function to call with the results * @param peer_address_callback_cls closure for peer_address_callback */ -void -GNUNET_TRANSPORT_address_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TIME_Relative timeout, - GNUNET_TRANSPORT_AddressLookUpCallback - peer_address_callback, - void *peer_address_callback_cls) +struct GNUNET_TRANSPORT_PeerIterateContext * +GNUNET_TRANSPORT_peer_get_active_addresses (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity + *peer, int one_shot, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_PeerIterateCallback + peer_address_callback, + void *peer_address_callback_cls) { - struct AddressIterateMessage msg; - struct GNUNET_TIME_Absolute abs_timeout; - struct GNUNET_TRANSPORT_PeerAddressLookupContext *peer_address_lookup_cb; + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx; struct GNUNET_CLIENT_Connection *client; client = GNUNET_CLIENT_connect ("transport", cfg); if (client == NULL) + return NULL; + if (GNUNET_YES != one_shot) + timeout = GNUNET_TIME_UNIT_FOREVER_REL; + pal_ctx = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerIterateContext)); + pal_ctx->cb = peer_address_callback; + pal_ctx->cb_cls = peer_address_callback_cls; + pal_ctx->cfg = cfg; + pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (NULL != peer) + pal_ctx->peer = *peer; + pal_ctx->one_shot = one_shot; + pal_ctx->client = client; + send_request (pal_ctx); + + return pal_ctx; +} + + +/** + * Cancel request for address conversion. + * + * @param alc handle for the request to cancel + */ +void +GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct + GNUNET_TRANSPORT_PeerIterateContext + *alc) +{ + if (NULL != alc->client) { - peer_address_callback (peer_address_callback_cls, NULL); - return; + GNUNET_CLIENT_disconnect (alc->client); + alc->client = NULL; } - abs_timeout = GNUNET_TIME_relative_to_absolute (timeout); - - msg.header.size = htons (sizeof (struct AddressIterateMessage)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE); - msg.timeout = GNUNET_TIME_absolute_hton (abs_timeout); - peer_address_lookup_cb = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerAddressLookupContext)); - peer_address_lookup_cb->cb = peer_address_callback; - peer_address_lookup_cb->cb_cls = peer_address_callback_cls; - peer_address_lookup_cb->timeout = abs_timeout; - peer_address_lookup_cb->client = client; - GNUNET_assert (GNUNET_OK == - GNUNET_CLIENT_transmit_and_get_response (client, &msg.header, - timeout, GNUNET_YES, - &peer_address_iteration_response_processor, - peer_address_lookup_cb)); + if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task) + { + GNUNET_SCHEDULER_cancel (alc->reconnect_task); + alc->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (alc); } + /* end of transport_api_peer_address_lookup.c */