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 GNUNET_ATS_address_add_session (ai->ar,
263 * Notify ATS that the session (but not the address) of
264 * a given address is no longer relevant.
266 * @param address the address
267 * @param session the session
270 GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
271 struct Session *session)
273 struct AddressInfo *ai;
280 ai = find_ai (address, session);
283 /* We sometimes create sessions just for sending a PING,
284 and if those are destroyed they were never known to
285 ATS which means we end up here (however, in this
286 case, the address must be an outbound address). */
287 GNUNET_break (GNUNET_YES !=
288 GNUNET_HELLO_address_check_option (address,
289 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
293 GNUNET_assert (session == ai->session);
295 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
297 "Telling ATS to destroy session %p from peer %s\n",
299 GNUNET_i2s (&address->peer));
301 GNUNET_ATS_address_del_session (ai->ar, session))
304 GST_ats_expire_address (address);
310 * Notify ATS about property changes to an address.
312 * @param address our information about the address
313 * @param session the session
314 * @param ats performance information
315 * @param ats_count number of elements in @a ats
318 GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address,
319 struct Session *session,
320 const struct GNUNET_ATS_Information *ats,
323 struct GNUNET_ATS_Information *ats_new;
324 struct AddressInfo *ai;
326 ai = find_ai (address, session);
329 /* We sometimes create sessions just for sending a PING,
330 and if we get metrics for those, they were never known to
331 ATS which means we end up here (however, in this
332 case, the address must be an outbound address). */
333 GNUNET_break (GNUNET_YES !=
334 GNUNET_HELLO_address_check_option (address,
335 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
339 /* Call to manipulation to manipulate ATS information */
340 GNUNET_assert (NULL != GST_ats);
341 if ((NULL == ats) || (0 == ats_count))
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344 "Updating metrics for peer `%s' address %s session %p\n",
345 GNUNET_i2s (&address->peer),
346 GST_plugins_a2s (address),
348 ats_new = GST_manipulation_manipulate_metrics (address,
352 GNUNET_ATS_address_update (ai->ar,
354 GNUNET_free_non_null (ats_new);
359 * Notify ATS about a new session now being in use (or not).
361 * @param address the address
362 * @param session the session
363 * @param in_use #GNUNET_YES or #GNUNET_NO
366 GST_ats_set_in_use (const struct GNUNET_HELLO_Address *address,
367 struct Session *session,
370 struct AddressInfo *ai;
372 ai = find_ai (address, session);
378 GNUNET_ATS_address_set_in_use (ai->ar, in_use);
383 * Notify ATS that the address has expired and thus cannot
384 * be used any longer. This function must only be called
385 * if the corresponding session is already gone.
387 * @param address the address
390 GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
392 struct AddressInfo *ai;
394 ai = find_ai (address, NULL);
400 GNUNET_assert (GNUNET_YES ==
401 GNUNET_CONTAINER_multipeermap_remove (p2a,
404 GNUNET_break (NULL == ai->session);
405 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
407 "Telling ATS to destroy address from peer %s\n",
408 GNUNET_i2s (&address->peer));
410 GNUNET_ATS_address_destroy (ai->ar);
411 GNUNET_HELLO_address_free (ai->address);
417 * Initialize ATS subsystem.
422 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
427 * Release memory used by the given address data.
430 * @param key which peer is this about
431 * @param value the `struct AddressInfo`
432 * @return #GNUNET_OK (continue to iterate)
435 destroy_ai (void *cls,
436 const struct GNUNET_PeerIdentity *key,
439 struct AddressInfo *ai = value;
441 GNUNET_HELLO_address_free (ai->address);
448 * Shutdown ATS subsystem.
453 GNUNET_CONTAINER_multipeermap_iterate (p2a,
456 GNUNET_CONTAINER_multipeermap_destroy (p2a);
460 /* end of gnunet-service-transport_ats.c */