ats_api_performance.c 28 KB

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