2 This file is part of GNUnet.
3 Copyright (C) 2010--2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/transport_api2_application.c
22 * @brief enable clients to ask TRANSPORT about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
27 #include "gnunet_transport_application_service.h"
28 #include "gnunet_transport_core_service.h"
29 #include "transport.h"
32 #define LOG(kind, ...) \
33 GNUNET_log_from (kind, "transport-application-api", __VA_ARGS__)
37 * Handle for TRANSPORT address suggestion requests.
39 struct GNUNET_TRANSPORT_ApplicationSuggestHandle
42 * ID of the peer for which address suggestion was requested.
44 struct GNUNET_PeerIdentity id;
47 * Connecitivity handle this suggestion handle belongs to.
49 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
52 * What preference is being expressed?
54 enum GNUNET_MQ_PriorityPreferences pk;
57 * How much bandwidth does the client expect?
59 struct GNUNET_BANDWIDTH_Value32NBO bw;
64 * Handle to the TRANSPORT subsystem for application management.
66 struct GNUNET_TRANSPORT_ApplicationHandle
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
74 * Map with the identities of all the peers for which we would
75 * like to have address suggestions. The key is the PID, the
76 * value is currently the `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`
78 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
81 * Message queue for sending requests to the TRANSPORT service.
83 struct GNUNET_MQ_Handle *mq;
86 * Task to trigger reconnect.
88 struct GNUNET_SCHEDULER_Task *task;
91 * Reconnect backoff delay.
93 struct GNUNET_TIME_Relative backoff;
98 * Re-establish the connection to the TRANSPORT service.
100 * @param ch handle to use to re-connect.
103 reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch);
107 * Re-establish the connection to the TRANSPORT service.
109 * @param cls handle to use to re-connect.
112 reconnect_task (void *cls)
114 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
122 * Disconnect from TRANSPORT and then reconnect.
124 * @param ch our handle
127 force_reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
131 GNUNET_MQ_destroy (ch->mq);
134 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
135 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff, &reconnect_task, ch);
140 * We encountered an error handling the MQ to the
141 * TRANSPORT service. Reconnect.
143 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
144 * @param error details about the error
147 error_handler (void *cls, enum GNUNET_MQ_Error error)
149 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
151 LOG (GNUNET_ERROR_TYPE_DEBUG,
152 "TRANSPORT connection died (code %d), reconnecting\n",
154 force_reconnect (ch);
159 * Transmit request for an address suggestion.
161 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
162 * @param peer peer to ask for an address suggestion for
163 * @param value the `struct GNUNET_TRANSPORT_SuggestHandle`
164 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
165 * failure (message queue no longer exists)
168 transmit_suggestion (void *cls,
169 const struct GNUNET_PeerIdentity *peer,
172 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
173 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value;
174 struct GNUNET_MQ_Envelope *ev;
175 struct ExpressPreferenceMessage *m;
178 return GNUNET_SYSERR;
179 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST);
180 m->pk = htonl ((uint32_t) sh->pk);
183 GNUNET_MQ_send (ch->mq, ev);
189 * Re-establish the connection to the TRANSPORT service.
191 * @param ch handle to use to re-connect.
194 reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
196 static const struct GNUNET_MQ_MessageHandler handlers[] = { { NULL, 0, 0 } };
198 GNUNET_assert (NULL == ch->mq);
200 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
203 force_reconnect (ch);
206 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
207 &transmit_suggestion,
213 * Initialize the TRANSPORT application suggestion client handle.
215 * @param cfg configuration to use
216 * @return transport application handle, NULL on error
218 struct GNUNET_TRANSPORT_ApplicationHandle *
219 GNUNET_TRANSPORT_application_init (
220 const struct GNUNET_CONFIGURATION_Handle *cfg)
222 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
224 ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle);
226 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
233 * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s
238 * @param value the value to free
239 * @return #GNUNET_OK (continue to iterate)
242 free_sug_handle (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
244 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *cur = value;
252 * Client is done with TRANSPORT application management, release resources.
254 * @param ch handle to release
257 GNUNET_TRANSPORT_application_done (
258 struct GNUNET_TRANSPORT_ApplicationHandle *ch)
262 GNUNET_MQ_destroy (ch->mq);
265 if (NULL != ch->task)
267 GNUNET_SCHEDULER_cancel (ch->task);
270 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
273 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
279 * An application would like TRANSPORT to connect to a peer.
282 * @param peer identity of the peer we need an address for
283 * @param pk what kind of application will the application require (can be
284 * #GNUNET_MQ_PRIO_BACKGROUND, we will still try to connect)
285 * @param bw desired bandwith, can be zero (we will still try to connect)
286 * @return suggest handle, NULL if a request is already pending
288 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *
289 GNUNET_TRANSPORT_application_suggest (
290 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
291 const struct GNUNET_PeerIdentity *peer,
292 enum GNUNET_MQ_PriorityPreferences pk,
293 struct GNUNET_BANDWIDTH_Value32NBO bw)
295 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s;
297 s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle);
302 (void) GNUNET_CONTAINER_multipeermap_put (
306 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "Requesting TRANSPORT to suggest address for `%s'\n",
312 GNUNET_assert (GNUNET_OK == transmit_suggestion (ch, &s->id, s));
318 * We no longer care about being connected to a peer.
320 * @param sh handle to stop
323 GNUNET_TRANSPORT_application_suggest_cancel (
324 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh)
326 struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch;
327 struct GNUNET_MQ_Envelope *ev;
328 struct ExpressPreferenceMessage *m;
330 LOG (GNUNET_ERROR_TYPE_DEBUG,
331 "Telling TRANSPORT we no longer care for an address for `%s'\n",
332 GNUNET_i2s (&sh->id));
335 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests, &sh->id, sh));
341 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL);
342 m->pk = htonl ((uint32_t) sh->pk);
345 GNUNET_MQ_send (ch->mq, ev);
351 * An application (or a communicator) has received a HELLO (or other address
352 * data of another peer) and wants TRANSPORT to validate that the address is
353 * correct. The result is NOT returned, in fact TRANSPORT may do nothing
354 * (i.e. if it has too many active validations or recently tried this one
355 * already). If the @a addr validates, TRANSPORT will persist the address
359 * @param peer identity of the peer we have an address for
360 * @param nt network type of @a addr (as claimed by the other peer);
361 * used by TRANSPORT to avoid trying @a addr's that really cannot work
362 * due to network type missmatches
363 * @param addr address to validate
366 GNUNET_TRANSPORT_application_validate (
367 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
368 const struct GNUNET_PeerIdentity *peer,
369 enum GNUNET_NetworkType nt,
372 struct GNUNET_MQ_Envelope *ev;
373 struct RequestHelloValidationMessage *m;
379 GNUNET_ERROR_TYPE_WARNING,
380 "Address validation for %s:%s skipped as transport is not connected\n",
385 alen = strlen (addr) + 1;
387 GNUNET_MQ_msg_extra (m,
389 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION);
391 m->nt = htonl ((uint32_t) nt);
392 memcpy (&m[1], addr, alen);
393 GNUNET_MQ_send (ch->mq, ev);
397 /* end of transport_api2_application.c */