From 670ebb20b9570120df1021e467b575a212743125 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 3 Apr 2019 21:25:59 +0200 Subject: allow applications expressing connection preferences directly to TNG, collect HELLOs from PEERSTORE for expressed prefs --- src/transport/transport_api2_application.c | 366 +++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 src/transport/transport_api2_application.c (limited to 'src/transport/transport_api2_application.c') diff --git a/src/transport/transport_api2_application.c b/src/transport/transport_api2_application.c new file mode 100644 index 000000000..325438e11 --- /dev/null +++ b/src/transport/transport_api2_application.c @@ -0,0 +1,366 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010--2019 GNUnet e.V. + + 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 + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later +*/ +/** + * @file transport/transport_api2_application.c + * @brief enable clients to ask TRANSPORT about establishing connections to peers + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_transport_application_service.h" +#include "gnunet_transport_core_service.h" +#include "transport.h" + + +#define LOG(kind,...) GNUNET_log_from(kind, "transport-application-api", __VA_ARGS__) + + +/** + * Handle for TRANSPORT address suggestion requests. + */ +struct GNUNET_TRANSPORT_ApplicationSuggestHandle +{ + /** + * ID of the peer for which address suggestion was requested. + */ + struct GNUNET_PeerIdentity id; + + /** + * Connecitivity handle this suggestion handle belongs to. + */ + struct GNUNET_TRANSPORT_ApplicationHandle *ch; + + /** + * What preference is being expressed? + */ + enum GNUNET_MQ_PreferenceKind pk; + + /** + * How much bandwidth does the client expect? + */ + struct GNUNET_BANDWIDTH_Value32NBO bw; +}; + + +/** + * Handle to the TRANSPORT subsystem for application management. + */ +struct GNUNET_TRANSPORT_ApplicationHandle +{ + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * 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_TRANSPORT_ApplicationSuggestHandle` + */ + struct GNUNET_CONTAINER_MultiPeerMap *sug_requests; + + /** + * Message queue for sending requests to the TRANSPORT service. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Task to trigger reconnect. + */ + struct GNUNET_SCHEDULER_Task *task; + + /** + * Reconnect backoff delay. + */ + struct GNUNET_TIME_Relative backoff; +}; + + +/** + * Re-establish the connection to the TRANSPORT service. + * + * @param ch handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch); + + +/** + * Re-establish the connection to the TRANSPORT service. + * + * @param cls handle to use to re-connect. + */ +static void +reconnect_task (void *cls) +{ + struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls; + + ch->task = NULL; + reconnect (ch); +} + + +/** + * Disconnect from TRANSPORT and then reconnect. + * + * @param ch our handle + */ +static void +force_reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch) +{ + if (NULL != ch->mq) + { + GNUNET_MQ_destroy (ch->mq); + ch->mq = NULL; + } + ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff); + ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff, + &reconnect_task, + ch); +} + + +/** + * We encountered an error handling the MQ to the + * TRANSPORT service. Reconnect. + * + * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle` + * @param error details about the error + */ +static void +error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "TRANSPORT connection died (code %d), reconnecting\n", + (int) error); + force_reconnect (ch); +} + + +/** + * Transmit request for an address suggestion. + * + * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle` + * @param peer peer to ask for an address suggestion for + * @param value the `struct GNUNET_TRANSPORT_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_TRANSPORT_ApplicationHandle *ch = cls; + struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value; + struct GNUNET_MQ_Envelope *ev; + struct ExpressPreferenceMessage *m; + + if (NULL == ch->mq) + return GNUNET_SYSERR; + ev = GNUNET_MQ_msg (m, + GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST); + m->pk = htonl ((uint32_t) sh->pk); + m->bw = sh->bw; + m->peer = *peer; + GNUNET_MQ_send (ch->mq, ev); + return GNUNET_OK; +} + + +/** + * Re-establish the connection to the TRANSPORT service. + * + * @param ch handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch) +{ + static const struct GNUNET_MQ_MessageHandler handlers[] = { + { NULL, 0, 0 } + }; + + GNUNET_assert (NULL == ch->mq); + ch->mq = GNUNET_CLIENT_connect (ch->cfg, + "transport", + handlers, + &error_handler, + ch); + if (NULL == ch->mq) + { + force_reconnect (ch); + return; + } + GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests, + &transmit_suggestion, + ch); +} + + +/** + * Initialize the TRANSPORT application suggestion client handle. + * + * @param cfg configuration to use + * @return transport application handle, NULL on error + */ +struct GNUNET_TRANSPORT_ApplicationHandle * +GNUNET_TRANSPORT_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TRANSPORT_ApplicationHandle *ch; + + ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle); + ch->cfg = cfg; + ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, + GNUNET_YES); + reconnect (ch); + return ch; +} + + +/** + * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s + * 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_TRANSPORT_ApplicationSuggestHandle *cur = value; + + GNUNET_free (cur); + return GNUNET_OK; +} + + +/** + * Client is done with TRANSPORT application management, release resources. + * + * @param ch handle to release + */ +void +GNUNET_TRANSPORT_application_done (struct GNUNET_TRANSPORT_ApplicationHandle *ch) +{ + if (NULL != ch->mq) + { + GNUNET_MQ_destroy (ch->mq); + ch->mq = NULL; + } + if (NULL != ch->task) + { + GNUNET_SCHEDULER_cancel (ch->task); + ch->task = NULL; + } + GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests, + &free_sug_handle, + NULL); + GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests); + GNUNET_free (ch); +} + + +/** + * We would like to receive address suggestions for a peer. TRANSPORT will + * respond with a call to the continuation immediately containing an address or + * no address if none is available. TRANSPORT can suggest more addresses until we call + * #GNUNET_TRANSPORT_application_suggest_cancel(). + * + * @param ch handle + * @param peer identity of the peer we need an address for + * @param pk what kind of application will the application require (can be + * #GNUNET_MQ_PREFERENCE_NONE, we will still try to connect) + * @param bw desired bandwith, can be zero (we will still try to connect) + * @return suggest handle, NULL if a request is already pending + */ +struct GNUNET_TRANSPORT_ApplicationSuggestHandle * +GNUNET_TRANSPORT_application_suggest (struct GNUNET_TRANSPORT_ApplicationHandle *ch, + const struct GNUNET_PeerIdentity *peer, + enum GNUNET_MQ_PreferenceKind pk, + struct GNUNET_BANDWIDTH_Value32NBO bw) +{ + struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s; + + s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle); + s->ch = ch; + s->id = *peer; + s->pk = pk; + s->bw = bw; + (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests, + &s->id, + s, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Requesting TRANSPORT to suggest address for `%s'\n", + GNUNET_i2s (peer)); + if (NULL == ch->mq) + return s; + GNUNET_assert (GNUNET_OK == + transmit_suggestion (ch, + &s->id, + s)); + return s; +} + + +/** + * We no longer care about being connected to a peer. + * + * @param sh handle to stop + */ +void +GNUNET_TRANSPORT_application_suggest_cancel (struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh) +{ + struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch; + struct GNUNET_MQ_Envelope *ev; + struct ExpressPreferenceMessage *m; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Telling TRANSPORT we no longer care for an address for `%s'\n", + GNUNET_i2s (&sh->id)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests, + &sh->id, + sh)); + if (NULL == ch->mq) + { + GNUNET_free (sh); + return; + } + ev = GNUNET_MQ_msg (m, + GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL); + m->pk = htonl ((uint32_t) sh->pk); + m->bw = sh->bw; + m->peer = sh->id; + GNUNET_MQ_send (ch->mq, + ev); + GNUNET_free (sh); +} + + +/* end of transport_api2_application.c */ -- cgit v1.2.3