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);
190 ai = find_ai (address, session);
196 if (NULL == (papi = GST_plugins_find (address->transport_name)))
198 /* we don't have the plugin for this address */
204 net = papi->get_network (papi->cls, session);
205 if (GNUNET_ATS_NET_UNSPECIFIED == net)
207 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
208 _ ("Could not obtain a valid network for `%s' %s (%s)\n"),
209 GNUNET_i2s (&address->peer),
210 GST_plugins_a2s (address),
211 address->transport_name);
214 ats2[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
215 ats2[0].value = htonl (net);
218 sizeof(struct GNUNET_ATS_Information) * ats_count);
220 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
221 "Notifying ATS about peer `%s''s new address `%s' session %p in network %s\n",
222 GNUNET_i2s (&address->peer),
223 (0 == address->address_length)
225 : GST_plugins_a2s (address),
227 GNUNET_ATS_print_network_type (net));
228 ar = GNUNET_ATS_address_add (GST_ats,
231 (NULL != session) ? ats2 : ats,
232 (NULL != session) ? ats_count + 1 : ats_count);
233 ai = GNUNET_new (struct AddressInfo);
234 ai->address = GNUNET_HELLO_address_copy (address);
235 ai->session = session;
237 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
240 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
245 * Notify ATS about a new session now existing for the given
248 * @param address the address
249 * @param session the session
252 GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
253 struct Session *session)
255 struct AddressInfo *ai;
257 ai = find_ai (address, NULL);
260 /* We may already be aware of the session, even if some other part
261 of the code could not tell if it just created a new session or
262 just got one recycled from the plugin; hence, we may be called
263 with "new" session even for an "old" session; in that case,
264 check that this is the case, but just ignore it. */
265 GNUNET_assert (NULL != (find_ai (address, session)));
268 GNUNET_break (NULL == ai->session);
269 ai->session = session;
270 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
272 "Telling ATS about new session %p for peer %s\n",
274 GNUNET_i2s (&address->peer));
275 GNUNET_ATS_address_add_session (ai->ar,
281 * Notify ATS that the session (but not the address) of
282 * a given address is no longer relevant.
284 * @param address the address
285 * @param session the session
288 GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
289 struct Session *session)
291 struct AddressInfo *ai;
298 ai = find_ai (address, session);
301 /* We sometimes create sessions just for sending a PING,
302 and if those are destroyed they were never known to
303 ATS which means we end up here (however, in this
304 case, the address must be an outbound address). */
305 GNUNET_break (GNUNET_YES !=
306 GNUNET_HELLO_address_check_option (address,
307 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
311 GNUNET_assert (session == ai->session);
313 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
315 "Telling ATS to destroy session %p from peer %s\n",
317 GNUNET_i2s (&address->peer));
319 GNUNET_ATS_address_del_session (ai->ar, session))
322 GST_ats_expire_address (address);
328 * Notify ATS about property changes to an address.
330 * @param address our information about the address
331 * @param session the session
332 * @param ats performance information
333 * @param ats_count number of elements in @a ats
336 GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address,
337 struct Session *session,
338 const struct GNUNET_ATS_Information *ats,
341 struct GNUNET_ATS_Information *ats_new;
342 struct AddressInfo *ai;
344 ai = find_ai (address, session);
347 /* We sometimes create sessions just for sending a PING,
348 and if we get metrics for those, they were never known to
349 ATS which means we end up here (however, in this
350 case, the address must be an outbound address). */
351 GNUNET_assert (GNUNET_YES !=
352 GNUNET_HELLO_address_check_option (address,
353 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
357 /* Call to manipulation to manipulate ATS information */
358 GNUNET_assert (NULL != GST_ats);
359 if ((NULL == ats) || (0 == ats_count))
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "Updating metrics for peer `%s' address %s session %p\n",
363 GNUNET_i2s (&address->peer),
364 GST_plugins_a2s (address),
366 ats_new = GST_manipulation_manipulate_metrics (address,
370 GNUNET_ATS_address_update (ai->ar,
372 GNUNET_free_non_null (ats_new);
377 * Notify ATS about a new session now being in use (or not).
379 * @param address the address
380 * @param session the session
381 * @param in_use #GNUNET_YES or #GNUNET_NO
384 GST_ats_set_in_use (const struct GNUNET_HELLO_Address *address,
385 struct Session *session,
388 struct AddressInfo *ai;
390 ai = find_ai (address, session);
396 GNUNET_ATS_address_set_in_use (ai->ar, in_use);
401 * Notify ATS that the address has expired and thus cannot
402 * be used any longer. This function must only be called
403 * if the corresponding session is already gone.
405 * @param address the address
408 GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
410 struct AddressInfo *ai;
412 ai = find_ai (address, NULL);
418 GNUNET_assert (GNUNET_YES ==
419 GNUNET_CONTAINER_multipeermap_remove (p2a,
422 GNUNET_break (NULL == ai->session);
423 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
425 "Telling ATS to destroy address from peer %s\n",
426 GNUNET_i2s (&address->peer));
428 GNUNET_ATS_address_destroy (ai->ar);
429 GNUNET_HELLO_address_free (ai->address);
435 * Initialize ATS subsystem.
440 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
445 * Release memory used by the given address data.
448 * @param key which peer is this about
449 * @param value the `struct AddressInfo`
450 * @return #GNUNET_OK (continue to iterate)
453 destroy_ai (void *cls,
454 const struct GNUNET_PeerIdentity *key,
457 struct AddressInfo *ai = value;
459 GNUNET_HELLO_address_free (ai->address);
466 * Shutdown ATS subsystem.
471 GNUNET_CONTAINER_multipeermap_iterate (p2a,
474 GNUNET_CONTAINER_multipeermap_destroy (p2a);
478 /* end of gnunet-service-transport_ats.c */