aboutsummaryrefslogtreecommitdiff
path: root/src/ats/ats_api2_application.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats/ats_api2_application.c')
-rw-r--r--src/ats/ats_api2_application.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/src/ats/ats_api2_application.c b/src/ats/ats_api2_application.c
new file mode 100644
index 000000000..37198392c
--- /dev/null
+++ b/src/ats/ats_api2_application.c
@@ -0,0 +1,363 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016 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/**
19 * @file ats/ats_api2_application.c
20 * @brief enable clients to ask ATS about establishing connections to peers
21 * @author Christian Grothoff
22 * @author Matthias Wachs
23 */
24#include "platform.h"
25#include "gnunet_ats_application_service.h"
26#include "ats2.h"
27
28
29#define LOG(kind,...) GNUNET_log_from(kind, "ats-application-api", __VA_ARGS__)
30
31
32/**
33 * Handle for ATS address suggestion requests.
34 */
35struct GNUNET_ATS_ApplicationSuggestHandle
36{
37 /**
38 * ID of the peer for which address suggestion was requested.
39 */
40 struct GNUNET_PeerIdentity id;
41
42 /**
43 * Connecitivity handle this suggestion handle belongs to.
44 */
45 struct GNUNET_ATS_ApplicationHandle *ch;
46
47 /**
48 * What preference is being expressed?
49 */
50 enum GNUNET_MQ_PreferenceKind pk;
51
52 /**
53 * How much bandwidth does the client expect?
54 */
55 struct GNUNET_BANDWIDTH_Value32NBO bw;
56};
57
58
59/**
60 * Handle to the ATS subsystem for application management.
61 */
62struct GNUNET_ATS_ApplicationHandle
63{
64
65 /**
66 * Our configuration.
67 */
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70 /**
71 * Map with the identities of all the peers for which we would
72 * like to have address suggestions. The key is the PID, the
73 * value is currently the `struct GNUNET_ATS_ApplicationSuggestHandle`
74 */
75 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
76
77 /**
78 * Message queue for sending requests to the ATS service.
79 */
80 struct GNUNET_MQ_Handle *mq;
81
82 /**
83 * Task to trigger reconnect.
84 */
85 struct GNUNET_SCHEDULER_Task *task;
86
87 /**
88 * Reconnect backoff delay.
89 */
90 struct GNUNET_TIME_Relative backoff;
91};
92
93
94/**
95 * Re-establish the connection to the ATS service.
96 *
97 * @param ch handle to use to re-connect.
98 */
99static void
100reconnect (struct GNUNET_ATS_ApplicationHandle *ch);
101
102
103/**
104 * Re-establish the connection to the ATS service.
105 *
106 * @param cls handle to use to re-connect.
107 */
108static void
109reconnect_task (void *cls)
110{
111 struct GNUNET_ATS_ApplicationHandle *ch = cls;
112
113 ch->task = NULL;
114 reconnect (ch);
115}
116
117
118/**
119 * Disconnect from ATS and then reconnect.
120 *
121 * @param ch our handle
122 */
123static void
124force_reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
125{
126 if (NULL != ch->mq)
127 {
128 GNUNET_MQ_destroy (ch->mq);
129 ch->mq = NULL;
130 }
131 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
132 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff,
133 &reconnect_task,
134 ch);
135}
136
137
138/**
139 * We encountered an error handling the MQ to the
140 * ATS service. Reconnect.
141 *
142 * @param cls the `struct GNUNET_ATS_ApplicationHandle`
143 * @param error details about the error
144 */
145static void
146error_handler (void *cls,
147 enum GNUNET_MQ_Error error)
148{
149 struct GNUNET_ATS_ApplicationHandle *ch = cls;
150
151 LOG (GNUNET_ERROR_TYPE_DEBUG,
152 "ATS connection died (code %d), reconnecting\n",
153 (int) error);
154 force_reconnect (ch);
155}
156
157
158/**
159 * Transmit request for an address suggestion.
160 *
161 * @param cls the `struct GNUNET_ATS_ApplicationHandle`
162 * @param peer peer to ask for an address suggestion for
163 * @param value the `struct GNUNET_ATS_SuggestHandle`
164 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
165 * failure (message queue no longer exists)
166 */
167static int
168transmit_suggestion (void *cls,
169 const struct GNUNET_PeerIdentity *peer,
170 void *value)
171{
172 struct GNUNET_ATS_ApplicationHandle *ch = cls;
173 struct GNUNET_ATS_ApplicationSuggestHandle *sh = value;
174 struct GNUNET_MQ_Envelope *ev;
175 struct ExpressPreferenceMessage *m;
176
177 if (NULL == ch->mq)
178 return GNUNET_SYSERR;
179 ev = GNUNET_MQ_msg (m,
180 GNUNET_MESSAGE_TYPE_ATS_SUGGEST);
181 m->pk = htonl ((uint32_t) sh->pk);
182 m->bw = sh->bw;
183 m->peer = *peer;
184 GNUNET_MQ_send (ch->mq, ev);
185 return GNUNET_OK;
186}
187
188
189/**
190 * Re-establish the connection to the ATS service.
191 *
192 * @param ch handle to use to re-connect.
193 */
194static void
195reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
196{
197 static const struct GNUNET_MQ_MessageHandler handlers[] = {
198 { NULL, 0, 0 }
199 };
200
201 GNUNET_assert (NULL == ch->mq);
202 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
203 "ats",
204 handlers,
205 &error_handler,
206 ch);
207 if (NULL == ch->mq)
208 {
209 force_reconnect (ch);
210 return;
211 }
212 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
213 &transmit_suggestion,
214 ch);
215}
216
217
218/**
219 * Initialize the ATS application suggestion client handle.
220 *
221 * @param cfg configuration to use
222 * @return ats application handle, NULL on error
223 */
224struct GNUNET_ATS_ApplicationHandle *
225GNUNET_ATS_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
226{
227 struct GNUNET_ATS_ApplicationHandle *ch;
228
229 ch = GNUNET_new (struct GNUNET_ATS_ApplicationHandle);
230 ch->cfg = cfg;
231 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
232 GNUNET_YES);
233 reconnect (ch);
234 return ch;
235}
236
237
238/**
239 * Function called to free all `struct GNUNET_ATS_ApplicationSuggestHandle`s
240 * in the map.
241 *
242 * @param cls NULL
243 * @param key the key
244 * @param value the value to free
245 * @return #GNUNET_OK (continue to iterate)
246 */
247static int
248free_sug_handle (void *cls,
249 const struct GNUNET_PeerIdentity *key,
250 void *value)
251{
252 struct GNUNET_ATS_ApplicationSuggestHandle *cur = value;
253
254 GNUNET_free (cur);
255 return GNUNET_OK;
256}
257
258
259/**
260 * Client is done with ATS application management, release resources.
261 *
262 * @param ch handle to release
263 */
264void
265GNUNET_ATS_application_done (struct GNUNET_ATS_ApplicationHandle *ch)
266{
267 if (NULL != ch->mq)
268 {
269 GNUNET_MQ_destroy (ch->mq);
270 ch->mq = NULL;
271 }
272 if (NULL != ch->task)
273 {
274 GNUNET_SCHEDULER_cancel (ch->task);
275 ch->task = NULL;
276 }
277 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
278 &free_sug_handle,
279 NULL);
280 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
281 GNUNET_free (ch);
282}
283
284
285/**
286 * We would like to receive address suggestions for a peer. ATS will
287 * respond with a call to the continuation immediately containing an address or
288 * no address if none is available. ATS can suggest more addresses until we call
289 * #GNUNET_ATS_application_suggest_cancel().
290 *
291 * @param ch handle
292 * @param peer identity of the peer we need an address for
293 * @param pk what kind of application will the application require (can be
294 * #GNUNET_MQ_PREFERENCE_NONE, we will still try to connect)
295 * @param bw desired bandwith, can be zero (we will still try to connect)
296 * @return suggest handle, NULL if a request is already pending
297 */
298struct GNUNET_ATS_ApplicationSuggestHandle *
299GNUNET_ATS_application_suggest (struct GNUNET_ATS_ApplicationHandle *ch,
300 const struct GNUNET_PeerIdentity *peer,
301 enum GNUNET_MQ_PreferenceKind pk,
302 struct GNUNET_BANDWIDTH_Value32NBO bw)
303{
304 struct GNUNET_ATS_ApplicationSuggestHandle *s;
305
306 s = GNUNET_new (struct GNUNET_ATS_ApplicationSuggestHandle);
307 s->ch = ch;
308 s->id = *peer;
309 s->pk = pk;
310 s->bw = bw;
311 (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
312 &s->id,
313 s,
314 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
315 LOG (GNUNET_ERROR_TYPE_DEBUG,
316 "Requesting ATS to suggest address for `%s'\n",
317 GNUNET_i2s (peer));
318 if (NULL == ch->mq)
319 return s;
320 GNUNET_assert (GNUNET_OK ==
321 transmit_suggestion (ch,
322 &s->id,
323 s));
324 return s;
325}
326
327
328/**
329 * We no longer care about being connected to a peer.
330 *
331 * @param sh handle to stop
332 */
333void
334GNUNET_ATS_application_suggest_cancel (struct GNUNET_ATS_ApplicationSuggestHandle *sh)
335{
336 struct GNUNET_ATS_ApplicationHandle *ch = sh->ch;
337 struct GNUNET_MQ_Envelope *ev;
338 struct ExpressPreferenceMessage *m;
339
340 LOG (GNUNET_ERROR_TYPE_DEBUG,
341 "Telling ATS we no longer care for an address for `%s'\n",
342 GNUNET_i2s (&sh->id));
343 GNUNET_assert (GNUNET_OK ==
344 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests,
345 &sh->id,
346 sh));
347 if (NULL == ch->mq)
348 {
349 GNUNET_free (sh);
350 return;
351 }
352 ev = GNUNET_MQ_msg (m,
353 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL);
354 m->pk = htonl ((uint32_t) sh->pk);
355 m->bw = sh->bw;
356 m->peer = sh->id;
357 GNUNET_MQ_send (ch->mq,
358 ev);
359 GNUNET_free (sh);
360}
361
362
363/* end of ats_api2_application.c */