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) )
111 GNUNET_assert ( (fc->session != ai->session) ||
112 (NULL == ai->session) );
118 * Find the address information struct for the
119 * given address and session.
121 * @param address address to look for
122 * @param session session to match for inbound connections
123 * @return NULL if this combination is unknown
125 static struct AddressInfo *
126 find_ai (const struct GNUNET_HELLO_Address *address,
127 struct Session *session)
129 struct FindClosure fc;
131 fc.address = address;
132 fc.session = session;
134 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
143 * Test if ATS knows about this address.
145 * @param address the address
146 * @param session the session
147 * @return #GNUNET_YES if address is known, #GNUNET_NO if not.
150 GST_ats_is_known (const struct GNUNET_HELLO_Address *address,
151 struct Session *session)
153 return (NULL != find_ai (address, session)) ? GNUNET_YES : GNUNET_NO;
158 * Notify ATS about the new address including the network this address is
161 * @param address the address
162 * @param session the session
163 * @param ats ats information
164 * @param ats_count number of @a ats information
167 GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
168 struct Session *session,
169 const struct GNUNET_ATS_Information *ats,
172 struct GNUNET_TRANSPORT_PluginFunctions *papi;
173 struct GNUNET_ATS_Information ats2[ats_count + 1];
174 struct GNUNET_ATS_AddressRecord *ar;
175 struct AddressInfo *ai;
178 /* valid new address, let ATS know! */
179 if (NULL == address->transport_name)
185 GNUNET_HELLO_address_check_option (address,
186 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
188 GNUNET_break (NULL != session);
192 GNUNET_break (NULL == session);
194 ai = find_ai (address, session);
200 if (NULL == (papi = GST_plugins_find (address->transport_name)))
202 /* we don't have the plugin for this address */
208 net = papi->get_network (papi->cls, session);
209 if (GNUNET_ATS_NET_UNSPECIFIED == net)
211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
212 _ ("Could not obtain a valid network for `%s' %s (%s)\n"),
213 GNUNET_i2s (&address->peer),
214 GST_plugins_a2s (address),
215 address->transport_name);
218 ats2[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
219 ats2[0].value = htonl (net);
222 sizeof(struct GNUNET_ATS_Information) * ats_count);
224 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
225 "Notifying ATS about peer `%s''s new address `%s' session %p in network %s\n",
226 GNUNET_i2s (&address->peer),
227 (0 == address->address_length)
229 : GST_plugins_a2s (address),
231 GNUNET_ATS_print_network_type (net));
232 ar = GNUNET_ATS_address_add (GST_ats,
235 (NULL != session) ? ats2 : ats,
236 (NULL != session) ? ats_count + 1 : ats_count);
237 ai = GNUNET_new (struct AddressInfo);
238 ai->address = GNUNET_HELLO_address_copy (address);
239 ai->session = session;
241 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
244 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
249 * Notify ATS about a new session now existing for the given
252 * @param address the address
253 * @param session the session
256 GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
257 struct Session *session)
259 struct AddressInfo *ai;
261 ai = find_ai (address, NULL);
264 /* We may already be aware of the session, even if some other part
265 of the code could not tell if it just created a new session or
266 just got one recycled from the plugin; hence, we may be called
267 with "new" session even for an "old" session; in that case,
268 check that this is the case, but just ignore it. */
269 GNUNET_assert (NULL != (find_ai (address, session)));
272 GNUNET_break (NULL == ai->session);
273 ai->session = session;
274 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
276 "Telling ATS about new session %p for peer %s\n",
278 GNUNET_i2s (&address->peer));
279 GNUNET_ATS_address_add_session (ai->ar,
285 * Notify ATS that the session (but not the address) of
286 * a given address is no longer relevant.
288 * @param address the address
289 * @param session the session
292 GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
293 struct Session *session)
295 struct AddressInfo *ai;
302 ai = find_ai (address, session);
305 /* We sometimes create sessions just for sending a PING,
306 and if those are destroyed they were never known to
307 ATS which means we end up here (however, in this
308 case, the address must be an outbound address). */
309 GNUNET_break (GNUNET_YES !=
310 GNUNET_HELLO_address_check_option (address,
311 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
315 GNUNET_assert (session == ai->session);
317 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
319 "Telling ATS to destroy session %p from peer %s\n",
321 GNUNET_i2s (&address->peer));
323 GNUNET_ATS_address_del_session (ai->ar, session))
326 GST_ats_expire_address (address);
332 * Notify ATS about property changes to an address.
334 * @param address our information about the address
335 * @param session the session
336 * @param ats performance information
337 * @param ats_count number of elements in @a ats
340 GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address,
341 struct Session *session,
342 const struct GNUNET_ATS_Information *ats,
345 struct GNUNET_ATS_Information *ats_new;
346 struct AddressInfo *ai;
348 ai = find_ai (address, session);
351 /* We sometimes create sessions just for sending a PING,
352 and if we get metrics for those, they were never known to
353 ATS which means we end up here (however, in this
354 case, the address must be an outbound address). */
355 GNUNET_assert (GNUNET_YES !=
356 GNUNET_HELLO_address_check_option (address,
357 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
361 /* Call to manipulation to manipulate ATS information */
362 GNUNET_assert (NULL != GST_ats);
363 if ((NULL == ats) || (0 == ats_count))
365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366 "Updating metrics for peer `%s' address %s session %p\n",
367 GNUNET_i2s (&address->peer),
368 GST_plugins_a2s (address),
370 ats_new = GST_manipulation_manipulate_metrics (address,
374 GNUNET_ATS_address_update (ai->ar,
376 GNUNET_free_non_null (ats_new);
381 * Notify ATS about a new session now being in use (or not).
383 * @param address the address
384 * @param session the session
385 * @param in_use #GNUNET_YES or #GNUNET_NO
388 GST_ats_set_in_use (const struct GNUNET_HELLO_Address *address,
389 struct Session *session,
392 struct AddressInfo *ai;
394 ai = find_ai (address, session);
400 GNUNET_ATS_address_set_in_use (ai->ar, in_use);
405 * Notify ATS that the address has expired and thus cannot
406 * be used any longer. This function must only be called
407 * if the corresponding session is already gone.
409 * @param address the address
412 GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
414 struct AddressInfo *ai;
416 ai = find_ai (address, NULL);
422 GNUNET_assert (GNUNET_YES ==
423 GNUNET_CONTAINER_multipeermap_remove (p2a,
426 GNUNET_break (NULL == ai->session);
427 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
429 "Telling ATS to destroy address from peer %s\n",
430 GNUNET_i2s (&address->peer));
432 GNUNET_ATS_address_destroy (ai->ar);
433 GNUNET_HELLO_address_free (ai->address);
439 * Initialize ATS subsystem.
444 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
449 * Release memory used by the given address data.
452 * @param key which peer is this about
453 * @param value the `struct AddressInfo`
454 * @return #GNUNET_OK (continue to iterate)
457 destroy_ai (void *cls,
458 const struct GNUNET_PeerIdentity *key,
461 struct AddressInfo *ai = value;
463 GNUNET_HELLO_address_free (ai->address);
470 * Shutdown ATS subsystem.
475 GNUNET_CONTAINER_multipeermap_iterate (p2a,
478 GNUNET_CONTAINER_multipeermap_destroy (p2a);
482 /* end of gnunet-service-transport_ats.c */