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,...) GNUNET_log_from(kind, "transport-application-api", __VA_ARGS__)
36 * Handle for TRANSPORT address suggestion requests.
38 struct GNUNET_TRANSPORT_ApplicationSuggestHandle
41 * ID of the peer for which address suggestion was requested.
43 struct GNUNET_PeerIdentity id;
46 * Connecitivity handle this suggestion handle belongs to.
48 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
51 * What preference is being expressed?
53 enum GNUNET_MQ_PreferenceKind pk;
56 * How much bandwidth does the client expect?
58 struct GNUNET_BANDWIDTH_Value32NBO bw;
63 * Handle to the TRANSPORT subsystem for application management.
65 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,
142 * We encountered an error handling the MQ to the
143 * TRANSPORT service. Reconnect.
145 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
146 * @param error details about the error
149 error_handler (void *cls,
150 enum GNUNET_MQ_Error error)
152 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
154 LOG (GNUNET_ERROR_TYPE_DEBUG,
155 "TRANSPORT connection died (code %d), reconnecting\n",
157 force_reconnect (ch);
162 * Transmit request for an address suggestion.
164 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
165 * @param peer peer to ask for an address suggestion for
166 * @param value the `struct GNUNET_TRANSPORT_SuggestHandle`
167 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
168 * failure (message queue no longer exists)
171 transmit_suggestion (void *cls,
172 const struct GNUNET_PeerIdentity *peer,
175 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
176 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value;
177 struct GNUNET_MQ_Envelope *ev;
178 struct ExpressPreferenceMessage *m;
181 return GNUNET_SYSERR;
182 ev = GNUNET_MQ_msg (m,
183 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST);
184 m->pk = htonl ((uint32_t) sh->pk);
187 GNUNET_MQ_send (ch->mq, ev);
193 * Re-establish the connection to the TRANSPORT service.
195 * @param ch handle to use to re-connect.
198 reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
200 static const struct GNUNET_MQ_MessageHandler handlers[] = {
204 GNUNET_assert (NULL == ch->mq);
205 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
212 force_reconnect (ch);
215 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
216 &transmit_suggestion,
222 * Initialize the TRANSPORT application suggestion client handle.
224 * @param cfg configuration to use
225 * @return transport application handle, NULL on error
227 struct GNUNET_TRANSPORT_ApplicationHandle *
228 GNUNET_TRANSPORT_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
230 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
232 ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle);
234 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
242 * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s
247 * @param value the value to free
248 * @return #GNUNET_OK (continue to iterate)
251 free_sug_handle (void *cls,
252 const struct GNUNET_PeerIdentity *key,
255 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *cur = value;
263 * Client is done with TRANSPORT application management, release resources.
265 * @param ch handle to release
268 GNUNET_TRANSPORT_application_done (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
272 GNUNET_MQ_destroy (ch->mq);
275 if (NULL != ch->task)
277 GNUNET_SCHEDULER_cancel (ch->task);
280 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
283 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
289 * We would like to receive address suggestions for a peer. TRANSPORT will
290 * respond with a call to the continuation immediately containing an address or
291 * no address if none is available. TRANSPORT can suggest more addresses until we call
292 * #GNUNET_TRANSPORT_application_suggest_cancel().
295 * @param peer identity of the peer we need an address for
296 * @param pk what kind of application will the application require (can be
297 * #GNUNET_MQ_PREFERENCE_NONE, we will still try to connect)
298 * @param bw desired bandwith, can be zero (we will still try to connect)
299 * @return suggest handle, NULL if a request is already pending
301 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *
302 GNUNET_TRANSPORT_application_suggest (struct GNUNET_TRANSPORT_ApplicationHandle *ch,
303 const struct GNUNET_PeerIdentity *peer,
304 enum GNUNET_MQ_PreferenceKind pk,
305 struct GNUNET_BANDWIDTH_Value32NBO bw)
307 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s;
309 s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle);
314 (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
317 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
318 LOG (GNUNET_ERROR_TYPE_DEBUG,
319 "Requesting TRANSPORT to suggest address for `%s'\n",
323 GNUNET_assert (GNUNET_OK ==
324 transmit_suggestion (ch,
332 * We no longer care about being connected to a peer.
334 * @param sh handle to stop
337 GNUNET_TRANSPORT_application_suggest_cancel (struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh)
339 struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch;
340 struct GNUNET_MQ_Envelope *ev;
341 struct ExpressPreferenceMessage *m;
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 "Telling TRANSPORT we no longer care for an address for `%s'\n",
345 GNUNET_i2s (&sh->id));
346 GNUNET_assert (GNUNET_OK ==
347 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests,
355 ev = GNUNET_MQ_msg (m,
356 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL);
357 m->pk = htonl ((uint32_t) sh->pk);
360 GNUNET_MQ_send (ch->mq,
368 * An application (or a communicator) has received a HELLO (or other address
369 * data of another peer) and wants TRANSPORT to validate that the address is
370 * correct. The result is NOT returned, in fact TRANSPORT may do nothing
371 * (i.e. if it has too many active validations or recently tried this one
372 * already). If the @a addr validates, TRANSPORT will persist the address
376 * @param peer identity of the peer we have an address for
377 * @param expiration when does @a addr expire; used by TRANSPORT to know when
378 * to definitively give up attempting to validate
379 * @param nt network type of @a addr (as claimed by the other peer);
380 * used by TRANSPORT to avoid trying @a addr's that really cannot work
381 * due to network type missmatches
382 * @param addr address to validate
385 GNUNET_TRANSPORT_application_validate (struct GNUNET_TRANSPORT_ApplicationHandle *ch,
386 const struct GNUNET_PeerIdentity *peer,
387 struct GNUNET_TIME_Absolute expiration,
388 enum GNUNET_NetworkType nt,
391 struct GNUNET_MQ_Envelope *ev;
392 struct RequestHelloValidationMessage *m;
397 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
398 "Address validation for %s:%s skipped as transport is not connected\n",
403 alen = strlen (addr) + 1;
404 ev = GNUNET_MQ_msg_extra (m,
406 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION);
408 m->expiration = GNUNET_TIME_absolute_hton (expiration);
409 m->nt = htonl ((uint32_t) nt);
413 GNUNET_MQ_send (ch->mq,
418 /* end of transport_api2_application.c */