ats_api_performance.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010, 2011, 2016 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 ats/ats_api_performance.c
  18. * @brief automatic transport selection and outbound bandwidth determination
  19. * @author Christian Grothoff
  20. * @author Matthias Wachs
  21. */
  22. #include "platform.h"
  23. #include "gnunet_ats_service.h"
  24. #include "ats.h"
  25. #define LOG(kind,...) GNUNET_log_from(kind, "ats-performance-api", __VA_ARGS__)
  26. /**
  27. * Linked list of pending reservations.
  28. */
  29. struct GNUNET_ATS_ReservationContext
  30. {
  31. /**
  32. * Kept in a DLL.
  33. */
  34. struct GNUNET_ATS_ReservationContext *next;
  35. /**
  36. * Kept in a DLL.
  37. */
  38. struct GNUNET_ATS_ReservationContext *prev;
  39. /**
  40. * Target peer.
  41. */
  42. struct GNUNET_PeerIdentity peer;
  43. /**
  44. * Desired reservation
  45. */
  46. int32_t size;
  47. /**
  48. * Function to call on result.
  49. */
  50. GNUNET_ATS_ReservationCallback rcb;
  51. /**
  52. * Closure for @e rcb
  53. */
  54. void *rcb_cls;
  55. /**
  56. * Do we need to undo this reservation if it succeeded? Set to
  57. * #GNUNET_YES if a reservation is cancelled. (at that point, 'info'
  58. * is also set to NULL; however, info will ALSO be NULL for the
  59. * reservation context that is created to undo the original request,
  60. * so 'info' being NULL cannot be used to check if undo is
  61. * required).
  62. */
  63. int undo;
  64. };
  65. /**
  66. * Linked list of pending reservations.
  67. */
  68. struct GNUNET_ATS_AddressListHandle
  69. {
  70. /**
  71. * Kept in a DLL.
  72. */
  73. struct GNUNET_ATS_AddressListHandle *next;
  74. /**
  75. * Kept in a DLL.
  76. */
  77. struct GNUNET_ATS_AddressListHandle *prev;
  78. /**
  79. * Performance handle
  80. */
  81. struct GNUNET_ATS_PerformanceHandle *ph;
  82. /**
  83. * Callback
  84. */
  85. GNUNET_ATS_AddressInformationCallback cb;
  86. /**
  87. * Callback closure for @e cb
  88. */
  89. void *cb_cls;
  90. /**
  91. * Target peer.
  92. */
  93. struct GNUNET_PeerIdentity peer;
  94. /**
  95. * Return all or specific peer only
  96. */
  97. int all_peers;
  98. /**
  99. * Return all or used address only
  100. */
  101. int all_addresses;
  102. /**
  103. * Request multiplexing
  104. */
  105. uint32_t id;
  106. };
  107. /**
  108. * ATS Handle to obtain and/or modify performance information.
  109. */
  110. struct GNUNET_ATS_PerformanceHandle
  111. {
  112. /**
  113. * Our configuration.
  114. */
  115. const struct GNUNET_CONFIGURATION_Handle *cfg;
  116. /**
  117. * Callback to invoke when an address has performance changes.
  118. */
  119. GNUNET_ATS_AddressInformationCallback addr_info_cb;
  120. /**
  121. * Closure for @e addr_info_cb.
  122. */
  123. void *addr_info_cb_cls;
  124. /**
  125. * Connection to ATS service.
  126. */
  127. struct GNUNET_MQ_Handle *mq;
  128. /**
  129. * Head of linked list of pending reservation requests.
  130. */
  131. struct GNUNET_ATS_ReservationContext *reservation_head;
  132. /**
  133. * Tail of linked list of pending reservation requests.
  134. */
  135. struct GNUNET_ATS_ReservationContext *reservation_tail;
  136. /**
  137. * Head of linked list of pending address list requests.
  138. */
  139. struct GNUNET_ATS_AddressListHandle *addresslist_head;
  140. /**
  141. * Tail of linked list of pending address list requests.
  142. */
  143. struct GNUNET_ATS_AddressListHandle *addresslist_tail;
  144. /**
  145. * Current request for transmission to ATS.
  146. */
  147. struct GNUNET_CLIENT_TransmitHandle *th;
  148. /**
  149. * Task to trigger reconnect.
  150. */
  151. struct GNUNET_SCHEDULER_Task *task;
  152. /**
  153. * Reconnect backoff delay.
  154. */
  155. struct GNUNET_TIME_Relative backoff;
  156. /**
  157. * Monitor request multiplexing
  158. */
  159. uint32_t monitor_id;
  160. /**
  161. * Request multiplexing
  162. */
  163. uint32_t id;
  164. /**
  165. * Is the receive loop active?
  166. */
  167. int in_receive;
  168. };
  169. /**
  170. * Re-establish the connection to the ATS service.
  171. *
  172. * @param ph handle to use to re-connect.
  173. */
  174. static void
  175. reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
  176. /**
  177. * Re-establish the connection to the ATS service.
  178. *
  179. * @param cls handle to use to re-connect.
  180. */
  181. static void
  182. reconnect_task (void *cls)
  183. {
  184. struct GNUNET_ATS_PerformanceHandle *ph = cls;
  185. ph->task = NULL;
  186. reconnect (ph);
  187. }
  188. /**
  189. * Reconnect to the ATS service, something went wrong.
  190. *
  191. * @param ph handle to reconnect
  192. */
  193. static void
  194. do_reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
  195. {
  196. struct GNUNET_ATS_ReservationContext *rc;
  197. struct GNUNET_ATS_AddressListHandle *alh;
  198. struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
  199. if (NULL != ph->mq)
  200. {
  201. GNUNET_MQ_destroy (ph->mq);
  202. ph->mq = NULL;
  203. }
  204. while (NULL != (rc = ph->reservation_head))
  205. {
  206. GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
  207. ph->reservation_tail,
  208. rc);
  209. if (NULL != rc->rcb)
  210. rc->rcb (rc->rcb_cls,
  211. NULL,
  212. 0,
  213. GNUNET_TIME_UNIT_FOREVER_REL);
  214. GNUNET_free (rc);
  215. }
  216. bandwidth_zero.value__ = htonl (0);
  217. while (NULL != (alh = ph->addresslist_head))
  218. {
  219. GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
  220. ph->addresslist_tail,
  221. alh);
  222. if (NULL != alh->cb)
  223. alh->cb (alh->cb_cls,
  224. NULL,
  225. GNUNET_NO,
  226. bandwidth_zero,
  227. bandwidth_zero,
  228. NULL);
  229. GNUNET_free (alh);
  230. }
  231. if (NULL != ph->addr_info_cb)
  232. {
  233. /* Indicate reconnect */
  234. ph->addr_info_cb (ph->addr_info_cb_cls,
  235. NULL,
  236. GNUNET_NO,
  237. bandwidth_zero,
  238. bandwidth_zero,
  239. NULL);
  240. }
  241. ph->backoff = GNUNET_TIME_STD_BACKOFF (ph->backoff);
  242. ph->task = GNUNET_SCHEDULER_add_delayed (ph->backoff,
  243. &reconnect_task,
  244. ph);
  245. }
  246. /**
  247. * We received a peer information message. Validate and process it.
  248. *
  249. * @param cls our context with the callback
  250. * @param pi the message
  251. * @return #GNUNET_OK if the message was well-formed
  252. */
  253. static int
  254. check_peer_information (void *cls,
  255. const struct PeerInformationMessage *pi)
  256. {
  257. const char *plugin_address;
  258. const char *plugin_name;
  259. uint16_t plugin_address_length;
  260. uint16_t plugin_name_length;
  261. plugin_address_length = ntohs (pi->address_length);
  262. plugin_name_length = ntohs (pi->plugin_name_length);
  263. plugin_address = (const char *) &pi[1];
  264. plugin_name = &plugin_address[plugin_address_length];
  265. if ( (plugin_address_length + plugin_name_length
  266. + sizeof(struct PeerInformationMessage) != ntohs (pi->header.size)) ||
  267. (plugin_name[plugin_name_length - 1] != '\0'))
  268. {
  269. GNUNET_break(0);
  270. return GNUNET_SYSERR;
  271. }
  272. return GNUNET_OK;
  273. }
  274. /**
  275. * We received a peer information message. Validate and process it.
  276. *
  277. * @param cls our context with the callback
  278. * @param pi the message
  279. * @return #GNUNET_OK if the message was well-formed
  280. */
  281. static void
  282. handle_peer_information (void *cls,
  283. const struct PeerInformationMessage *pi)
  284. {
  285. struct GNUNET_ATS_PerformanceHandle *ph = cls;
  286. const char *plugin_address;
  287. const char *plugin_name;
  288. struct GNUNET_HELLO_Address address;
  289. uint16_t plugin_address_length;
  290. int addr_active;
  291. struct GNUNET_ATS_Properties prop;
  292. if (NULL == ph->addr_info_cb)
  293. return;
  294. plugin_address_length = ntohs (pi->address_length);
  295. addr_active = (int) ntohl (pi->address_active);
  296. plugin_address = (const char *) &pi[1];
  297. plugin_name = &plugin_address[plugin_address_length];
  298. GNUNET_ATS_properties_ntoh (&prop,
  299. &pi->properties);
  300. address.peer = pi->peer;
  301. address.local_info = (enum GNUNET_HELLO_AddressInfo) ntohl (pi->address_local_info);
  302. address.address = plugin_address;
  303. address.address_length = plugin_address_length;
  304. address.transport_name = plugin_name;
  305. ph->addr_info_cb (ph->addr_info_cb_cls,
  306. &address,
  307. addr_active,
  308. pi->bandwidth_out,
  309. pi->bandwidth_in,
  310. &prop);
  311. }
  312. /**
  313. * We received a reservation result message. Validate and process it.
  314. *
  315. * @param cls our context with the callback
  316. * @param rr the message
  317. */
  318. static void
  319. handle_reservation_result (void *cls,
  320. const struct ReservationResultMessage *rr)
  321. {
  322. struct GNUNET_ATS_PerformanceHandle *ph = cls;
  323. struct GNUNET_ATS_ReservationContext *rc;
  324. int32_t amount;
  325. amount = ntohl (rr->amount);
  326. rc = ph->reservation_head;
  327. if (0 != memcmp (&rr->peer,
  328. &rc->peer,
  329. sizeof(struct GNUNET_PeerIdentity)))
  330. {
  331. GNUNET_break(0);
  332. reconnect (ph);
  333. return;
  334. }
  335. GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
  336. ph->reservation_tail,
  337. rc);
  338. if ( (0 == amount) ||
  339. (NULL != rc->rcb) )
  340. {
  341. /* tell client if not cancelled */
  342. if (NULL != rc->rcb)
  343. rc->rcb (rc->rcb_cls,
  344. &rr->peer,
  345. amount,
  346. GNUNET_TIME_relative_ntoh (rr->res_delay));
  347. GNUNET_free (rc);
  348. return;
  349. }
  350. /* amount non-zero, but client cancelled, consider undo! */
  351. if (GNUNET_YES != rc->undo)
  352. {
  353. GNUNET_free (rc);
  354. return; /* do not try to undo failed undos or negative amounts */
  355. }
  356. GNUNET_free (rc);
  357. (void) GNUNET_ATS_reserve_bandwidth (ph,
  358. &rr->peer,
  359. -amount,
  360. NULL, NULL);
  361. }
  362. /**
  363. * We received a PeerInformationMessage. Validate it.
  364. *
  365. * @param cls our context with the callback
  366. * @param pi the message
  367. * @return #GNUNET_OK if the message was well-formed
  368. */
  369. static int
  370. check_address_list (void *cls,
  371. const struct PeerInformationMessage *pi)
  372. {
  373. const char *plugin_address;
  374. const char *plugin_name;
  375. uint16_t plugin_address_length;
  376. uint16_t plugin_name_length;
  377. plugin_address_length = ntohs (pi->address_length);
  378. plugin_name_length = ntohs (pi->plugin_name_length);
  379. plugin_address = (const char *) &pi[1];
  380. plugin_name = &plugin_address[plugin_address_length];
  381. if ( (plugin_address_length + plugin_name_length
  382. + sizeof (struct PeerInformationMessage) != ntohs (pi->header.size)) ||
  383. (plugin_name[plugin_name_length - 1] != '\0') )
  384. {
  385. GNUNET_break(0);
  386. return GNUNET_SYSERR;
  387. }
  388. return GNUNET_OK;
  389. }
  390. /**
  391. * We received a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE.
  392. * Process it.
  393. *
  394. * @param cls our context with the callback
  395. * @param pi the message
  396. */
  397. static void
  398. handle_address_list (void *cls,
  399. const struct PeerInformationMessage *pi)
  400. {
  401. struct GNUNET_ATS_PerformanceHandle *ph = cls;
  402. struct GNUNET_ATS_AddressListHandle *alh;
  403. struct GNUNET_ATS_AddressListHandle *next;
  404. const char *plugin_address;
  405. const char *plugin_name;
  406. struct GNUNET_HELLO_Address address;
  407. struct GNUNET_PeerIdentity allzeros;
  408. struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
  409. struct GNUNET_ATS_Properties prop;
  410. uint16_t plugin_address_length;
  411. uint16_t plugin_name_length;
  412. uint32_t active;
  413. uint32_t id;
  414. id = ntohl (pi->id);
  415. active = ntohl (pi->address_active);
  416. plugin_address_length = ntohs (pi->address_length);
  417. plugin_name_length = ntohs (pi->plugin_name_length);
  418. plugin_address = (const char *) &pi[1];
  419. plugin_name = &plugin_address[plugin_address_length];
  420. LOG (GNUNET_ERROR_TYPE_DEBUG,
  421. "Received ATS_ADDRESSLIST_RESPONSE message for peer %s and plugin %s\n",
  422. GNUNET_i2s (&pi->peer),
  423. plugin_name);
  424. next = ph->addresslist_head;
  425. while (NULL != (alh = next))
  426. {
  427. next = alh->next;
  428. if (alh->id == id)
  429. break;
  430. }
  431. if (NULL == alh)
  432. return; /* was canceled */
  433. memset (&allzeros, '\0', sizeof (allzeros));
  434. if ( (0 == memcmp (&allzeros, &pi->peer, sizeof(allzeros))) &&
  435. (0 == plugin_name_length) &&
  436. (0 == plugin_address_length) )
  437. {
  438. /* Done */
  439. LOG (GNUNET_ERROR_TYPE_DEBUG,
  440. "Received last message for ATS_ADDRESSLIST_RESPONSE\n");
  441. bandwidth_zero.value__ = htonl (0);
  442. GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
  443. ph->addresslist_tail,
  444. alh);
  445. if (NULL != alh->cb)
  446. alh->cb (alh->cb_cls,
  447. NULL,
  448. GNUNET_NO,
  449. bandwidth_zero,
  450. bandwidth_zero,
  451. NULL);
  452. GNUNET_free (alh);
  453. return;
  454. }
  455. address.peer = pi->peer;
  456. address.address = plugin_address;
  457. address.address_length = plugin_address_length;
  458. address.transport_name = plugin_name;
  459. if ( ( (GNUNET_YES == alh->all_addresses) ||
  460. (GNUNET_YES == active) ) &&
  461. (NULL != alh->cb) )
  462. {
  463. GNUNET_ATS_properties_ntoh (&prop,
  464. &pi->properties);
  465. alh->cb (alh->cb_cls,
  466. &address,
  467. active,
  468. pi->bandwidth_out,
  469. pi->bandwidth_in,
  470. &prop);
  471. }
  472. }
  473. /**
  474. * Generic error handler, called with the appropriate error code and
  475. * the same closure specified at the creation of the message queue.
  476. * Not every message queue implementation supports an error handler.
  477. *
  478. * @param cls closure with the `struct GNUNET_ATS_PerformanceHandle *`
  479. * @param error error code
  480. */
  481. static void
  482. mq_error_handler (void *cls,
  483. enum GNUNET_MQ_Error error)
  484. {
  485. struct GNUNET_ATS_PerformanceHandle *ph = cls;
  486. do_reconnect (ph);
  487. }
  488. /**
  489. * Re-establish the connection to the ATS service.
  490. *
  491. * @param ph handle to use to re-connect.
  492. */
  493. static void
  494. reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
  495. {
  496. struct GNUNET_MQ_MessageHandler handlers[] = {
  497. GNUNET_MQ_hd_var_size (peer_information,
  498. GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION,
  499. struct PeerInformationMessage,
  500. ph),
  501. GNUNET_MQ_hd_fixed_size (reservation_result,
  502. GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT,
  503. struct ReservationResultMessage,
  504. ph),
  505. GNUNET_MQ_hd_var_size (address_list,
  506. GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE,
  507. struct PeerInformationMessage,
  508. ph),
  509. GNUNET_MQ_handler_end ()
  510. };
  511. struct GNUNET_MQ_Envelope *env;
  512. struct ClientStartMessage *init;
  513. GNUNET_assert (NULL == ph->mq);
  514. ph->mq = GNUNET_CLIENT_connect (ph->cfg,
  515. "ats",
  516. handlers,
  517. &mq_error_handler,
  518. ph);
  519. if (NULL == ph->mq)
  520. return;
  521. env = GNUNET_MQ_msg (init,
  522. GNUNET_MESSAGE_TYPE_ATS_START);
  523. init->start_flag = htonl ( (NULL == ph->addr_info_cb)
  524. ? START_FLAG_PERFORMANCE_NO_PIC
  525. : START_FLAG_PERFORMANCE_WITH_PIC);
  526. GNUNET_MQ_send (ph->mq,
  527. env);
  528. }
  529. /**
  530. * Get handle to access performance API of the ATS subsystem.
  531. *
  532. * @param cfg configuration to use
  533. * @param addr_info_cb callback called when performance characteristics for
  534. * an address change
  535. * @param addr_info_cb_cls closure for @a addr_info_cb
  536. * @return ats performance context
  537. */
  538. struct GNUNET_ATS_PerformanceHandle *
  539. GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
  540. GNUNET_ATS_AddressInformationCallback addr_info_cb,
  541. void *addr_info_cb_cls)
  542. {
  543. struct GNUNET_ATS_PerformanceHandle *ph;
  544. ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle);
  545. ph->cfg = cfg;
  546. ph->addr_info_cb = addr_info_cb;
  547. ph->addr_info_cb_cls = addr_info_cb_cls;
  548. reconnect (ph);
  549. if (NULL == ph->mq)
  550. {
  551. GNUNET_free (ph);
  552. return NULL;
  553. }
  554. return ph;
  555. }
  556. /**
  557. * Client is done using the ATS performance subsystem, release resources.
  558. *
  559. * @param ph handle
  560. */
  561. void
  562. GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
  563. {
  564. struct GNUNET_ATS_ReservationContext *rc;
  565. struct GNUNET_ATS_AddressListHandle *alh;
  566. while (NULL != (alh = ph->addresslist_head))
  567. {
  568. GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
  569. ph->addresslist_tail,
  570. alh);
  571. GNUNET_free (alh);
  572. }
  573. while (NULL != (rc = ph->reservation_head))
  574. {
  575. GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
  576. ph->reservation_tail,
  577. rc);
  578. GNUNET_break (NULL == rc->rcb);
  579. GNUNET_free (rc);
  580. }
  581. if (NULL != ph->task)
  582. {
  583. GNUNET_SCHEDULER_cancel (ph->task);
  584. ph->task = NULL;
  585. }
  586. if (NULL != ph->mq)
  587. {
  588. GNUNET_MQ_destroy (ph->mq);
  589. ph->mq = NULL;
  590. }
  591. GNUNET_free (ph);
  592. }
  593. /**
  594. * Reserve inbound bandwidth from the given peer. ATS will look at
  595. * the current amount of traffic we receive from the peer and ensure
  596. * that the peer could add @a amount of data to its stream.
  597. *
  598. * @param ph performance handle
  599. * @param peer identifies the peer
  600. * @param amount reserve N bytes for receiving, negative
  601. * amounts can be used to undo a (recent) reservation;
  602. * @param rcb function to call with the resulting reservation information
  603. * @param rcb_cls closure for @a rcb
  604. * @return NULL on error
  605. * @deprecated will be replaced soon
  606. */
  607. struct GNUNET_ATS_ReservationContext *
  608. GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
  609. const struct GNUNET_PeerIdentity *peer,
  610. int32_t amount,
  611. GNUNET_ATS_ReservationCallback rcb,
  612. void *rcb_cls)
  613. {
  614. struct GNUNET_ATS_ReservationContext *rc;
  615. struct GNUNET_MQ_Envelope *env;
  616. struct ReservationRequestMessage *m;
  617. if (NULL == ph->mq)
  618. return NULL;
  619. rc = GNUNET_new (struct GNUNET_ATS_ReservationContext);
  620. rc->size = amount;
  621. rc->peer = *peer;
  622. rc->rcb = rcb;
  623. rc->rcb_cls = rcb_cls;
  624. if ( (NULL != rcb) &&
  625. (amount > 0) )
  626. rc->undo = GNUNET_YES;
  627. GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head,
  628. ph->reservation_tail,
  629. rc);
  630. env = GNUNET_MQ_msg (m,
  631. GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
  632. m->amount = htonl (amount);
  633. m->peer = *peer;
  634. GNUNET_MQ_send (ph->mq,
  635. env);
  636. return rc;
  637. }
  638. /**
  639. * Cancel request for reserving bandwidth.
  640. *
  641. * @param rc context returned by the original #GNUNET_ATS_reserve_bandwidth() call
  642. */
  643. void
  644. GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
  645. {
  646. rc->rcb = NULL;
  647. }
  648. /**
  649. * Get information about addresses known to the ATS subsystem.
  650. *
  651. * @param ph the performance handle to use
  652. * @param peer peer idm can be NULL for all peers
  653. * @param all #GNUNET_YES to get information about all addresses or #GNUNET_NO to
  654. * get only address currently used
  655. * @param infocb callback to call with the addresses,
  656. * will callback with address == NULL when done
  657. * @param infocb_cls closure for @a infocb
  658. * @return ats performance context
  659. */
  660. struct GNUNET_ATS_AddressListHandle*
  661. GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *ph,
  662. const struct GNUNET_PeerIdentity *peer,
  663. int all,
  664. GNUNET_ATS_AddressInformationCallback infocb,
  665. void *infocb_cls)
  666. {
  667. struct GNUNET_ATS_AddressListHandle *alh;
  668. struct GNUNET_MQ_Envelope *env;
  669. struct AddressListRequestMessage *m;
  670. if (NULL == ph->mq)
  671. return NULL;
  672. if (NULL == infocb)
  673. {
  674. GNUNET_break (0);
  675. return NULL;
  676. }
  677. alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle);
  678. alh->id = ph->id++;
  679. alh->cb = infocb;
  680. alh->cb_cls = infocb_cls;
  681. alh->ph = ph;
  682. alh->all_addresses = all;
  683. if (NULL == peer)
  684. {
  685. alh->all_peers = GNUNET_YES;
  686. }
  687. else
  688. {
  689. alh->all_peers = GNUNET_NO;
  690. alh->peer = *peer;
  691. }
  692. GNUNET_CONTAINER_DLL_insert (ph->addresslist_head,
  693. ph->addresslist_tail,
  694. alh);
  695. env = GNUNET_MQ_msg (m,
  696. GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
  697. m->all = htonl (all);
  698. m->id = htonl (alh->id);
  699. if (NULL != peer)
  700. m->peer = *peer;
  701. GNUNET_MQ_send (ph->mq,
  702. env);
  703. return alh;
  704. }
  705. /**
  706. * Cancel a pending address listing operation
  707. *
  708. * @param alh the handle of the request to cancel
  709. */
  710. void
  711. GNUNET_ATS_performance_list_addresses_cancel (struct GNUNET_ATS_AddressListHandle *alh)
  712. {
  713. struct GNUNET_ATS_PerformanceHandle *ph = alh->ph;
  714. GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
  715. ph->addresslist_tail,
  716. alh);
  717. GNUNET_free (alh);
  718. }
  719. /**
  720. * Convert a `enum GNUNET_ATS_PreferenceType` to a string
  721. *
  722. * @param type the preference type
  723. * @return a string or NULL if invalid
  724. */
  725. const char *
  726. GNUNET_ATS_print_preference_type (enum GNUNET_ATS_PreferenceKind type)
  727. {
  728. const char *prefs[] = GNUNET_ATS_PreferenceTypeString;
  729. if (type < GNUNET_ATS_PREFERENCE_END)
  730. return prefs[type];
  731. return NULL;
  732. }
  733. /**
  734. * Change preferences for the given peer. Preference changes are forgotten if peers
  735. * disconnect.
  736. *
  737. * @param ph performance handle
  738. * @param peer identifies the peer
  739. * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes
  740. */
  741. void
  742. GNUNET_ATS_performance_change_preference (struct GNUNET_ATS_PerformanceHandle *ph,
  743. const struct GNUNET_PeerIdentity *peer,
  744. ...)
  745. {
  746. struct GNUNET_MQ_Envelope *env;
  747. struct ChangePreferenceMessage *m;
  748. uint32_t count;
  749. struct PreferenceInformation *pi;
  750. va_list ap;
  751. enum GNUNET_ATS_PreferenceKind kind;
  752. if (NULL == ph->mq)
  753. return;
  754. count = 0;
  755. va_start(ap, peer);
  756. while (GNUNET_ATS_PREFERENCE_END !=
  757. (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind) ))
  758. {
  759. switch (kind)
  760. {
  761. case GNUNET_ATS_PREFERENCE_BANDWIDTH:
  762. count++;
  763. (void) va_arg (ap, double);
  764. break;
  765. case GNUNET_ATS_PREFERENCE_LATENCY:
  766. count++;
  767. (void) va_arg (ap, double);
  768. break;
  769. default:
  770. GNUNET_assert(0);
  771. }
  772. }
  773. va_end(ap);
  774. env = GNUNET_MQ_msg_extra (m,
  775. count * sizeof(struct PreferenceInformation),
  776. GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
  777. m->num_preferences = htonl (count);
  778. m->peer = *peer;
  779. pi = (struct PreferenceInformation *) &m[1];
  780. count = 0;
  781. va_start(ap, peer);
  782. while (GNUNET_ATS_PREFERENCE_END != (kind =
  783. GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind) ))
  784. {
  785. pi[count].preference_kind = htonl (kind);
  786. switch (kind)
  787. {
  788. case GNUNET_ATS_PREFERENCE_BANDWIDTH:
  789. pi[count].preference_value = (float) va_arg (ap, double);
  790. count++;
  791. break;
  792. case GNUNET_ATS_PREFERENCE_LATENCY:
  793. pi[count].preference_value = (float) va_arg (ap, double);
  794. count++;
  795. break;
  796. default:
  797. GNUNET_assert(0);
  798. }
  799. }
  800. va_end(ap);
  801. GNUNET_MQ_send (ph->mq,
  802. env);
  803. }
  804. /**
  805. * Send feedback to ATS on how good a the requirements for a peer and a
  806. * preference is satisfied by ATS
  807. *
  808. * @param ph performance handle
  809. * @param scope the time interval this valid for: [now - scope .. now]
  810. * @param peer identifies the peer
  811. * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes
  812. */
  813. void
  814. GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
  815. const struct GNUNET_PeerIdentity *peer,
  816. const struct GNUNET_TIME_Relative scope,
  817. ...)
  818. {
  819. struct GNUNET_MQ_Envelope *env;
  820. struct FeedbackPreferenceMessage *m;
  821. uint32_t count;
  822. struct PreferenceInformation *pi;
  823. va_list ap;
  824. enum GNUNET_ATS_PreferenceKind kind;
  825. if (NULL == ph->mq)
  826. return;
  827. count = 0;
  828. va_start(ap, scope);
  829. while (GNUNET_ATS_PREFERENCE_END !=
  830. (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind) ))
  831. {
  832. switch (kind)
  833. {
  834. case GNUNET_ATS_PREFERENCE_BANDWIDTH:
  835. count++;
  836. (void) va_arg (ap, double);
  837. break;
  838. case GNUNET_ATS_PREFERENCE_LATENCY:
  839. count++;
  840. (void) va_arg (ap, double);
  841. break;
  842. default:
  843. GNUNET_assert(0);
  844. }
  845. }
  846. va_end(ap);
  847. env = GNUNET_MQ_msg_extra (m,
  848. count * sizeof(struct PreferenceInformation),
  849. GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK);
  850. m->scope = GNUNET_TIME_relative_hton (scope);
  851. m->num_feedback = htonl (count);
  852. m->peer = *peer;
  853. pi = (struct PreferenceInformation *) &m[1];
  854. count = 0;
  855. va_start(ap, scope);
  856. while (GNUNET_ATS_PREFERENCE_END != (kind =
  857. GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind) ))
  858. {
  859. pi[count].preference_kind = htonl (kind);
  860. switch (kind)
  861. {
  862. case GNUNET_ATS_PREFERENCE_BANDWIDTH:
  863. pi[count].preference_value = (float) va_arg (ap, double);
  864. count++;
  865. break;
  866. case GNUNET_ATS_PREFERENCE_LATENCY:
  867. pi[count].preference_value = (float) va_arg (ap, double);
  868. count++;
  869. break;
  870. default:
  871. GNUNET_assert(0);
  872. }
  873. }
  874. va_end(ap);
  875. GNUNET_MQ_send (ph->mq,
  876. env);
  877. }
  878. /* end of ats_api_performance.c */