ats_api_scheduling.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/ats_api_scheduling.c
  19. * @brief automatic transport selection and outbound bandwidth determination
  20. * @author Christian Grothoff
  21. * @author Matthias Wachs
  22. *
  23. * TODO:
  24. * - we could avoid a linear scan over the
  25. * active addresses in some cases, so if
  26. * there is need, we can still optimize here
  27. * - we might want to split off the logic to
  28. * determine LAN vs. WAN, as it has nothing
  29. * to do with accessing the ATS service.
  30. */
  31. #include "platform.h"
  32. #include "gnunet_ats_service.h"
  33. #include "ats.h"
  34. /**
  35. * How frequently do we scan the interfaces for changes to the addresses?
  36. */
  37. #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
  38. /**
  39. * Session ID we use if there is no session / slot.
  40. */
  41. #define NOT_FOUND 0
  42. /**
  43. * Information we track per address, incoming or outgoing. It also
  44. * doesn't matter if we have a session, any address that ATS is
  45. * allowed to suggest right now should be tracked.
  46. */
  47. struct GNUNET_ATS_AddressRecord
  48. {
  49. /**
  50. * Scheduling handle this address record belongs to.
  51. */
  52. struct GNUNET_ATS_SchedulingHandle *sh;
  53. /**
  54. * Address data.
  55. */
  56. struct GNUNET_HELLO_Address *address;
  57. /**
  58. * Session handle. NULL if we have an address but no
  59. * active session for this address.
  60. */
  61. struct Session *session;
  62. /**
  63. * Array with performance data about the address.
  64. */
  65. struct GNUNET_ATS_Information *ats;
  66. /**
  67. * Number of entries in @e ats.
  68. */
  69. uint32_t ats_count;
  70. /**
  71. * Which slot (index) in the session array does
  72. * this record correspond to? FIXME:
  73. * FIXME: a linear search on this is really crappy!
  74. * Maybe switch to a 64-bit global counter and be
  75. * done with it? Or does that then cause too much
  76. * trouble on the ATS-service side?
  77. */
  78. uint32_t slot;
  79. /**
  80. * We're about to destroy this address record, just ATS does
  81. * not know this yet. Once ATS confirms its destruction,
  82. * we can clean up.
  83. */
  84. int in_destroy;
  85. };
  86. /**
  87. * Handle to the ATS subsystem for bandwidth/transport scheduling information.
  88. */
  89. struct GNUNET_ATS_SchedulingHandle
  90. {
  91. /**
  92. * Our configuration.
  93. */
  94. const struct GNUNET_CONFIGURATION_Handle *cfg;
  95. /**
  96. * Callback to invoke on suggestions.
  97. */
  98. GNUNET_ATS_AddressSuggestionCallback suggest_cb;
  99. /**
  100. * Closure for @e suggest_cb.
  101. */
  102. void *suggest_cb_cls;
  103. /**
  104. * Connection to ATS service.
  105. */
  106. struct GNUNET_CLIENT_Connection *client;
  107. /**
  108. * Message queue for sending requests to the ATS service.
  109. */
  110. struct GNUNET_MQ_Handle *mq;
  111. /**
  112. * Array of session objects (we need to translate them to numbers and back
  113. * for the protocol; the offset in the array is the session number on the
  114. * network). Index 0 is always NULL and reserved to represent the NULL pointer.
  115. * Unused entries are also NULL.
  116. */
  117. struct GNUNET_ATS_AddressRecord **session_array;
  118. /**
  119. * Task to trigger reconnect.
  120. */
  121. struct GNUNET_SCHEDULER_Task *task;
  122. /**
  123. * Size of the @e session_array.
  124. */
  125. unsigned int session_array_size;
  126. };
  127. /**
  128. * Re-establish the connection to the ATS service.
  129. *
  130. * @param sh handle to use to re-connect.
  131. */
  132. static void
  133. reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
  134. /**
  135. * Re-establish the connection to the ATS service.
  136. *
  137. * @param cls handle to use to re-connect.
  138. * @param tc scheduler context
  139. */
  140. static void
  141. reconnect_task (void *cls,
  142. const struct GNUNET_SCHEDULER_TaskContext *tc)
  143. {
  144. struct GNUNET_ATS_SchedulingHandle *sh = cls;
  145. sh->task = NULL;
  146. reconnect (sh);
  147. }
  148. /**
  149. * Disconnect from ATS and then reconnect.
  150. *
  151. * @param sh our handle
  152. */
  153. static void
  154. force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
  155. {
  156. if (NULL != sh->mq)
  157. {
  158. GNUNET_MQ_destroy (sh->mq);
  159. sh->mq = NULL;
  160. }
  161. if (NULL != sh->client)
  162. {
  163. GNUNET_CLIENT_disconnect (sh->client);
  164. sh->client = NULL;
  165. }
  166. sh->suggest_cb (sh->suggest_cb_cls,
  167. NULL, NULL, NULL,
  168. GNUNET_BANDWIDTH_ZERO,
  169. GNUNET_BANDWIDTH_ZERO);
  170. sh->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  171. &reconnect_task,
  172. sh);
  173. }
  174. /**
  175. * Find the session object corresponding to the given session ID.
  176. *
  177. * @param sh our handle
  178. * @param session_id current session ID
  179. * @param peer peer the session belongs to
  180. * @return the session object (or NULL)
  181. */
  182. static struct GNUNET_ATS_AddressRecord *
  183. find_session (struct GNUNET_ATS_SchedulingHandle *sh,
  184. uint32_t session_id,
  185. const struct GNUNET_PeerIdentity *peer)
  186. {
  187. struct GNUNET_ATS_AddressRecord *ar;
  188. if (session_id >= sh->session_array_size)
  189. {
  190. GNUNET_break (0);
  191. return NULL;
  192. }
  193. if (0 == session_id)
  194. return NULL;
  195. ar = sh->session_array[session_id];
  196. if (NULL == ar)
  197. {
  198. GNUNET_break (0);
  199. return NULL;
  200. }
  201. if (NULL == ar->address)
  202. {
  203. /* address was destroyed in the meantime, this can happen
  204. as we communicate asynchronously with the ATS service. */
  205. return NULL;
  206. }
  207. if (0 != memcmp (peer,
  208. &ar->address->peer,
  209. sizeof (struct GNUNET_PeerIdentity)))
  210. {
  211. GNUNET_break (0);
  212. force_reconnect (sh);
  213. return NULL;
  214. }
  215. return ar;
  216. }
  217. /**
  218. * Get an available session ID.
  219. *
  220. * @param sh our handle
  221. * @return an unused slot, but never NOT_FOUND (0)
  222. */
  223. static uint32_t
  224. find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh)
  225. {
  226. static uint32_t off;
  227. uint32_t i;
  228. i = 0;
  229. while ( ( (NOT_FOUND == off) ||
  230. (NULL != sh->session_array[off % sh->session_array_size]) ) &&
  231. (i < sh->session_array_size) )
  232. {
  233. off++;
  234. i++;
  235. }
  236. if ( (NOT_FOUND != off % sh->session_array_size) &&
  237. (NULL == sh->session_array[off % sh->session_array_size]) )
  238. return off;
  239. i = sh->session_array_size;
  240. GNUNET_array_grow (sh->session_array,
  241. sh->session_array_size,
  242. sh->session_array_size * 2);
  243. return i;
  244. }
  245. /**
  246. * Get the ID for the given session object.
  247. *
  248. * @param sh our handle
  249. * @param session session object
  250. * @param address the address we are looking for
  251. * @return the session id or NOT_FOUND for error
  252. */
  253. static uint32_t
  254. find_session_id (struct GNUNET_ATS_SchedulingHandle *sh,
  255. struct Session *session,
  256. const struct GNUNET_HELLO_Address *address)
  257. {
  258. uint32_t i;
  259. if (NULL == address)
  260. {
  261. GNUNET_break (0);
  262. return NOT_FOUND;
  263. }
  264. for (i = 1; i < sh->session_array_size; i++)
  265. if ( (NULL != sh->session_array[i]) &&
  266. ( (session == sh->session_array[i]->session) ||
  267. (NULL == sh->session_array[i]->session) ) &&
  268. (0 == GNUNET_HELLO_address_cmp (address,
  269. sh->session_array[i]->address)) )
  270. return i;
  271. return NOT_FOUND;
  272. }
  273. /**
  274. * Release the session slot from the session table (ATS service is
  275. * also done using it).
  276. *
  277. * @param sh our handle
  278. * @param session_id identifies session that is no longer valid
  279. */
  280. static void
  281. release_session (struct GNUNET_ATS_SchedulingHandle *sh,
  282. uint32_t session_id)
  283. {
  284. struct GNUNET_ATS_AddressRecord *ar;
  285. if (NOT_FOUND == session_id)
  286. return;
  287. if (session_id >= sh->session_array_size)
  288. {
  289. GNUNET_break (0);
  290. force_reconnect (sh);
  291. return;
  292. }
  293. /* this slot should have been removed from remove_session before */
  294. ar = sh->session_array[session_id];
  295. if (NULL != ar->session)
  296. {
  297. GNUNET_break (0);
  298. force_reconnect (sh);
  299. return;
  300. }
  301. GNUNET_HELLO_address_free (ar->address);
  302. GNUNET_free (ar);
  303. sh->session_array[session_id] = NULL;
  304. }
  305. /**
  306. * Type of a function to call when we receive a session release
  307. * message from the service.
  308. *
  309. * @param cls the `struct GNUNET_ATS_SchedulingHandle`
  310. * @param msg message received, NULL on timeout or fatal error
  311. */
  312. static void
  313. process_ats_session_release_message (void *cls,
  314. const struct GNUNET_MessageHeader *msg)
  315. {
  316. struct GNUNET_ATS_SchedulingHandle *sh = cls;
  317. const struct SessionReleaseMessage *srm;
  318. srm = (const struct SessionReleaseMessage *) msg;
  319. /* Note: peer field in srm not necessary right now,
  320. but might be good to have in the future */
  321. release_session (sh,
  322. ntohl (srm->session_id));
  323. }
  324. /**
  325. * Type of a function to call when we receive a address suggestion
  326. * message from the service.
  327. *
  328. * @param cls the `struct GNUNET_ATS_SchedulingHandle`
  329. * @param msg message received, NULL on timeout or fatal error
  330. */
  331. static void
  332. process_ats_address_suggestion_message (void *cls,
  333. const struct GNUNET_MessageHeader *msg)
  334. {
  335. struct GNUNET_ATS_SchedulingHandle *sh = cls;
  336. const struct AddressSuggestionMessage *m;
  337. struct GNUNET_ATS_AddressRecord *ar;
  338. uint32_t session_id;
  339. m = (const struct AddressSuggestionMessage *) msg;
  340. session_id = ntohl (m->session_id);
  341. if (0 == session_id)
  342. {
  343. GNUNET_break (0);
  344. force_reconnect (sh);
  345. return;
  346. }
  347. ar = find_session (sh, session_id, &m->peer);
  348. if (NULL == ar)
  349. {
  350. GNUNET_break (0);
  351. force_reconnect (sh);
  352. return;
  353. }
  354. if (NULL == sh->suggest_cb)
  355. return;
  356. if (GNUNET_YES == ar->in_destroy)
  357. {
  358. /* ignore suggestion, as this address is dying, unless BW is 0,
  359. in that case signal 'disconnect' via BW 0 */
  360. if ( (0 == ntohl (m->bandwidth_out.value__)) &&
  361. (0 == ntohl (m->bandwidth_in.value__)) )
  362. {
  363. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  364. "ATS suggests disconnect from peer `%s' with BW %u/%u\n",
  365. GNUNET_i2s (&ar->address->peer),
  366. (unsigned int) ntohl (m->bandwidth_out.value__),
  367. (unsigned int) ntohl (m->bandwidth_in.value__));
  368. sh->suggest_cb (sh->suggest_cb_cls,
  369. &m->peer,
  370. NULL,
  371. NULL,
  372. m->bandwidth_out,
  373. m->bandwidth_in);
  374. }
  375. return;
  376. }
  377. if ( (NULL == ar->session) &&
  378. (GNUNET_HELLO_address_check_option (ar->address,
  379. GNUNET_HELLO_ADDRESS_INFO_INBOUND)) )
  380. {
  381. GNUNET_break (0);
  382. return;
  383. }
  384. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  385. "ATS suggests address slot %u for peer `%s' using plugin %s\n",
  386. ar->slot,
  387. GNUNET_i2s (&ar->address->peer),
  388. ar->address->transport_name);
  389. sh->suggest_cb (sh->suggest_cb_cls,
  390. &m->peer,
  391. ar->address,
  392. ar->session,
  393. m->bandwidth_out,
  394. m->bandwidth_in);
  395. }
  396. /**
  397. * We encountered an error handling the MQ to the
  398. * ATS service. Reconnect.
  399. *
  400. * @param cls the `struct GNUNET_ATS_SchedulingHandle`
  401. * @param error details about the error
  402. */
  403. static void
  404. error_handler (void *cls,
  405. enum GNUNET_MQ_Error error)
  406. {
  407. struct GNUNET_ATS_SchedulingHandle *sh = cls;
  408. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  409. "ATS connection died (code %d), reconnecting\n",
  410. (int) error);
  411. force_reconnect (sh);
  412. }
  413. /**
  414. * Generate and transmit the `struct AddressAddMessage` for the given
  415. * address record.
  416. *
  417. * @param sh the scheduling handle to use for transmission
  418. * @param ar the address to inform the ATS service about
  419. */
  420. static void
  421. send_add_address_message (struct GNUNET_ATS_SchedulingHandle *sh,
  422. const struct GNUNET_ATS_AddressRecord *ar)
  423. {
  424. struct GNUNET_MQ_Envelope *ev;
  425. struct AddressAddMessage *m;
  426. struct GNUNET_ATS_Information *am;
  427. char *pm;
  428. size_t namelen;
  429. size_t msize;
  430. if (NULL == sh->mq)
  431. return; /* disconnected, skip for now */
  432. namelen = (NULL == ar->address->transport_name)
  433. ? 0
  434. : strlen (ar->address->transport_name) + 1;
  435. msize = ar->address->address_length +
  436. ar->ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
  437. ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD);
  438. m->ats_count = htonl (ar->ats_count);
  439. m->peer = ar->address->peer;
  440. m->address_length = htons (ar->address->address_length);
  441. m->address_local_info = htonl ((uint32_t) ar->address->local_info);
  442. m->plugin_name_length = htons (namelen);
  443. m->session_id = htonl (ar->slot);
  444. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  445. "Adding address for peer `%s', plugin `%s', session %p slot %u\n",
  446. GNUNET_i2s (&ar->address->peer),
  447. ar->address->transport_name,
  448. ar->session,
  449. ar->slot);
  450. am = (struct GNUNET_ATS_Information *) &m[1];
  451. memcpy (am,
  452. ar->ats,
  453. ar->ats_count * sizeof (struct GNUNET_ATS_Information));
  454. pm = (char *) &am[ar->ats_count];
  455. memcpy (pm,
  456. ar->address->address,
  457. ar->address->address_length);
  458. if (NULL != ar->address->transport_name)
  459. memcpy (&pm[ar->address->address_length],
  460. ar->address->transport_name,
  461. namelen);
  462. GNUNET_MQ_send (sh->mq, ev);
  463. }
  464. /**
  465. * Re-establish the connection to the ATS service.
  466. *
  467. * @param sh handle to use to re-connect.
  468. */
  469. static void
  470. reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
  471. {
  472. static const struct GNUNET_MQ_MessageHandler handlers[] =
  473. { { &process_ats_session_release_message,
  474. GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE,
  475. sizeof (struct SessionReleaseMessage) },
  476. { &process_ats_address_suggestion_message,
  477. GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION,
  478. sizeof (struct AddressSuggestionMessage) },
  479. { NULL, 0, 0 } };
  480. struct GNUNET_MQ_Envelope *ev;
  481. struct ClientStartMessage *init;
  482. unsigned int i;
  483. struct GNUNET_ATS_AddressRecord *ar;
  484. GNUNET_assert (NULL == sh->client);
  485. sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
  486. if (NULL == sh->client)
  487. {
  488. force_reconnect (sh);
  489. return;
  490. }
  491. sh->mq = GNUNET_MQ_queue_for_connection_client (sh->client,
  492. handlers,
  493. &error_handler,
  494. sh);
  495. ev = GNUNET_MQ_msg (init,
  496. GNUNET_MESSAGE_TYPE_ATS_START);
  497. init->start_flag = htonl (START_FLAG_SCHEDULING);
  498. GNUNET_MQ_send (sh->mq, ev);
  499. if (NULL == sh->mq)
  500. return;
  501. for (i=0;i<sh->session_array_size;i++)
  502. {
  503. ar = sh->session_array[i];
  504. if (NULL == ar)
  505. continue;
  506. send_add_address_message (sh, ar);
  507. if (NULL == sh->mq)
  508. return;
  509. }
  510. }
  511. /**
  512. * Initialize the ATS subsystem.
  513. *
  514. * @param cfg configuration to use
  515. * @param suggest_cb notification to call whenever the suggestation changed
  516. * @param suggest_cb_cls closure for @a suggest_cb
  517. * @return ats context
  518. */
  519. struct GNUNET_ATS_SchedulingHandle *
  520. GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
  521. GNUNET_ATS_AddressSuggestionCallback suggest_cb,
  522. void *suggest_cb_cls)
  523. {
  524. struct GNUNET_ATS_SchedulingHandle *sh;
  525. sh = GNUNET_new (struct GNUNET_ATS_SchedulingHandle);
  526. sh->cfg = cfg;
  527. sh->suggest_cb = suggest_cb;
  528. sh->suggest_cb_cls = suggest_cb_cls;
  529. GNUNET_array_grow (sh->session_array,
  530. sh->session_array_size,
  531. 4);
  532. reconnect (sh);
  533. return sh;
  534. }
  535. /**
  536. * Client is done with ATS scheduling, release resources.
  537. *
  538. * @param sh handle to release
  539. */
  540. void
  541. GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
  542. {
  543. if (NULL != sh->mq)
  544. {
  545. GNUNET_MQ_destroy (sh->mq);
  546. sh->mq = NULL;
  547. }
  548. if (NULL != sh->client)
  549. {
  550. GNUNET_CLIENT_disconnect (sh->client);
  551. sh->client = NULL;
  552. }
  553. if (NULL != sh->task)
  554. {
  555. GNUNET_SCHEDULER_cancel (sh->task);
  556. sh->task = NULL;
  557. }
  558. GNUNET_array_grow (sh->session_array,
  559. sh->session_array_size,
  560. 0);
  561. GNUNET_free (sh);
  562. }
  563. /**
  564. * Test if a address and a session is known to ATS
  565. *
  566. * @param sh the scheduling handle
  567. * @param address the address
  568. * @param session the session
  569. * @return #GNUNET_YES or #GNUNET_NO
  570. */
  571. int
  572. GNUNET_ATS_session_known (struct GNUNET_ATS_SchedulingHandle *sh,
  573. const struct GNUNET_HELLO_Address *address,
  574. struct Session *session)
  575. {
  576. if (NULL == session)
  577. return GNUNET_NO;
  578. if (NOT_FOUND != find_session_id (sh,
  579. session,
  580. address))
  581. return GNUNET_YES; /* Exists */
  582. return GNUNET_NO;
  583. }
  584. /**
  585. * We have a new address ATS should know. Addresses have to be added
  586. * with this function before they can be: updated, set in use and
  587. * destroyed.
  588. *
  589. * @param sh handle
  590. * @param address the address
  591. * @param session session handle, can be NULL
  592. * @param ats performance data for the address
  593. * @param ats_count number of performance records in @a ats
  594. * @return handle to the address representation inside ATS, NULL
  595. * on error (i.e. ATS knows this exact address already)
  596. */
  597. struct GNUNET_ATS_AddressRecord *
  598. GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
  599. const struct GNUNET_HELLO_Address *address,
  600. struct Session *session,
  601. const struct GNUNET_ATS_Information *ats,
  602. uint32_t ats_count)
  603. {
  604. struct GNUNET_ATS_AddressRecord *ar;
  605. size_t namelen;
  606. size_t msize;
  607. uint32_t s;
  608. if (NULL == address)
  609. {
  610. /* we need a valid address */
  611. GNUNET_break (0);
  612. return NULL;
  613. }
  614. namelen = (NULL == address->transport_name)
  615. ? 0
  616. : strlen (address->transport_name) + 1;
  617. msize = address->address_length +
  618. ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
  619. if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
  620. (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
  621. (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
  622. (ats_count >=
  623. GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
  624. {
  625. /* address too large for us, this should not happen */
  626. GNUNET_break (0);
  627. return NULL;
  628. }
  629. if (NOT_FOUND != find_session_id (sh, session, address))
  630. {
  631. /* Already existing, nothing todo, but this should not happen */
  632. GNUNET_break (0);
  633. return NULL;
  634. }
  635. s = find_empty_session_slot (sh);
  636. ar = GNUNET_new (struct GNUNET_ATS_AddressRecord);
  637. ar->sh = sh;
  638. ar->slot = s;
  639. ar->session = session;
  640. ar->address = GNUNET_HELLO_address_copy (address);
  641. GNUNET_array_grow (ar->ats,
  642. ar->ats_count,
  643. ats_count);
  644. memcpy (ar->ats,
  645. ats,
  646. ats_count * sizeof (struct GNUNET_ATS_Information));
  647. sh->session_array[s] = ar;
  648. send_add_address_message (sh, ar);
  649. return ar;
  650. }
  651. /**
  652. * An address was used to initiate a session.
  653. *
  654. * @param ar address record to update information for
  655. * @param session session handle
  656. */
  657. void
  658. GNUNET_ATS_address_add_session (struct GNUNET_ATS_AddressRecord *ar,
  659. struct Session *session)
  660. {
  661. GNUNET_break (NULL == ar->session);
  662. ar->session = session;
  663. }
  664. /**
  665. * A session was destroyed, disassociate it from the
  666. * given address record. If this was an incoming
  667. * addess, destroy the address as well.
  668. *
  669. * @param ar address record to update information for
  670. * @param session session handle
  671. * @return #GNUNET_YES if the @a ar was destroyed because
  672. * it was an incoming address,
  673. * #GNUNET_NO if the @ar was kept because we can
  674. * use it still to establish a new session
  675. */
  676. int
  677. GNUNET_ATS_address_del_session (struct GNUNET_ATS_AddressRecord *ar,
  678. struct Session *session)
  679. {
  680. GNUNET_break (session == ar->session);
  681. ar->session = NULL;
  682. if (GNUNET_HELLO_address_check_option (ar->address,
  683. GNUNET_HELLO_ADDRESS_INFO_INBOUND))
  684. {
  685. GNUNET_ATS_address_destroy (ar);
  686. return GNUNET_YES;
  687. }
  688. return GNUNET_NO;
  689. }
  690. /**
  691. * We have updated performance statistics for a given address. Note
  692. * that this function can be called for addresses that are currently
  693. * in use as well as addresses that are valid but not actively in use.
  694. * Furthermore, the peer may not even be connected to us right now (in
  695. * which case the call may be ignored or the information may be stored
  696. * for later use). Update bandwidth assignments.
  697. *
  698. * @param ar address record to update information for
  699. * @param ats performance data for the address
  700. * @param ats_count number of performance records in @a ats
  701. */
  702. void
  703. GNUNET_ATS_address_update (struct GNUNET_ATS_AddressRecord *ar,
  704. const struct GNUNET_ATS_Information *ats,
  705. uint32_t ats_count)
  706. {
  707. struct GNUNET_ATS_SchedulingHandle *sh = ar->sh;
  708. struct GNUNET_MQ_Envelope *ev;
  709. struct AddressUpdateMessage *m;
  710. struct GNUNET_ATS_Information *am;
  711. size_t msize;
  712. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  713. "Updating address for peer `%s', plugin `%s', session %p slot %u\n",
  714. GNUNET_i2s (&ar->address->peer),
  715. ar->address->transport_name,
  716. ar->session,
  717. ar->slot);
  718. GNUNET_array_grow (ar->ats,
  719. ar->ats_count,
  720. ats_count);
  721. memcpy (ar->ats,
  722. ats,
  723. ats_count * sizeof (struct GNUNET_ATS_Information));
  724. if (NULL == sh->mq)
  725. return; /* disconnected, skip for now */
  726. msize = ar->ats_count * sizeof (struct GNUNET_ATS_Information);
  727. ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
  728. m->ats_count = htonl (ar->ats_count);
  729. m->peer = ar->address->peer;
  730. m->session_id = htonl (ar->slot);
  731. am = (struct GNUNET_ATS_Information *) &m[1];
  732. memcpy (am,
  733. ar->ats,
  734. ar->ats_count * sizeof (struct GNUNET_ATS_Information));
  735. GNUNET_MQ_send (sh->mq, ev);
  736. }
  737. /**
  738. * An address got destroyed, stop using it as a valid address.
  739. *
  740. * @param ar address to destroy
  741. */
  742. void
  743. GNUNET_ATS_address_destroy (struct GNUNET_ATS_AddressRecord *ar)
  744. {
  745. struct GNUNET_ATS_SchedulingHandle *sh = ar->sh;
  746. struct GNUNET_MQ_Envelope *ev;
  747. struct AddressDestroyedMessage *m;
  748. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  749. "Deleting address for peer `%s', plugin `%s', slot %u session %p\n",
  750. GNUNET_i2s (&ar->address->peer),
  751. ar->address->transport_name,
  752. ar->slot,
  753. ar->session);
  754. GNUNET_break (NULL == ar->session);
  755. ar->session = NULL;
  756. ar->in_destroy = GNUNET_YES;
  757. GNUNET_array_grow (ar->ats,
  758. ar->ats_count,
  759. 0);
  760. if (NULL == sh->mq)
  761. return;
  762. ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
  763. m->session_id = htonl (ar->slot);
  764. m->peer = ar->address->peer;
  765. GNUNET_MQ_send (sh->mq, ev);
  766. }
  767. /* end of ats_api_scheduling.c */