gnunet-service-transport_ats.c 27 KB

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