2 This file is part of GNUnet.
3 Copyright (C) 2010-2016 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/>.
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
25 #include "gnunet_ats_application_service.h"
29 #define LOG(kind,...) GNUNET_log_from(kind, "ats-application-api", __VA_ARGS__)
33 * Handle for ATS address suggestion requests.
35 struct GNUNET_ATS_ApplicationSuggestHandle
38 * ID of the peer for which address suggestion was requested.
40 struct GNUNET_PeerIdentity id;
43 * Connecitivity handle this suggestion handle belongs to.
45 struct GNUNET_ATS_ApplicationHandle *ch;
48 * What preference is being expressed?
50 enum GNUNET_MQ_PreferenceKind pk;
53 * How much bandwidth does the client expect?
55 struct GNUNET_BANDWIDTH_Value32NBO bw;
60 * Handle to the ATS subsystem for application management.
62 struct GNUNET_ATS_ApplicationHandle
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
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`
75 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
78 * Message queue for sending requests to the ATS service.
80 struct GNUNET_MQ_Handle *mq;
83 * Task to trigger reconnect.
85 struct GNUNET_SCHEDULER_Task *task;
88 * Reconnect backoff delay.
90 struct GNUNET_TIME_Relative backoff;
95 * Re-establish the connection to the ATS service.
97 * @param ch handle to use to re-connect.
100 reconnect (struct GNUNET_ATS_ApplicationHandle *ch);
104 * Re-establish the connection to the ATS service.
106 * @param cls handle to use to re-connect.
109 reconnect_task (void *cls)
111 struct GNUNET_ATS_ApplicationHandle *ch = cls;
119 * Disconnect from ATS and then reconnect.
121 * @param ch our handle
124 force_reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
128 GNUNET_MQ_destroy (ch->mq);
131 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
132 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff,
139 * We encountered an error handling the MQ to the
140 * ATS service. Reconnect.
142 * @param cls the `struct GNUNET_ATS_ApplicationHandle`
143 * @param error details about the error
146 error_handler (void *cls,
147 enum GNUNET_MQ_Error error)
149 struct GNUNET_ATS_ApplicationHandle *ch = cls;
151 LOG (GNUNET_ERROR_TYPE_DEBUG,
152 "ATS connection died (code %d), reconnecting\n",
154 force_reconnect (ch);
159 * Transmit request for an address suggestion.
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)
168 transmit_suggestion (void *cls,
169 const struct GNUNET_PeerIdentity *peer,
172 struct GNUNET_ATS_ApplicationHandle *ch = cls;
173 struct GNUNET_ATS_ApplicationSuggestHandle *sh = value;
174 struct GNUNET_MQ_Envelope *ev;
175 struct ExpressPreferenceMessage *m;
178 return GNUNET_SYSERR;
179 ev = GNUNET_MQ_msg (m,
180 GNUNET_MESSAGE_TYPE_ATS_SUGGEST);
181 m->pk = htonl ((uint32_t) sh->pk);
184 GNUNET_MQ_send (ch->mq, ev);
190 * Re-establish the connection to the ATS service.
192 * @param ch handle to use to re-connect.
195 reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
197 static const struct GNUNET_MQ_MessageHandler handlers[] = {
201 GNUNET_assert (NULL == ch->mq);
202 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
209 force_reconnect (ch);
212 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
213 &transmit_suggestion,
219 * Initialize the ATS application suggestion client handle.
221 * @param cfg configuration to use
222 * @return ats application handle, NULL on error
224 struct GNUNET_ATS_ApplicationHandle *
225 GNUNET_ATS_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
227 struct GNUNET_ATS_ApplicationHandle *ch;
229 ch = GNUNET_new (struct GNUNET_ATS_ApplicationHandle);
231 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
239 * Function called to free all `struct GNUNET_ATS_ApplicationSuggestHandle`s
244 * @param value the value to free
245 * @return #GNUNET_OK (continue to iterate)
248 free_sug_handle (void *cls,
249 const struct GNUNET_PeerIdentity *key,
252 struct GNUNET_ATS_ApplicationSuggestHandle *cur = value;
260 * Client is done with ATS application management, release resources.
262 * @param ch handle to release
265 GNUNET_ATS_application_done (struct GNUNET_ATS_ApplicationHandle *ch)
269 GNUNET_MQ_destroy (ch->mq);
272 if (NULL != ch->task)
274 GNUNET_SCHEDULER_cancel (ch->task);
277 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
280 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
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().
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
298 struct GNUNET_ATS_ApplicationSuggestHandle *
299 GNUNET_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)
304 struct GNUNET_ATS_ApplicationSuggestHandle *s;
306 s = GNUNET_new (struct GNUNET_ATS_ApplicationSuggestHandle);
311 (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
314 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
315 LOG (GNUNET_ERROR_TYPE_DEBUG,
316 "Requesting ATS to suggest address for `%s'\n",
320 GNUNET_assert (GNUNET_OK ==
321 transmit_suggestion (ch,
329 * We no longer care about being connected to a peer.
331 * @param sh handle to stop
334 GNUNET_ATS_application_suggest_cancel (struct GNUNET_ATS_ApplicationSuggestHandle *sh)
336 struct GNUNET_ATS_ApplicationHandle *ch = sh->ch;
337 struct GNUNET_MQ_Envelope *ev;
338 struct ExpressPreferenceMessage *m;
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,
352 ev = GNUNET_MQ_msg (m,
353 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL);
354 m->pk = htonl ((uint32_t) sh->pk);
357 GNUNET_MQ_send (ch->mq,
363 /* end of ats_api2_application.c */