aboutsummaryrefslogtreecommitdiff
path: root/src/transport/transport_api2_application.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/transport_api2_application.c')
-rw-r--r--src/transport/transport_api2_application.c366
1 files changed, 366 insertions, 0 deletions
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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010--2019 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20/**
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
25 */
26#include "platform.h"
27#include "gnunet_transport_application_service.h"
28#include "gnunet_transport_core_service.h"
29#include "transport.h"
30
31
32#define LOG(kind,...) GNUNET_log_from(kind, "transport-application-api", __VA_ARGS__)
33
34
35/**
36 * Handle for TRANSPORT address suggestion requests.
37 */
38struct GNUNET_TRANSPORT_ApplicationSuggestHandle
39{
40 /**
41 * ID of the peer for which address suggestion was requested.
42 */
43 struct GNUNET_PeerIdentity id;
44
45 /**
46 * Connecitivity handle this suggestion handle belongs to.
47 */
48 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
49
50 /**
51 * What preference is being expressed?
52 */
53 enum GNUNET_MQ_PreferenceKind pk;
54
55 /**
56 * How much bandwidth does the client expect?
57 */
58 struct GNUNET_BANDWIDTH_Value32NBO bw;
59};
60
61
62/**
63 * Handle to the TRANSPORT subsystem for application management.
64 */
65struct GNUNET_TRANSPORT_ApplicationHandle
66{
67
68 /**
69 * Our configuration.
70 */
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
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`
77 */
78 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
79
80 /**
81 * Message queue for sending requests to the TRANSPORT service.
82 */
83 struct GNUNET_MQ_Handle *mq;
84
85 /**
86 * Task to trigger reconnect.
87 */
88 struct GNUNET_SCHEDULER_Task *task;
89
90 /**
91 * Reconnect backoff delay.
92 */
93 struct GNUNET_TIME_Relative backoff;
94};
95
96
97/**
98 * Re-establish the connection to the TRANSPORT service.
99 *
100 * @param ch handle to use to re-connect.
101 */
102static void
103reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch);
104
105
106/**
107 * Re-establish the connection to the TRANSPORT service.
108 *
109 * @param cls handle to use to re-connect.
110 */
111static void
112reconnect_task (void *cls)
113{
114 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
115
116 ch->task = NULL;
117 reconnect (ch);
118}
119
120
121/**
122 * Disconnect from TRANSPORT and then reconnect.
123 *
124 * @param ch our handle
125 */
126static void
127force_reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
128{
129 if (NULL != ch->mq)
130 {
131 GNUNET_MQ_destroy (ch->mq);
132 ch->mq = NULL;
133 }
134 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
135 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff,
136 &reconnect_task,
137 ch);
138}
139
140
141/**
142 * We encountered an error handling the MQ to the
143 * TRANSPORT service. Reconnect.
144 *
145 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
146 * @param error details about the error
147 */
148static void
149error_handler (void *cls,
150 enum GNUNET_MQ_Error error)
151{
152 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
153
154 LOG (GNUNET_ERROR_TYPE_DEBUG,
155 "TRANSPORT connection died (code %d), reconnecting\n",
156 (int) error);
157 force_reconnect (ch);
158}
159
160
161/**
162 * Transmit request for an address suggestion.
163 *
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)
169 */
170static int
171transmit_suggestion (void *cls,
172 const struct GNUNET_PeerIdentity *peer,
173 void *value)
174{
175 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
176 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value;
177 struct GNUNET_MQ_Envelope *ev;
178 struct ExpressPreferenceMessage *m;
179
180 if (NULL == ch->mq)
181 return GNUNET_SYSERR;
182 ev = GNUNET_MQ_msg (m,
183 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST);
184 m->pk = htonl ((uint32_t) sh->pk);
185 m->bw = sh->bw;
186 m->peer = *peer;
187 GNUNET_MQ_send (ch->mq, ev);
188 return GNUNET_OK;
189}
190
191
192/**
193 * Re-establish the connection to the TRANSPORT service.
194 *
195 * @param ch handle to use to re-connect.
196 */
197static void
198reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
199{
200 static const struct GNUNET_MQ_MessageHandler handlers[] = {
201 { NULL, 0, 0 }
202 };
203
204 GNUNET_assert (NULL == ch->mq);
205 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
206 "transport",
207 handlers,
208 &error_handler,
209 ch);
210 if (NULL == ch->mq)
211 {
212 force_reconnect (ch);
213 return;
214 }
215 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
216 &transmit_suggestion,
217 ch);
218}
219
220
221/**
222 * Initialize the TRANSPORT application suggestion client handle.
223 *
224 * @param cfg configuration to use
225 * @return transport application handle, NULL on error
226 */
227struct GNUNET_TRANSPORT_ApplicationHandle *
228GNUNET_TRANSPORT_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
229{
230 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
231
232 ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle);
233 ch->cfg = cfg;
234 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
235 GNUNET_YES);
236 reconnect (ch);
237 return ch;
238}
239
240
241/**
242 * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s
243 * in the map.
244 *
245 * @param cls NULL
246 * @param key the key
247 * @param value the value to free
248 * @return #GNUNET_OK (continue to iterate)
249 */
250static int
251free_sug_handle (void *cls,
252 const struct GNUNET_PeerIdentity *key,
253 void *value)
254{
255 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *cur = value;
256
257 GNUNET_free (cur);
258 return GNUNET_OK;
259}
260
261
262/**
263 * Client is done with TRANSPORT application management, release resources.
264 *
265 * @param ch handle to release
266 */
267void
268GNUNET_TRANSPORT_application_done (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
269{
270 if (NULL != ch->mq)
271 {
272 GNUNET_MQ_destroy (ch->mq);
273 ch->mq = NULL;
274 }
275 if (NULL != ch->task)
276 {
277 GNUNET_SCHEDULER_cancel (ch->task);
278 ch->task = NULL;
279 }
280 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
281 &free_sug_handle,
282 NULL);
283 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
284 GNUNET_free (ch);
285}
286
287
288/**
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().
293 *
294 * @param ch handle
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
300 */
301struct GNUNET_TRANSPORT_ApplicationSuggestHandle *
302GNUNET_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)
306{
307 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s;
308
309 s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle);
310 s->ch = ch;
311 s->id = *peer;
312 s->pk = pk;
313 s->bw = bw;
314 (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
315 &s->id,
316 s,
317 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
318 LOG (GNUNET_ERROR_TYPE_DEBUG,
319 "Requesting TRANSPORT to suggest address for `%s'\n",
320 GNUNET_i2s (peer));
321 if (NULL == ch->mq)
322 return s;
323 GNUNET_assert (GNUNET_OK ==
324 transmit_suggestion (ch,
325 &s->id,
326 s));
327 return s;
328}
329
330
331/**
332 * We no longer care about being connected to a peer.
333 *
334 * @param sh handle to stop
335 */
336void
337GNUNET_TRANSPORT_application_suggest_cancel (struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh)
338{
339 struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch;
340 struct GNUNET_MQ_Envelope *ev;
341 struct ExpressPreferenceMessage *m;
342
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,
348 &sh->id,
349 sh));
350 if (NULL == ch->mq)
351 {
352 GNUNET_free (sh);
353 return;
354 }
355 ev = GNUNET_MQ_msg (m,
356 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL);
357 m->pk = htonl ((uint32_t) sh->pk);
358 m->bw = sh->bw;
359 m->peer = sh->id;
360 GNUNET_MQ_send (ch->mq,
361 ev);
362 GNUNET_free (sh);
363}
364
365
366/* end of transport_api2_application.c */