2 This file is part of GNUnet.
3 (C) 2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @file transport/gnunet-service-transport_ats.h
22 * @brief interfacing between transport and ATS service
23 * @author Christian Grothoff
26 #include "gnunet-service-transport.h"
27 #include "gnunet-service-transport_ats.h"
28 #include "gnunet-service-transport_manipulation.h"
29 #include "gnunet-service-transport_plugins.h"
30 #include "gnunet_ats_service.h"
34 * Information we track for each address known to ATS.
40 * The address (with peer identity).
42 struct GNUNET_HELLO_Address *address;
45 * Session (can be NULL)
47 struct Session *session;
50 * Record with ATS API for the address.
52 struct GNUNET_ATS_AddressRecord *ar;
57 * Map from peer identities to one or more `struct AddressInfo` values
60 static struct GNUNET_CONTAINER_MultiPeerMap *p2a;
64 * Closure for #find_ai().
70 * Session to look for (only used if the address is inbound).
72 struct Session *session;
75 * Address to look for.
77 const struct GNUNET_HELLO_Address *address;
80 * Where to store the result.
82 struct AddressInfo *ret;
88 * Find matching address info.
90 * @param cls the `struct FindClosure`
91 * @param key which peer is this about
92 * @param value the `struct AddressInfo`
93 * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
96 find_ai_cb (void *cls,
97 const struct GNUNET_PeerIdentity *key,
100 struct FindClosure *fc = cls;
101 struct AddressInfo *ai = value;
104 GNUNET_HELLO_address_cmp (fc->address,
106 (fc->session == ai->session) )
116 * Find the address information struct for the
117 * given address and session.
119 * @param address address to look for
120 * @param session session to match for inbound connections
121 * @return NULL if this combination is unknown
123 static struct AddressInfo *
124 find_ai (const struct GNUNET_HELLO_Address *address,
125 struct Session *session)
127 struct FindClosure fc;
129 fc.address = address;
130 fc.session = session;
132 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
141 * Notify ATS about the new address including the network this address is
144 * @param address the address
145 * @param session the session
146 * @param ats ats information
147 * @param ats_count number of @a ats information
150 GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
151 struct Session *session,
152 const struct GNUNET_ATS_Information *ats,
155 struct GNUNET_TRANSPORT_PluginFunctions *papi;
156 struct GNUNET_ATS_Information ats2[ats_count + 1];
157 struct GNUNET_ATS_AddressRecord *ar;
158 struct AddressInfo *ai;
161 /* valid new address, let ATS know! */
162 if (NULL == address->transport_name)
168 GNUNET_HELLO_address_check_option (address,
169 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
171 GNUNET_break (NULL != session);
175 GNUNET_break (NULL == session);
177 ai = find_ai (address, session);
183 if (NULL == (papi = GST_plugins_find (address->transport_name)))
185 /* we don't have the plugin for this address */
191 net = papi->get_network (papi->cls, session);
192 if (GNUNET_ATS_NET_UNSPECIFIED == net)
194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
195 _ ("Could not obtain a valid network for `%s' %s (%s)\n"),
196 GNUNET_i2s (&address->peer),
197 GST_plugins_a2s (address),
198 address->transport_name);
201 ats2[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
202 ats2[0].value = htonl (net);
205 sizeof(struct GNUNET_ATS_Information) * ats_count);
207 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208 "Notifying ATS about peer `%s''s new address `%s' session %p in network %s\n",
209 GNUNET_i2s (&address->peer),
210 (0 == address->address_length)
212 : GST_plugins_a2s (address),
214 GNUNET_ATS_print_network_type (net));
215 ar = GNUNET_ATS_address_add (GST_ats,
218 (NULL != session) ? ats2 : ats,
219 (NULL != session) ? ats_count + 1 : ats_count);
220 ai = GNUNET_new (struct AddressInfo);
221 ai->address = GNUNET_HELLO_address_copy (address);
222 ai->session = session;
224 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
227 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
232 * Notify ATS about a new session now existing for the given
235 * @param address the address
236 * @param session the session
239 GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
240 struct Session *session)
242 struct AddressInfo *ai;
244 ai = find_ai (address, NULL);
247 GNUNET_break (NULL != (find_ai (address, session)));
250 GNUNET_break (NULL == ai->session);
251 ai->session = session;
252 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
254 "Telling ATS about new session %p for peer %s\n",
256 GNUNET_i2s (&address->peer));
257 // FIXME: tell ATS API, but not using this call:
258 GNUNET_ATS_address_update (ai->ar,
266 * Notify ATS that the session (but not the address) of
267 * a given address is no longer relevant.
269 * @param address the address
270 * @param session the session
273 GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
274 struct Session *session)
276 struct AddressInfo *ai;
283 ai = find_ai (address, session);
286 /* We sometimes create sessions just for sending a PING,
287 and if those are destroyed they were never known to
288 ATS which means we end up here (however, in this
289 case, the address must be an outbound address). */
290 GNUNET_break (GNUNET_YES !=
291 GNUNET_HELLO_address_check_option (address,
292 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
296 GNUNET_assert (session == ai->session);
298 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
300 "Telling ATS to destroy session %p from peer %s\n",
302 GNUNET_i2s (&address->peer));
303 /* FIXME: if this was an *inbound* address, destroy it
304 FULLY here well; but use different API, as looking up
305 inbound address without session is not great... */
306 GNUNET_ATS_address_destroyed (GST_ats, address, session);
308 GNUNET_HELLO_address_check_option (address,
309 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
310 GST_ats_expire_address (address);
315 * Notify ATS about property changes to an address.
317 * @param address our information about the address
318 * @param session the session
319 * @param ats performance information
320 * @param ats_count number of elements in @a ats
323 GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address,
324 struct Session *session,
325 const struct GNUNET_ATS_Information *ats,
328 struct GNUNET_ATS_Information *ats_new;
329 struct AddressInfo *ai;
331 ai = find_ai (address, session);
334 /* We sometimes create sessions just for sending a PING,
335 and if we get metrics for those, they were never known to
336 ATS which means we end up here (however, in this
337 case, the address must be an outbound address). */
338 GNUNET_break (GNUNET_YES !=
339 GNUNET_HELLO_address_check_option (address,
340 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
344 /* Call to manipulation to manipulate ATS information */
345 GNUNET_assert (NULL != GST_ats);
346 if ((NULL == ats) || (0 == ats_count))
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349 "Updating metrics for peer `%s' address %s session %p\n",
350 GNUNET_i2s (&address->peer),
351 GST_plugins_a2s (address),
353 ats_new = GST_manipulation_manipulate_metrics (address,
357 GNUNET_ATS_address_update (ai->ar,
360 GNUNET_free_non_null (ats_new);
365 * Notify ATS that the address has expired and thus cannot
366 * be used any longer. This function must only be called
367 * if the corresponding session is already gone.
369 * @param address the address
372 GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
374 struct AddressInfo *ai;
376 ai = find_ai (address, NULL);
382 GNUNET_assert (GNUNET_YES ==
383 GNUNET_CONTAINER_multipeermap_remove (p2a,
386 GNUNET_break (NULL == ai->session);
387 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
389 "Telling ATS to destroy address from peer %s\n",
390 GNUNET_i2s (&address->peer));
391 GNUNET_ATS_address_destroyed (GST_ats, address, NULL);
392 GNUNET_HELLO_address_free (ai->address);
398 * Initialize ATS subsystem.
403 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
408 * Release memory used by the given address data.
411 * @param key which peer is this about
412 * @param value the `struct AddressInfo`
413 * @return #GNUNET_OK (continue to iterate)
416 destroy_ai (void *cls,
417 const struct GNUNET_PeerIdentity *key,
420 struct AddressInfo *ai = value;
422 GNUNET_HELLO_address_free (ai->address);
429 * Shutdown ATS subsystem.
434 GNUNET_CONTAINER_multipeermap_iterate (p2a,
437 GNUNET_CONTAINER_multipeermap_destroy (p2a);
441 /* end of gnunet-service-transport_ats.c */