aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-transport_ats.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-19 01:08:03 +0000
committerChristian Grothoff <christian@grothoff.org>2015-01-19 01:08:03 +0000
commitf735158d94616b75ade351a3cce226483b8af55e (patch)
tree1cd9732b99cc6437fec7751b8f3c9ef28f0371c9 /src/transport/gnunet-service-transport_ats.c
parentd769049a7db56037ea4aff3d9d8a8d42a373ec9c (diff)
downloadgnunet-f735158d94616b75ade351a3cce226483b8af55e.tar.gz
gnunet-f735158d94616b75ade351a3cce226483b8af55e.zip
-towards improved ATS API, adding return value with address record when adding address, adding new subsystem with peer-to-address map to transport; causes various new assertions to fail, but no major regression -- not finished
Diffstat (limited to 'src/transport/gnunet-service-transport_ats.c')
-rw-r--r--src/transport/gnunet-service-transport_ats.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/transport/gnunet-service-transport_ats.c b/src/transport/gnunet-service-transport_ats.c
new file mode 100644
index 000000000..c6975e526
--- /dev/null
+++ b/src/transport/gnunet-service-transport_ats.c
@@ -0,0 +1,441 @@
1/*
2 This file is part of GNUnet.
3 (C) 2015 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20/**
21 * @file transport/gnunet-service-transport_ats.h
22 * @brief interfacing between transport and ATS service
23 * @author Christian Grothoff
24 */
25#include "platform.h"
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"
31
32
33/**
34 * Information we track for each address known to ATS.
35 */
36struct AddressInfo
37{
38
39 /**
40 * The address (with peer identity).
41 */
42 struct GNUNET_HELLO_Address *address;
43
44 /**
45 * Session (can be NULL)
46 */
47 struct Session *session;
48
49 /**
50 * Record with ATS API for the address.
51 */
52 struct GNUNET_ATS_AddressRecord *ar;
53};
54
55
56/**
57 * Map from peer identities to one or more `struct AddressInfo` values
58 * for the peer.
59 */
60static struct GNUNET_CONTAINER_MultiPeerMap *p2a;
61
62
63/**
64 * Closure for #find_ai().
65 */
66struct FindClosure
67{
68
69 /**
70 * Session to look for (only used if the address is inbound).
71 */
72 struct Session *session;
73
74 /**
75 * Address to look for.
76 */
77 const struct GNUNET_HELLO_Address *address;
78
79 /**
80 * Where to store the result.
81 */
82 struct AddressInfo *ret;
83
84};
85
86
87/**
88 * Find matching address info.
89 *
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
94 */
95static int
96find_ai_cb (void *cls,
97 const struct GNUNET_PeerIdentity *key,
98 void *value)
99{
100 struct FindClosure *fc = cls;
101 struct AddressInfo *ai = value;
102
103 if ( (0 ==
104 GNUNET_HELLO_address_cmp (fc->address,
105 ai->address) ) &&
106 (fc->session == ai->session) )
107 {
108 fc->ret = ai;
109 return GNUNET_NO;
110 }
111 return GNUNET_YES;
112}
113
114
115/**
116 * Find the address information struct for the
117 * given address and session.
118 *
119 * @param address address to look for
120 * @param session session to match for inbound connections
121 * @return NULL if this combination is unknown
122 */
123static struct AddressInfo *
124find_ai (const struct GNUNET_HELLO_Address *address,
125 struct Session *session)
126{
127 struct FindClosure fc;
128
129 fc.address = address;
130 fc.session = session;
131 fc.ret = NULL;
132 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
133 &address->peer,
134 &find_ai_cb,
135 &fc);
136 return fc.ret;
137}
138
139
140/**
141 * Notify ATS about the new address including the network this address is
142 * located in.
143 *
144 * @param address the address
145 * @param session the session
146 * @param ats ats information
147 * @param ats_count number of @a ats information
148 */
149void
150GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
151 struct Session *session,
152 const struct GNUNET_ATS_Information *ats,
153 uint32_t ats_count)
154{
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;
159 uint32_t net;
160
161 /* valid new address, let ATS know! */
162 if (NULL == address->transport_name)
163 {
164 GNUNET_break(0);
165 return;
166 }
167 if (GNUNET_YES ==
168 GNUNET_HELLO_address_check_option (address,
169 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
170 {
171 GNUNET_break (NULL != session);
172 }
173 else
174 {
175 GNUNET_break (NULL == session);
176 }
177 ai = find_ai (address, session);
178 if (NULL != ai)
179 {
180 GNUNET_break (0);
181 return;
182 }
183 if (NULL == (papi = GST_plugins_find (address->transport_name)))
184 {
185 /* we don't have the plugin for this address */
186 GNUNET_break(0);
187 return;
188 }
189 if (NULL != session)
190 {
191 net = papi->get_network (papi->cls, session);
192 if (GNUNET_ATS_NET_UNSPECIFIED == net)
193 {
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);
199 return;
200 }
201 ats2[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
202 ats2[0].value = htonl (net);
203 memcpy (&ats2[1],
204 ats,
205 sizeof(struct GNUNET_ATS_Information) * ats_count);
206 }
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)
211 ? "<inbound>"
212 : GST_plugins_a2s (address),
213 session,
214 GNUNET_ATS_print_network_type (net));
215 ar = GNUNET_ATS_address_add (GST_ats,
216 address,
217 session,
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;
223 ai->ar = ar;
224 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
225 &ai->address->peer,
226 ai,
227 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
228}
229
230
231/**
232 * Notify ATS about a new session now existing for the given
233 * address.
234 *
235 * @param address the address
236 * @param session the session
237 */
238void
239GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
240 struct Session *session)
241{
242 struct AddressInfo *ai;
243
244 ai = find_ai (address, NULL);
245 if (NULL == ai)
246 {
247 GNUNET_break (NULL != (find_ai (address, session)));
248 return;
249 }
250 GNUNET_break (NULL == ai->session);
251 ai->session = session;
252 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
253 "transport-ats",
254 "Telling ATS about new session %p for peer %s\n",
255 session,
256 GNUNET_i2s (&address->peer));
257 // FIXME: tell ATS API, but not using this call:
258 GNUNET_ATS_address_update (ai->ar,
259 session,
260 NULL, 0);
261
262}
263
264
265/**
266 * Notify ATS that the session (but not the address) of
267 * a given address is no longer relevant.
268 *
269 * @param address the address
270 * @param session the session
271 */
272void
273GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
274 struct Session *session)
275{
276 struct AddressInfo *ai;
277
278 if (NULL == session)
279 {
280 GNUNET_break (0);
281 return;
282 }
283 ai = find_ai (address, session);
284 if (NULL == ai)
285 {
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));
293
294 return;
295 }
296 GNUNET_assert (session == ai->session);
297 ai->session = NULL;
298 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
299 "transport-ats",
300 "Telling ATS to destroy session %p from peer %s\n",
301 session,
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);
307 if (GNUNET_YES ==
308 GNUNET_HELLO_address_check_option (address,
309 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
310 GST_ats_expire_address (address);
311}
312
313
314/**
315 * Notify ATS about property changes to an address.
316 *
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
321 */
322void
323GST_ats_update_metrics (const struct GNUNET_HELLO_Address *address,
324 struct Session *session,
325 const struct GNUNET_ATS_Information *ats,
326 uint32_t ats_count)
327{
328 struct GNUNET_ATS_Information *ats_new;
329 struct AddressInfo *ai;
330
331 ai = find_ai (address, session);
332 if (NULL == ai)
333 {
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));
341
342 return;
343 }
344 /* Call to manipulation to manipulate ATS information */
345 GNUNET_assert (NULL != GST_ats);
346 if ((NULL == ats) || (0 == ats_count))
347 return;
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),
352 session);
353 ats_new = GST_manipulation_manipulate_metrics (address,
354 session,
355 ats,
356 ats_count);
357 GNUNET_ATS_address_update (ai->ar,
358 session,
359 ats_new, ats_count);
360 GNUNET_free_non_null (ats_new);
361}
362
363
364/**
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.
368 *
369 * @param address the address
370 */
371void
372GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
373{
374 struct AddressInfo *ai;
375
376 ai = find_ai (address, NULL);
377 if (NULL == ai)
378 {
379 GNUNET_break (0);
380 return;
381 }
382 GNUNET_assert (GNUNET_YES ==
383 GNUNET_CONTAINER_multipeermap_remove (p2a,
384 &address->peer,
385 ai));
386 GNUNET_break (NULL == ai->session);
387 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
388 "transport-ats",
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);
393 GNUNET_free (ai);
394}
395
396
397/**
398 * Initialize ATS subsystem.
399 */
400void
401GST_ats_init ()
402{
403 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
404}
405
406
407/**
408 * Release memory used by the given address data.
409 *
410 * @param cls NULL
411 * @param key which peer is this about
412 * @param value the `struct AddressInfo`
413 * @return #GNUNET_OK (continue to iterate)
414 */
415static int
416destroy_ai (void *cls,
417 const struct GNUNET_PeerIdentity *key,
418 void *value)
419{
420 struct AddressInfo *ai = value;
421
422 GNUNET_HELLO_address_free (ai->address);
423 GNUNET_free (ai);
424 return GNUNET_OK;
425}
426
427
428/**
429 * Shutdown ATS subsystem.
430 */
431void
432GST_ats_done ()
433{
434 GNUNET_CONTAINER_multipeermap_iterate (p2a,
435 &destroy_ai,
436 NULL);
437 GNUNET_CONTAINER_multipeermap_destroy (p2a);
438 p2a = NULL;
439}
440
441/* end of gnunet-service-transport_ats.c */