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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file ats/ats_api_connectivity.c
22 * @brief enable clients to ask ATS about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
27 #include "gnunet_ats_service.h"
31 #define LOG(kind, ...) GNUNET_log_from(kind, "ats-connectivity-api", __VA_ARGS__)
35 * Handle for ATS address suggestion requests.
37 struct GNUNET_ATS_ConnectivitySuggestHandle {
39 * ID of the peer for which address suggestion was requested.
41 struct GNUNET_PeerIdentity id;
44 * Connecitivity handle this suggestion handle belongs to.
46 struct GNUNET_ATS_ConnectivityHandle *ch;
49 * How urgent is the request.
56 * Handle to the ATS subsystem for connectivity management.
58 struct GNUNET_ATS_ConnectivityHandle {
62 const struct GNUNET_CONFIGURATION_Handle *cfg;
65 * Map with the identities of all the peers for which we would
66 * like to have address suggestions. The key is the PID, the
67 * value is currently the `struct GNUNET_ATS_ConnectivitySuggestHandle`
69 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
72 * Message queue for sending requests to the ATS service.
74 struct GNUNET_MQ_Handle *mq;
77 * Task to trigger reconnect.
79 struct GNUNET_SCHEDULER_Task *task;
82 * Reconnect backoff delay.
84 struct GNUNET_TIME_Relative backoff;
89 * Re-establish the connection to the ATS service.
91 * @param ch handle to use to re-connect.
94 reconnect(struct GNUNET_ATS_ConnectivityHandle *ch);
98 * Re-establish the connection to the ATS service.
100 * @param cls handle to use to re-connect.
103 reconnect_task(void *cls)
105 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
113 * Disconnect from ATS and then reconnect.
115 * @param ch our handle
118 force_reconnect(struct GNUNET_ATS_ConnectivityHandle *ch)
122 GNUNET_MQ_destroy(ch->mq);
125 ch->backoff = GNUNET_TIME_STD_BACKOFF(ch->backoff);
126 ch->task = GNUNET_SCHEDULER_add_delayed(ch->backoff,
133 * We encountered an error handling the MQ to the
134 * ATS service. Reconnect.
136 * @param cls the `struct GNUNET_ATS_ConnectivityHandle`
137 * @param error details about the error
140 error_handler(void *cls,
141 enum GNUNET_MQ_Error error)
143 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
145 LOG(GNUNET_ERROR_TYPE_DEBUG,
146 "ATS connection died (code %d), reconnecting\n",
153 * Transmit request for an address suggestion.
155 * @param cls the `struct GNUNET_ATS_ConnectivityHandle`
156 * @param peer peer to ask for an address suggestion for
157 * @param value the `struct GNUNET_ATS_SuggestHandle`
158 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
159 * failure (message queue no longer exists)
162 transmit_suggestion(void *cls,
163 const struct GNUNET_PeerIdentity *peer,
166 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
167 struct GNUNET_ATS_ConnectivitySuggestHandle *sh = value;
168 struct GNUNET_MQ_Envelope *ev;
169 struct RequestAddressMessage *m;
172 return GNUNET_SYSERR;
173 ev = GNUNET_MQ_msg(m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
174 m->strength = htonl(sh->strength);
176 GNUNET_MQ_send(ch->mq, ev);
182 * Re-establish the connection to the ATS service.
184 * @param ch handle to use to re-connect.
187 reconnect(struct GNUNET_ATS_ConnectivityHandle *ch)
189 static const struct GNUNET_MQ_MessageHandler handlers[] =
191 struct GNUNET_MQ_Envelope *ev;
192 struct ClientStartMessage *init;
194 GNUNET_assert(NULL == ch->mq);
195 ch->mq = GNUNET_CLIENT_connect(ch->cfg,
205 ev = GNUNET_MQ_msg(init,
206 GNUNET_MESSAGE_TYPE_ATS_START);
207 init->start_flag = htonl(START_FLAG_CONNECTION_SUGGESTION);
208 GNUNET_MQ_send(ch->mq, ev);
211 GNUNET_CONTAINER_multipeermap_iterate(ch->sug_requests,
212 &transmit_suggestion,
218 * Initialize the ATS connectivity suggestion client handle.
220 * @param cfg configuration to use
221 * @return ats connectivity handle, NULL on error
223 struct GNUNET_ATS_ConnectivityHandle *
224 GNUNET_ATS_connectivity_init(const struct GNUNET_CONFIGURATION_Handle *cfg)
226 struct GNUNET_ATS_ConnectivityHandle *ch;
228 ch = GNUNET_new(struct GNUNET_ATS_ConnectivityHandle);
230 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create(32,
238 * Function called to free all `struct GNUNET_ATS_ConnectivitySuggestHandle`s
243 * @param value the value to free
244 * @return #GNUNET_OK (continue to iterate)
247 free_sug_handle(void *cls,
248 const struct GNUNET_PeerIdentity *key,
251 struct GNUNET_ATS_ConnectivitySuggestHandle *cur = value;
259 * Client is done with ATS connectivity management, release resources.
261 * @param ch handle to release
264 GNUNET_ATS_connectivity_done(struct GNUNET_ATS_ConnectivityHandle *ch)
268 GNUNET_MQ_destroy(ch->mq);
271 if (NULL != ch->task)
273 GNUNET_SCHEDULER_cancel(ch->task);
276 GNUNET_CONTAINER_multipeermap_iterate(ch->sug_requests,
279 GNUNET_CONTAINER_multipeermap_destroy(ch->sug_requests);
285 * We would like to receive address suggestions for a peer. ATS will
286 * respond with a call to the continuation immediately containing an address or
287 * no address if none is available. ATS can suggest more addresses until we call
288 * #GNUNET_ATS_connectivity_suggest_cancel().
291 * @param peer identity of the peer we need an address for
292 * @param strength how urgent is the need for such a suggestion
293 * @return suggest handle, NULL if a request is already pending
295 struct GNUNET_ATS_ConnectivitySuggestHandle *
296 GNUNET_ATS_connectivity_suggest(struct GNUNET_ATS_ConnectivityHandle *ch,
297 const struct GNUNET_PeerIdentity *peer,
300 struct GNUNET_ATS_ConnectivitySuggestHandle *s;
302 s = GNUNET_new(struct GNUNET_ATS_ConnectivitySuggestHandle);
305 s->strength = strength;
307 GNUNET_CONTAINER_multipeermap_put(ch->sug_requests,
310 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
312 LOG(GNUNET_ERROR_TYPE_DEBUG,
313 "Not requesting ATS to suggest address for `%s', request already pending\n",
318 LOG(GNUNET_ERROR_TYPE_DEBUG,
319 "Requesting ATS to suggest address for `%s'\n",
323 (void)transmit_suggestion(ch,
331 * We no longer care about being connected to a peer.
333 * @param sh handle to stop
336 GNUNET_ATS_connectivity_suggest_cancel(struct GNUNET_ATS_ConnectivitySuggestHandle *sh)
338 struct GNUNET_ATS_ConnectivityHandle *ch = sh->ch;
339 struct GNUNET_MQ_Envelope *ev;
340 struct RequestAddressMessage *m;
342 LOG(GNUNET_ERROR_TYPE_DEBUG,
343 "Telling ATS we no longer care for an address for `%s'\n",
344 GNUNET_i2s(&sh->id));
345 GNUNET_assert(GNUNET_OK ==
346 GNUNET_CONTAINER_multipeermap_remove(ch->sug_requests,
354 ev = GNUNET_MQ_msg(m,
355 GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
356 m->strength = htonl(0);
358 GNUNET_MQ_send(ch->mq, ev);
363 /* end of ats_api_connectivity.c */