aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-transport_ats.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/gnunet-service-transport_ats.c')
-rw-r--r--src/transport/gnunet-service-transport_ats.c906
1 files changed, 0 insertions, 906 deletions
diff --git a/src/transport/gnunet-service-transport_ats.c b/src/transport/gnunet-service-transport_ats.c
deleted file mode 100644
index 2438a0a48..000000000
--- a/src/transport/gnunet-service-transport_ats.c
+++ /dev/null
@@ -1,906 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-transport_ats.c
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 * Log convenience function.
34 */
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-ats", __VA_ARGS__)
36
37
38/**
39 * Information we track for each address known to ATS.
40 */
41struct AddressInfo
42{
43 /**
44 * The address (with peer identity). Must never change
45 * while this struct is in the #p2a map.
46 */
47 struct GNUNET_HELLO_Address *address;
48
49 /**
50 * Session (can be NULL)
51 */
52 struct GNUNET_ATS_Session *session;
53
54 /**
55 * Record with ATS API for the address.
56 */
57 struct GNUNET_ATS_AddressRecord *ar;
58
59 /**
60 * Performance properties of this address.
61 */
62 struct GNUNET_ATS_Properties properties;
63
64 /**
65 * Time until when this address is blocked and should thus not be
66 * made available to ATS (@e ar should be NULL until this time).
67 * Used when transport determines that for some reason it
68 * (temporarily) cannot use an address, even though it has been
69 * validated.
70 */
71 struct GNUNET_TIME_Absolute blocked;
72
73 /**
74 * If an address is blocked as part of an exponential back-off,
75 * we track the current size of the backoff here.
76 */
77 struct GNUNET_TIME_Relative back_off;
78
79 /**
80 * Task scheduled to unblock an ATS-blocked address at
81 * @e blocked time, or NULL if the address is not blocked
82 * (and thus @e ar is non-NULL).
83 */
84 struct GNUNET_SCHEDULER_Task *unblock_task;
85
86 /**
87 * Set to #GNUNET_YES if the address has expired but we could
88 * not yet remove it because we still have a valid session.
89 */
90 int expired;
91};
92
93
94/**
95 * Map from peer identities to one or more `struct AddressInfo` values
96 * for the peer.
97 */
98static struct GNUNET_CONTAINER_MultiPeerMap *p2a;
99
100/**
101 * Number of blocked addresses.
102 */
103static unsigned int num_blocked;
104
105
106/**
107 * Closure for #find_ai_cb() and #find_ai_no_session_cb().
108 */
109struct FindClosure
110{
111 /**
112 * Session to look for (only used if the address is inbound).
113 */
114 struct GNUNET_ATS_Session *session;
115
116 /**
117 * Address to look for.
118 */
119 const struct GNUNET_HELLO_Address *address;
120
121 /**
122 * Where to store the result.
123 */
124 struct AddressInfo *ret;
125};
126
127
128/**
129 * Provide an update on the `p2a` map size to statistics.
130 * This function should be called whenever the `p2a` map
131 * is changed.
132 */
133static void
134publish_p2a_stat_update ()
135{
136 GNUNET_STATISTICS_set (GST_stats,
137 gettext_noop ("# Addresses given to ATS"),
138 GNUNET_CONTAINER_multipeermap_size (p2a) - num_blocked,
139 GNUNET_NO);
140 GNUNET_STATISTICS_set (GST_stats,
141 "# blocked addresses",
142 num_blocked,
143 GNUNET_NO);
144}
145
146
147/**
148 * Find matching address info. Both the address and the session
149 * must match; note that expired addresses are still found (as
150 * the session kind-of keeps those alive).
151 *
152 * @param cls the `struct FindClosure`
153 * @param key which peer is this about
154 * @param value the `struct AddressInfo`
155 * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
156 */
157static int
158find_ai_cb (void *cls,
159 const struct GNUNET_PeerIdentity *key,
160 void *value)
161{
162 struct FindClosure *fc = cls;
163 struct AddressInfo *ai = value;
164
165 if ((0 ==
166 GNUNET_HELLO_address_cmp (fc->address,
167 ai->address)) &&
168 (fc->session == ai->session))
169 {
170 fc->ret = ai;
171 return GNUNET_NO;
172 }
173 return GNUNET_YES;
174}
175
176
177/**
178 * Find the address information struct for the
179 * given @a address and @a session.
180 *
181 * @param address address to look for
182 * @param session session to match for inbound connections
183 * @return NULL if this combination is unknown
184 */
185static struct AddressInfo *
186find_ai (const struct GNUNET_HELLO_Address *address,
187 struct GNUNET_ATS_Session *session)
188{
189 struct FindClosure fc;
190
191 fc.address = address;
192 fc.session = session;
193 fc.ret = NULL;
194 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
195 &address->peer,
196 &find_ai_cb,
197 &fc);
198 return fc.ret;
199}
200
201
202/**
203 * Find matching address info, ignoring sessions and expired
204 * addresses.
205 *
206 * @param cls the `struct FindClosure`
207 * @param key which peer is this about
208 * @param value the `struct AddressInfo`
209 * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
210 */
211static int
212find_ai_no_session_cb (void *cls,
213 const struct GNUNET_PeerIdentity *key,
214 void *value)
215{
216 struct FindClosure *fc = cls;
217 struct AddressInfo *ai = value;
218
219 if (ai->expired)
220 return GNUNET_YES; /* expired do not count here */
221 if (0 ==
222 GNUNET_HELLO_address_cmp (fc->address,
223 ai->address))
224 {
225 fc->ret = ai;
226 return GNUNET_NO;
227 }
228 return GNUNET_YES;
229}
230
231
232/**
233 * Find the address information struct for the
234 * given address (ignoring sessions)
235 *
236 * @param address address to look for
237 * @return NULL if this combination is unknown
238 */
239static struct AddressInfo *
240find_ai_no_session (const struct GNUNET_HELLO_Address *address)
241{
242 struct FindClosure fc;
243
244 fc.address = address;
245 fc.session = NULL;
246 fc.ret = NULL;
247 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
248 &address->peer,
249 &find_ai_no_session_cb,
250 &fc);
251 return fc.ret;
252}
253
254
255/**
256 * Test if ATS knows about this @a address and @a session.
257 * Note that even if the address is expired, we return
258 * #GNUNET_YES if the respective session matches.
259 *
260 * @param address the address
261 * @param session the session
262 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
263 */
264int
265GST_ats_is_known (const struct GNUNET_HELLO_Address *address,
266 struct GNUNET_ATS_Session *session)
267{
268 return (NULL != find_ai (address, session)) ? GNUNET_YES : GNUNET_NO;
269}
270
271
272/**
273 * Test if ATS knows about this @a address. Note that
274 * expired addresses do not count.
275 *
276 * @param address the address
277 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
278 */
279int
280GST_ats_is_known_no_session (const struct GNUNET_HELLO_Address *address)
281{
282 return (NULL != find_ai_no_session (address))
283 ? GNUNET_YES
284 : GNUNET_NO;
285}
286
287
288/**
289 * The blocking time for an address has expired, allow ATS to
290 * suggest it again.
291 *
292 * @param cls the `struct AddressInfo` of the address to unblock
293 */
294static void
295unblock_address (void *cls)
296{
297 struct AddressInfo *ai = cls;
298
299 ai->unblock_task = NULL;
300 LOG (GNUNET_ERROR_TYPE_DEBUG,
301 "Unblocking address %s of peer %s\n",
302 GST_plugins_a2s (ai->address),
303 GNUNET_i2s (&ai->address->peer));
304 ai->ar = GNUNET_ATS_address_add (GST_ats,
305 ai->address,
306 ai->session,
307 &ai->properties);
308 GNUNET_break (NULL != ai->ar);
309 num_blocked--;
310 publish_p2a_stat_update ();
311}
312
313
314/**
315 * Temporarily block a valid address for use by ATS for address
316 * suggestions. This function should be called if an address was
317 * suggested by ATS but failed to perform (i.e. failure to establish a
318 * session or to exchange the PING/PONG).
319 *
320 * @param address the address to block
321 * @param session the session (can be NULL)
322 */
323void
324GST_ats_block_address (const struct GNUNET_HELLO_Address *address,
325 struct GNUNET_ATS_Session *session)
326{
327 struct AddressInfo *ai;
328
329 if (0 ==
330 memcmp (&GST_my_identity,
331 &address->peer,
332 sizeof(struct GNUNET_PeerIdentity)))
333 return; /* our own, ignore! */
334 ai = find_ai (address,
335 session);
336 if ((NULL == ai) || (NULL == ai->ar))
337 {
338 /* The address is already gone/blocked, this can happen during a blacklist
339 * callback. */
340 return;
341 }
342 ai->back_off = GNUNET_TIME_STD_BACKOFF (ai->back_off);
343 if (GNUNET_YES ==
344 GNUNET_HELLO_address_check_option (address,
345 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
346 LOG (GNUNET_ERROR_TYPE_DEBUG,
347 "Removing address %s of peer %s from use (inbound died)\n",
348 GST_plugins_a2s (address),
349 GNUNET_i2s (&address->peer));
350 else
351 LOG (GNUNET_ERROR_TYPE_INFO,
352 "Blocking address %s of peer %s from use for %s\n",
353 GST_plugins_a2s (address),
354 GNUNET_i2s (&address->peer),
355 GNUNET_STRINGS_relative_time_to_string (ai->back_off,
356 GNUNET_YES));
357 /* destroy session and address */
358 if ((NULL == session) ||
359 (GNUNET_NO ==
360 GNUNET_ATS_address_del_session (ai->ar,
361 session)))
362 {
363 GNUNET_ATS_address_destroy (ai->ar);
364 }
365 /* "ar" has been freed, regardless how the branch
366 above played out: it was either freed in
367 #GNUNET_ATS_address_del_session() because it was
368 incoming, or explicitly in
369 #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
370
371 /* determine when the address should come back to life */
372 ai->blocked = GNUNET_TIME_relative_to_absolute (ai->back_off);
373 ai->unblock_task = GNUNET_SCHEDULER_add_delayed (ai->back_off,
374 &unblock_address,
375 ai);
376 num_blocked++;
377 publish_p2a_stat_update ();
378}
379
380
381/**
382 * Reset address blocking time. Resets the exponential
383 * back-off timer for this address to zero. Called when
384 * an address was used to create a successful connection.
385 *
386 * @param address the address to reset the blocking timer
387 * @param session the session (can be NULL)
388 */
389void
390GST_ats_block_reset (const struct GNUNET_HELLO_Address *address,
391 struct GNUNET_ATS_Session *session)
392{
393 struct AddressInfo *ai;
394
395 if (0 ==
396 memcmp (&GST_my_identity,
397 &address->peer,
398 sizeof(struct GNUNET_PeerIdentity)))
399 return; /* our own, ignore! */
400 ai = find_ai (address, session);
401 if (NULL == ai)
402 {
403 GNUNET_break (0);
404 return;
405 }
406 /* address is in successful use, so it should not be blocked right now */
407 GNUNET_break (NULL == ai->unblock_task);
408 ai->back_off = GNUNET_TIME_UNIT_ZERO;
409}
410
411
412/**
413 * Notify ATS about a new inbound @a address. The @a address in
414 * combination with the @a session must be new, but this function will
415 * perform a santiy check. If the @a address is indeed new, make it
416 * available to ATS.
417 *
418 * @param address the address
419 * @param session the session
420 * @param prop performance information
421 */
422void
423GST_ats_add_inbound_address (const struct GNUNET_HELLO_Address *address,
424 struct GNUNET_ATS_Session *session,
425 const struct GNUNET_ATS_Properties *prop)
426{
427 struct GNUNET_ATS_AddressRecord *ar;
428 struct AddressInfo *ai;
429
430 if (0 ==
431 memcmp (&GST_my_identity,
432 &address->peer,
433 sizeof(struct GNUNET_PeerIdentity)))
434 return; /* our own, ignore! */
435
436 /* Sanity checks for a valid inbound address */
437 if (NULL == address->transport_name)
438 {
439 GNUNET_break (0);
440 return;
441 }
442 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
443 GNUNET_assert (GNUNET_YES ==
444 GNUNET_HELLO_address_check_option (address,
445 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
446 GNUNET_assert (NULL != session);
447 ai = find_ai (address, session);
448 if (NULL != ai)
449 {
450 /* This should only be called for new sessions, and thus
451 we should not already have the address */
452 GNUNET_break (0);
453 return;
454 }
455 /* Is indeed new, let's tell ATS */
456 LOG (GNUNET_ERROR_TYPE_DEBUG,
457 "Notifying ATS about peer `%s''s new inbound address `%s' session %p in network %s\n",
458 GNUNET_i2s (&address->peer),
459 GST_plugins_a2s (address),
460 session,
461 GNUNET_NT_to_string (prop->scope));
462 ar = GNUNET_ATS_address_add (GST_ats,
463 address,
464 session,
465 prop);
466 GNUNET_assert (NULL != ar);
467 ai = GNUNET_new (struct AddressInfo);
468 ai->address = GNUNET_HELLO_address_copy (address);
469 ai->session = session;
470 ai->properties = *prop;
471 ai->ar = ar;
472 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
473 &ai->address->peer,
474 ai,
475 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
476 publish_p2a_stat_update ();
477}
478
479
480void
481GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
482 const struct GNUNET_ATS_Properties *prop)
483{
484 struct GNUNET_ATS_AddressRecord *ar;
485 struct AddressInfo *ai;
486
487 if (0 ==
488 memcmp (&GST_my_identity,
489 &address->peer,
490 sizeof(struct GNUNET_PeerIdentity)))
491 return; /* our own, ignore! */
492 /* validadte address */
493 if (NULL == address->transport_name)
494 {
495 GNUNET_break (0);
496 return;
497 }
498 GNUNET_assert (GNUNET_YES !=
499 GNUNET_HELLO_address_check_option (address,
500 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
501 ai = find_ai_no_session (address);
502 GNUNET_assert (NULL == ai);
503 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
504
505 /* address seems sane, let's tell ATS */
506 LOG (GNUNET_ERROR_TYPE_INFO,
507 "Notifying ATS about peer %s's new address `%s'\n",
508 GNUNET_i2s (&address->peer),
509 GST_plugins_a2s (address));
510 ar = GNUNET_ATS_address_add (GST_ats,
511 address,
512 NULL,
513 prop);
514 GNUNET_assert (NULL != ar);
515 ai = GNUNET_new (struct AddressInfo);
516 ai->address = GNUNET_HELLO_address_copy (address);
517 ai->ar = ar;
518 ai->properties = *prop;
519 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
520 &ai->address->peer,
521 ai,
522 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
523 publish_p2a_stat_update ();
524}
525
526
527/**
528 * Notify ATS about a new @a session now existing for the given
529 * @a address. Essentially, an outbound @a address was used
530 * to establish a @a session. It is safe to call this function
531 * repeatedly for the same @a address and @a session pair.
532 *
533 * @param address the address
534 * @param session the session
535 */
536void
537GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
538 struct GNUNET_ATS_Session *session)
539{
540 struct AddressInfo *ai;
541
542 if (0 ==
543 memcmp (&GST_my_identity,
544 &address->peer,
545 sizeof(struct GNUNET_PeerIdentity)))
546 return; /* our own, ignore! */
547 ai = find_ai (address, NULL);
548 if (NULL == ai)
549 {
550 /* We may simply already be aware of the session, even if some
551 other part of the code could not tell if it just created a new
552 session or just got one recycled from the plugin; hence, we may
553 be called with "new" session even for an "old" session; in that
554 case, check that this is the case, but just ignore it. */GNUNET_assert (NULL != (find_ai (address, session)));
555 return;
556 }
557 GNUNET_assert (NULL == ai->session);
558 ai->session = session;
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Telling ATS about new session for peer %s\n",
561 GNUNET_i2s (&address->peer));
562 /* Note that the address might currently be blocked; we only
563 tell ATS about the session if the address is currently not
564 blocked; otherwise, ATS will be told about the session on
565 unblock. */
566 if (NULL != ai->ar)
567 GNUNET_ATS_address_add_session (ai->ar,
568 session);
569 else
570 GNUNET_assert (NULL != ai->unblock_task);
571}
572
573
574/**
575 * Release memory used by the given address data.
576 *
577 * @param ai the `struct AddressInfo`
578 */
579static void
580destroy_ai (struct AddressInfo *ai)
581{
582 GNUNET_assert (NULL == ai->session);
583 if (NULL != ai->unblock_task)
584 {
585 GNUNET_SCHEDULER_cancel (ai->unblock_task);
586 ai->unblock_task = NULL;
587 num_blocked--;
588 }
589 GNUNET_assert (GNUNET_YES ==
590 GNUNET_CONTAINER_multipeermap_remove (p2a,
591 &ai->address->peer,
592 ai));
593 LOG (GNUNET_ERROR_TYPE_DEBUG,
594 "Telling ATS to destroy address from peer %s\n",
595 GNUNET_i2s (&ai->address->peer));
596 if (NULL != ai->ar)
597 {
598 GNUNET_ATS_address_destroy (ai->ar);
599 ai->ar = NULL;
600 }
601 publish_p2a_stat_update ();
602 GNUNET_HELLO_address_free (ai->address);
603 GNUNET_free (ai);
604}
605
606
607/**
608 * Notify ATS that the @a session (but not the @a address) of
609 * a given @a address is no longer relevant. (The @a session
610 * went down.) This function may be called even if for the
611 * respective outbound address #GST_ats_new_session() was
612 * never called and thus the pair is unknown to ATS. In this
613 * case, the call is simply ignored.
614 *
615 * @param address the address
616 * @param session the session
617 */
618void
619GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
620 struct GNUNET_ATS_Session *session)
621{
622 struct AddressInfo *ai;
623
624 if (0 ==
625 memcmp (&GST_my_identity,
626 &address->peer,
627 sizeof(struct GNUNET_PeerIdentity)))
628 return; /* our own, ignore! */
629 if (NULL == session)
630 {
631 GNUNET_break (0);
632 return;
633 }
634 ai = find_ai (address,
635 session);
636 if (NULL == ai)
637 {
638 /* We sometimes create sessions just for sending a PING,
639 and if those are destroyed they were never known to
640 ATS which means we end up here (however, in this
641 case, the address must be an outbound address). */
642 GNUNET_break (GNUNET_YES !=
643 GNUNET_HELLO_address_check_option (address,
644 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
645 return;
646 }
647 GNUNET_assert (session == ai->session);
648 ai->session = NULL;
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "Telling ATS to destroy session %p from peer %s\n",
651 session,
652 GNUNET_i2s (&address->peer));
653 if (GNUNET_YES == ai->expired)
654 {
655 /* last reason to keep this 'ai' around is now gone, the
656 session is dead as well, clean up */
657 if (NULL != ai->ar)
658 {
659 /* Address expired but not blocked, and thus 'ar' was still
660 live because of the session; deleting just the session
661 will do for an inbound session, but for an outbound we
662 then also need to destroy the address with ATS. */
663 if (GNUNET_NO ==
664 GNUNET_ATS_address_del_session (ai->ar,
665 session))
666 {
667 GNUNET_ATS_address_destroy (ai->ar);
668 }
669 /* "ar" has been freed, regardless how the branch
670 above played out: it was either freed in
671 #GNUNET_ATS_address_del_session() because it was
672 incoming, or explicitly in
673 #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
674 }
675 destroy_ai (ai);
676 return;
677 }
678
679 if (NULL == ai->ar)
680 {
681 /* If ATS doesn't know about the address/session, this means
682 this address was blocked. */
683 if (GNUNET_YES ==
684 GNUNET_HELLO_address_check_option (address,
685 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
686 {
687 /* This was a blocked inbound session, which now lost the
688 session. But inbound addresses are by themselves useless,
689 so we must forget about the address as well. */
690 destroy_ai (ai);
691 return;
692 }
693 /* Otherwise, we are done as we have set `ai->session` to NULL
694 already and ATS will simply not be told about the session when
695 the connection is unblocked and the outbound address becomes
696 available again. . */
697 return;
698 }
699
700 /* This is the "simple" case where ATS knows about the session and
701 the address is neither blocked nor expired. Delete the session,
702 and if it was inbound, free the address as well. */
703 if (GNUNET_YES ==
704 GNUNET_ATS_address_del_session (ai->ar,
705 session))
706 {
707 /* This was an inbound address, the session is now gone, so we
708 need to also forget about the address itself. */
709 ai->ar = NULL;
710 destroy_ai (ai);
711 }
712}
713
714
715/**
716 * Notify ATS about DV @a distance change to an @a address.
717 * Does nothing if the @a address is not known to us.
718 *
719 * @param address the address
720 * @param distance new distance value
721 */
722void
723GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
724 uint32_t distance)
725{
726 struct AddressInfo *ai;
727
728 ai = find_ai_no_session (address);
729 if (NULL == ai)
730 {
731 /* We do not know about this address, do nothing. */
732 return;
733 }
734 LOG (GNUNET_ERROR_TYPE_DEBUG,
735 "Updated distance for peer `%s' to %u\n",
736 GNUNET_i2s (&address->peer),
737 distance);
738 ai->properties.distance = distance;
739 /* Give manipulation its chance to change metrics */
740 GST_manipulation_manipulate_metrics (address,
741 ai->session,
742 &ai->properties);
743 /* Address may be blocked, only give ATS if address is
744 currently active. */
745 if (NULL != ai->ar)
746 GNUNET_ATS_address_update (ai->ar,
747 &ai->properties);
748}
749
750
751void
752GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
753 struct GNUNET_TIME_Relative delay)
754{
755 struct AddressInfo *ai;
756
757 ai = find_ai_no_session (address);
758 if (NULL == ai)
759 {
760 /* We do not know about this address, do nothing. */
761 return;
762 }
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Updated latency for peer `%s' to %s\n",
765 GNUNET_i2s (&address->peer),
766 GNUNET_STRINGS_relative_time_to_string (delay,
767 GNUNET_YES));
768 ai->properties.delay = delay;
769 /* Give manipulation its chance to change metrics */
770 GST_manipulation_manipulate_metrics (address,
771 ai->session,
772 &ai->properties);
773 /* Address may be blocked, only give ATS if address is
774 currently active. */
775 if (NULL != ai->ar)
776 GNUNET_ATS_address_update (ai->ar,
777 &ai->properties);
778}
779
780
781/**
782 * Notify ATS about utilization changes to an @a address.
783 * Does nothing if the @a address is not known to us.
784 *
785 * @param address our information about the address
786 * @param bps_in new utilization inbound
787 * @param bps_out new utilization outbound
788 */
789void
790GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
791 uint32_t bps_in,
792 uint32_t bps_out)
793{
794 struct AddressInfo *ai;
795
796 ai = find_ai_no_session (address);
797 if (NULL == ai)
798 {
799 /* We do not know about this address, do nothing. */
800 return;
801 }
802 LOG (GNUNET_ERROR_TYPE_DEBUG,
803 "Updating utilization for peer `%s' address %s: %u/%u\n",
804 GNUNET_i2s (&address->peer),
805 GST_plugins_a2s (address),
806 (unsigned int) bps_in,
807 (unsigned int) bps_out);
808 ai->properties.utilization_in = bps_in;
809 ai->properties.utilization_out = bps_out;
810 /* Give manipulation its chance to change metrics */
811 GST_manipulation_manipulate_metrics (address,
812 ai->session,
813 &ai->properties);
814 /* Address may be blocked, only give ATS if address is
815 currently active. */
816 if (NULL != ai->ar)
817 GNUNET_ATS_address_update (ai->ar,
818 &ai->properties);
819}
820
821
822/**
823 * Notify ATS that the address has expired and thus cannot
824 * be used any longer. This function must only be called
825 * if the corresponding session is already gone.
826 *
827 * @param address the address
828 */
829void
830GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
831{
832 struct AddressInfo *ai;
833
834 if (0 ==
835 memcmp (&GST_my_identity,
836 &address->peer,
837 sizeof(struct GNUNET_PeerIdentity)))
838 return; /* our own, ignore! */
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Address %s of peer %s expired\n",
841 GST_plugins_a2s (address),
842 GNUNET_i2s (&address->peer));
843 ai = find_ai_no_session (address);
844 if (NULL == ai)
845 {
846 GNUNET_assert (0);
847 return;
848 }
849 if (NULL != ai->session)
850 {
851 /* Got an active session, just remember the expiration
852 and act upon it when the session goes down. */
853 ai->expired = GNUNET_YES;
854 return;
855 }
856 /* Address expired, no session, free resources */
857 destroy_ai (ai);
858}
859
860
861/**
862 * Initialize ATS subsystem.
863 */
864void
865GST_ats_init ()
866{
867 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
868}
869
870
871/**
872 * Release memory used by the given address data.
873 *
874 * @param cls NULL
875 * @param key which peer is this about
876 * @param value the `struct AddressInfo`
877 * @return #GNUNET_OK (continue to iterate)
878 */
879static int
880destroy_ai_cb (void *cls,
881 const struct GNUNET_PeerIdentity *key,
882 void *value)
883{
884 struct AddressInfo *ai = value;
885
886 destroy_ai (ai);
887 return GNUNET_OK;
888}
889
890
891/**
892 * Shutdown ATS subsystem.
893 */
894void
895GST_ats_done ()
896{
897 GNUNET_CONTAINER_multipeermap_iterate (p2a,
898 &destroy_ai_cb,
899 NULL);
900 publish_p2a_stat_update ();
901 GNUNET_CONTAINER_multipeermap_destroy (p2a);
902 p2a = NULL;
903}
904
905
906/* end of gnunet-service-transport_ats.c */