dv_api.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009--2013 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 dv/dv_api.c
  19. * @brief library to access the DV service
  20. * @author Christian Grothoff
  21. * @author Nathan Evans
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_dv_service.h"
  26. #include "gnunet_protocols.h"
  27. #include "dv.h"
  28. #include "gnunet_transport_plugin.h"
  29. #define LOG(kind,...) GNUNET_log_from (kind, "dv-api",__VA_ARGS__)
  30. /**
  31. * Information we track for each peer.
  32. */
  33. struct ConnectedPeer;
  34. /**
  35. * Handle for a send operation.
  36. */
  37. struct GNUNET_DV_TransmitHandle
  38. {
  39. /**
  40. * Kept in a DLL.
  41. */
  42. struct GNUNET_DV_TransmitHandle *next;
  43. /**
  44. * Kept in a DLL.
  45. */
  46. struct GNUNET_DV_TransmitHandle *prev;
  47. /**
  48. * Handle to the service.
  49. */
  50. struct GNUNET_DV_ServiceHandle *sh;
  51. /**
  52. * Function to call upon completion.
  53. */
  54. GNUNET_DV_MessageSentCallback cb;
  55. /**
  56. * Closure for @a cb.
  57. */
  58. void *cb_cls;
  59. /**
  60. * The actual message (allocated at the end of this struct).
  61. */
  62. const struct GNUNET_MessageHeader *msg;
  63. /**
  64. * Destination for the message.
  65. */
  66. struct ConnectedPeer *target;
  67. /**
  68. * UID of our message, if any.
  69. */
  70. uint32_t uid;
  71. };
  72. /**
  73. * Information we track for each peer.
  74. */
  75. struct ConnectedPeer
  76. {
  77. /**
  78. * Identity of the peer.
  79. */
  80. struct GNUNET_PeerIdentity pid;
  81. /**
  82. * Head of DLL of transmission handles where we need
  83. * to invoke a continuation when we are informed about
  84. * successful transmission. The respective request
  85. * has already been sent to the DV service.
  86. */
  87. struct GNUNET_DV_TransmitHandle *head;
  88. /**
  89. * Tail of DLL of transmission handles where we need
  90. * to invoke a continuation when we are informed about
  91. * successful transmission. The respective request
  92. * has already been sent to the DV service.
  93. */
  94. struct GNUNET_DV_TransmitHandle *tail;
  95. };
  96. /**
  97. * Handle to the DV service.
  98. */
  99. struct GNUNET_DV_ServiceHandle
  100. {
  101. /**
  102. * Connection to DV service.
  103. */
  104. struct GNUNET_CLIENT_Connection *client;
  105. /**
  106. * Active request for transmission to DV service.
  107. */
  108. struct GNUNET_CLIENT_TransmitHandle *th;
  109. /**
  110. * Our configuration.
  111. */
  112. const struct GNUNET_CONFIGURATION_Handle *cfg;
  113. /**
  114. * Closure for the callbacks.
  115. */
  116. void *cls;
  117. /**
  118. * Function to call on connect events.
  119. */
  120. GNUNET_DV_ConnectCallback connect_cb;
  121. /**
  122. * Function to call on distance change events.
  123. */
  124. GNUNET_DV_DistanceChangedCallback distance_cb;
  125. /**
  126. * Function to call on disconnect events.
  127. */
  128. GNUNET_DV_DisconnectCallback disconnect_cb;
  129. /**
  130. * Function to call on receiving messages events.
  131. */
  132. GNUNET_DV_MessageReceivedCallback message_cb;
  133. /**
  134. * Head of messages to transmit.
  135. */
  136. struct GNUNET_DV_TransmitHandle *th_head;
  137. /**
  138. * Tail of messages to transmit.
  139. */
  140. struct GNUNET_DV_TransmitHandle *th_tail;
  141. /**
  142. * Information tracked per connected peer. Maps peer
  143. * identities to `struct ConnectedPeer` entries.
  144. */
  145. struct GNUNET_CONTAINER_MultiPeerMap *peers;
  146. /**
  147. * Current unique ID
  148. */
  149. uint32_t uid_gen;
  150. };
  151. /**
  152. * Disconnect and then reconnect to the DV service.
  153. *
  154. * @param sh service handle
  155. */
  156. static void
  157. reconnect (struct GNUNET_DV_ServiceHandle *sh);
  158. /**
  159. * Start sending messages from our queue to the service.
  160. *
  161. * @param sh service handle
  162. */
  163. static void
  164. start_transmit (struct GNUNET_DV_ServiceHandle *sh);
  165. /**
  166. * Gives a message from our queue to the DV service.
  167. *
  168. * @param cls handle to the dv service (`struct GNUNET_DV_ServiceHandle`)
  169. * @param size how many bytes can we send
  170. * @param buf where to copy the message to send
  171. * @return how many bytes we copied to @a buf
  172. */
  173. static size_t
  174. transmit_pending (void *cls, size_t size, void *buf)
  175. {
  176. struct GNUNET_DV_ServiceHandle *sh = cls;
  177. char *cbuf = buf;
  178. struct GNUNET_DV_TransmitHandle *th;
  179. size_t ret;
  180. size_t tsize;
  181. sh->th = NULL;
  182. if (NULL == buf)
  183. {
  184. reconnect (sh);
  185. return 0;
  186. }
  187. ret = 0;
  188. while ( (NULL != (th = sh->th_head)) &&
  189. (size - ret >= (tsize = ntohs (th->msg->size)) ))
  190. {
  191. GNUNET_CONTAINER_DLL_remove (sh->th_head,
  192. sh->th_tail,
  193. th);
  194. memcpy (&cbuf[ret], th->msg, tsize);
  195. LOG (GNUNET_ERROR_TYPE_DEBUG,
  196. "Passing %u bytes of type %u to DV service\n",
  197. tsize,
  198. ntohs (th->msg->type));
  199. th->msg = NULL;
  200. ret += tsize;
  201. if (NULL != th->cb)
  202. {
  203. GNUNET_CONTAINER_DLL_insert_tail (th->target->head,
  204. th->target->tail,
  205. th);
  206. }
  207. else
  208. {
  209. GNUNET_free (th);
  210. }
  211. }
  212. if (NULL != sh->th_head)
  213. start_transmit (sh);
  214. return ret;
  215. }
  216. /**
  217. * Start sending messages from our queue to the service.
  218. *
  219. * @param sh service handle
  220. */
  221. static void
  222. start_transmit (struct GNUNET_DV_ServiceHandle *sh)
  223. {
  224. if (NULL != sh->th)
  225. return;
  226. if (NULL == sh->th_head)
  227. return;
  228. sh->th =
  229. GNUNET_CLIENT_notify_transmit_ready (sh->client,
  230. ntohs (sh->th_head->msg->size),
  231. GNUNET_TIME_UNIT_FOREVER_REL,
  232. GNUNET_NO,
  233. &transmit_pending, sh);
  234. }
  235. /**
  236. * We got disconnected from the service and thus all of the
  237. * pending send callbacks will never be confirmed. Clean up.
  238. *
  239. * @param cls the 'struct GNUNET_DV_ServiceHandle'
  240. * @param key a peer identity
  241. * @param value a `struct ConnectedPeer` to clean up
  242. * @return #GNUNET_OK (continue to iterate)
  243. */
  244. static int
  245. cleanup_send_cb (void *cls,
  246. const struct GNUNET_PeerIdentity *key,
  247. void *value)
  248. {
  249. struct GNUNET_DV_ServiceHandle *sh = cls;
  250. struct ConnectedPeer *peer = value;
  251. struct GNUNET_DV_TransmitHandle *th;
  252. GNUNET_assert (GNUNET_YES ==
  253. GNUNET_CONTAINER_multipeermap_remove (sh->peers,
  254. key,
  255. peer));
  256. sh->disconnect_cb (sh->cls,
  257. key);
  258. while (NULL != (th = peer->head))
  259. {
  260. GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, th);
  261. th->cb (th->cb_cls, GNUNET_SYSERR);
  262. GNUNET_free (th);
  263. }
  264. GNUNET_free (peer);
  265. return GNUNET_OK;
  266. }
  267. /**
  268. * Handles a message sent from the DV service to us.
  269. * Parse it out and give it to the plugin.
  270. *
  271. * @param cls the handle to the DV API
  272. * @param msg the message that was received
  273. */
  274. static void
  275. handle_message_receipt (void *cls,
  276. const struct GNUNET_MessageHeader *msg)
  277. {
  278. struct GNUNET_DV_ServiceHandle *sh = cls;
  279. const struct GNUNET_DV_ConnectMessage *cm;
  280. const struct GNUNET_DV_DistanceUpdateMessage *dum;
  281. const struct GNUNET_DV_DisconnectMessage *dm;
  282. const struct GNUNET_DV_ReceivedMessage *rm;
  283. const struct GNUNET_MessageHeader *payload;
  284. const struct GNUNET_DV_AckMessage *ack;
  285. struct GNUNET_DV_TransmitHandle *th;
  286. struct GNUNET_DV_TransmitHandle *tn;
  287. struct ConnectedPeer *peer;
  288. if (NULL == msg)
  289. {
  290. /* Connection closed */
  291. reconnect (sh);
  292. return;
  293. }
  294. LOG (GNUNET_ERROR_TYPE_DEBUG,
  295. "Received message of type %u with %u bytes from DV service\n",
  296. (unsigned int) ntohs (msg->type),
  297. (unsigned int) ntohs (msg->size));
  298. switch (ntohs (msg->type))
  299. {
  300. case GNUNET_MESSAGE_TYPE_DV_CONNECT:
  301. if (ntohs (msg->size) != sizeof (struct GNUNET_DV_ConnectMessage))
  302. {
  303. GNUNET_break (0);
  304. reconnect (sh);
  305. return;
  306. }
  307. cm = (const struct GNUNET_DV_ConnectMessage *) msg;
  308. peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
  309. &cm->peer);
  310. if (NULL != peer)
  311. {
  312. GNUNET_break (0);
  313. reconnect (sh);
  314. return;
  315. }
  316. peer = GNUNET_new (struct ConnectedPeer);
  317. peer->pid = cm->peer;
  318. GNUNET_assert (GNUNET_OK ==
  319. GNUNET_CONTAINER_multipeermap_put (sh->peers,
  320. &peer->pid,
  321. peer,
  322. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  323. sh->connect_cb (sh->cls,
  324. &cm->peer,
  325. ntohl (cm->distance),
  326. (enum GNUNET_ATS_Network_Type) ntohl (cm->network));
  327. break;
  328. case GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED:
  329. if (ntohs (msg->size) != sizeof (struct GNUNET_DV_DistanceUpdateMessage))
  330. {
  331. GNUNET_break (0);
  332. reconnect (sh);
  333. return;
  334. }
  335. dum = (const struct GNUNET_DV_DistanceUpdateMessage *) msg;
  336. sh->distance_cb (sh->cls,
  337. &dum->peer,
  338. ntohl (dum->distance),
  339. (enum GNUNET_ATS_Network_Type) ntohl (dum->network));
  340. break;
  341. case GNUNET_MESSAGE_TYPE_DV_DISCONNECT:
  342. if (ntohs (msg->size) != sizeof (struct GNUNET_DV_DisconnectMessage))
  343. {
  344. GNUNET_break (0);
  345. reconnect (sh);
  346. return;
  347. }
  348. dm = (const struct GNUNET_DV_DisconnectMessage *) msg;
  349. peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
  350. &dm->peer);
  351. if (NULL == peer)
  352. {
  353. GNUNET_break (0);
  354. reconnect (sh);
  355. return;
  356. }
  357. tn = sh->th_head;
  358. while (NULL != (th = tn))
  359. {
  360. tn = th->next;
  361. if (peer == th->target)
  362. {
  363. GNUNET_CONTAINER_DLL_remove (sh->th_head,
  364. sh->th_tail,
  365. th);
  366. th->cb (th->cb_cls, GNUNET_SYSERR);
  367. GNUNET_free (th);
  368. }
  369. }
  370. cleanup_send_cb (sh, &dm->peer, peer);
  371. break;
  372. case GNUNET_MESSAGE_TYPE_DV_RECV:
  373. if (ntohs (msg->size) < sizeof (struct GNUNET_DV_ReceivedMessage) + sizeof (struct GNUNET_MessageHeader))
  374. {
  375. GNUNET_break (0);
  376. reconnect (sh);
  377. return;
  378. }
  379. rm = (const struct GNUNET_DV_ReceivedMessage *) msg;
  380. payload = (const struct GNUNET_MessageHeader *) &rm[1];
  381. if (ntohs (msg->size) != sizeof (struct GNUNET_DV_ReceivedMessage) + ntohs (payload->size))
  382. {
  383. GNUNET_break (0);
  384. reconnect (sh);
  385. return;
  386. }
  387. if (NULL ==
  388. GNUNET_CONTAINER_multipeermap_get (sh->peers,
  389. &rm->sender))
  390. {
  391. GNUNET_break (0);
  392. reconnect (sh);
  393. return;
  394. }
  395. sh->message_cb (sh->cls,
  396. &rm->sender,
  397. ntohl (rm->distance),
  398. payload);
  399. break;
  400. case GNUNET_MESSAGE_TYPE_DV_SEND_ACK:
  401. case GNUNET_MESSAGE_TYPE_DV_SEND_NACK:
  402. if (ntohs (msg->size) != sizeof (struct GNUNET_DV_AckMessage))
  403. {
  404. GNUNET_break (0);
  405. reconnect (sh);
  406. return;
  407. }
  408. ack = (const struct GNUNET_DV_AckMessage *) msg;
  409. peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
  410. &ack->target);
  411. if (NULL == peer)
  412. break; /* this happens, just ignore */
  413. for (th = peer->head; NULL != th; th = th->next)
  414. {
  415. if (th->uid != ntohl (ack->uid))
  416. continue;
  417. LOG (GNUNET_ERROR_TYPE_DEBUG,
  418. "Matched ACK for message to peer %s\n",
  419. GNUNET_i2s (&ack->target));
  420. GNUNET_CONTAINER_DLL_remove (peer->head,
  421. peer->tail,
  422. th);
  423. th->cb (th->cb_cls,
  424. (ntohs (ack->header.type) == GNUNET_MESSAGE_TYPE_DV_SEND_ACK)
  425. ? GNUNET_OK
  426. : GNUNET_SYSERR);
  427. GNUNET_free (th);
  428. break;
  429. }
  430. break;
  431. default:
  432. reconnect (sh);
  433. break;
  434. }
  435. LOG (GNUNET_ERROR_TYPE_DEBUG,
  436. "Received message, continuing receive loop for %p\n",
  437. sh->client);
  438. GNUNET_CLIENT_receive (sh->client,
  439. &handle_message_receipt, sh,
  440. GNUNET_TIME_UNIT_FOREVER_REL);
  441. }
  442. /**
  443. * Transmit the start message to the DV service.
  444. *
  445. * @param cls the `struct GNUNET_DV_ServiceHandle *`
  446. * @param size number of bytes available in buf
  447. * @param buf where to copy the message
  448. * @return number of bytes written to buf
  449. */
  450. static size_t
  451. transmit_start (void *cls,
  452. size_t size,
  453. void *buf)
  454. {
  455. struct GNUNET_DV_ServiceHandle *sh = cls;
  456. struct GNUNET_MessageHeader start_message;
  457. sh->th = NULL;
  458. if (NULL == buf)
  459. {
  460. GNUNET_break (0);
  461. reconnect (sh);
  462. return 0;
  463. }
  464. GNUNET_assert (size >= sizeof (start_message));
  465. start_message.size = htons (sizeof (struct GNUNET_MessageHeader));
  466. start_message.type = htons (GNUNET_MESSAGE_TYPE_DV_START);
  467. memcpy (buf, &start_message, sizeof (start_message));
  468. LOG (GNUNET_ERROR_TYPE_DEBUG,
  469. "Transmitting START request, starting receive loop for %p\n",
  470. sh->client);
  471. GNUNET_CLIENT_receive (sh->client,
  472. &handle_message_receipt, sh,
  473. GNUNET_TIME_UNIT_FOREVER_REL);
  474. start_transmit (sh);
  475. return sizeof (start_message);
  476. }
  477. /**
  478. * Disconnect and then reconnect to the DV service.
  479. *
  480. * @param sh service handle
  481. */
  482. static void
  483. reconnect (struct GNUNET_DV_ServiceHandle *sh)
  484. {
  485. if (NULL != sh->th)
  486. {
  487. GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
  488. sh->th = NULL;
  489. }
  490. LOG (GNUNET_ERROR_TYPE_DEBUG,
  491. "Disconnecting from DV service at %p\n",
  492. sh->client);
  493. if (NULL != sh->client)
  494. {
  495. GNUNET_CLIENT_disconnect (sh->client);
  496. sh->client = NULL;
  497. }
  498. GNUNET_CONTAINER_multipeermap_iterate (sh->peers,
  499. &cleanup_send_cb,
  500. sh);
  501. LOG (GNUNET_ERROR_TYPE_DEBUG,
  502. "Connecting to DV service\n");
  503. sh->client = GNUNET_CLIENT_connect ("dv", sh->cfg);
  504. if (NULL == sh->client)
  505. {
  506. GNUNET_break (0);
  507. return;
  508. }
  509. sh->th = GNUNET_CLIENT_notify_transmit_ready (sh->client,
  510. sizeof (struct GNUNET_MessageHeader),
  511. GNUNET_TIME_UNIT_FOREVER_REL,
  512. GNUNET_YES,
  513. &transmit_start,
  514. sh);
  515. }
  516. /**
  517. * Connect to the DV service.
  518. *
  519. * @param cfg configuration
  520. * @param cls closure for callbacks
  521. * @param connect_cb function to call on connects
  522. * @param distance_cb function to call if distances change
  523. * @param disconnect_cb function to call on disconnects
  524. * @param message_cb function to call if we receive messages
  525. * @return handle to access the service
  526. */
  527. struct GNUNET_DV_ServiceHandle *
  528. GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  529. void *cls,
  530. GNUNET_DV_ConnectCallback connect_cb,
  531. GNUNET_DV_DistanceChangedCallback distance_cb,
  532. GNUNET_DV_DisconnectCallback disconnect_cb,
  533. GNUNET_DV_MessageReceivedCallback message_cb)
  534. {
  535. struct GNUNET_DV_ServiceHandle *sh;
  536. sh = GNUNET_new (struct GNUNET_DV_ServiceHandle);
  537. sh->cfg = cfg;
  538. sh->cls = cls;
  539. sh->connect_cb = connect_cb;
  540. sh->distance_cb = distance_cb;
  541. sh->disconnect_cb = disconnect_cb;
  542. sh->message_cb = message_cb;
  543. sh->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
  544. reconnect (sh);
  545. return sh;
  546. }
  547. /**
  548. * Disconnect from DV service.
  549. *
  550. * @param sh service handle
  551. */
  552. void
  553. GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh)
  554. {
  555. struct GNUNET_DV_TransmitHandle *pos;
  556. if (NULL == sh)
  557. return;
  558. if (NULL != sh->th)
  559. {
  560. GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
  561. sh->th = NULL;
  562. }
  563. while (NULL != (pos = sh->th_head))
  564. {
  565. GNUNET_CONTAINER_DLL_remove (sh->th_head,
  566. sh->th_tail,
  567. pos);
  568. GNUNET_free (pos);
  569. }
  570. if (NULL != sh->client)
  571. {
  572. GNUNET_CLIENT_disconnect (sh->client);
  573. sh->client = NULL;
  574. }
  575. GNUNET_CONTAINER_multipeermap_iterate (sh->peers,
  576. &cleanup_send_cb,
  577. sh);
  578. GNUNET_CONTAINER_multipeermap_destroy (sh->peers);
  579. GNUNET_free (sh);
  580. }
  581. /**
  582. * Send a message via DV service.
  583. *
  584. * @param sh service handle
  585. * @param target intended recpient
  586. * @param msg message payload
  587. * @param cb function to invoke when done
  588. * @param cb_cls closure for @a cb
  589. * @return handle to cancel the operation
  590. */
  591. struct GNUNET_DV_TransmitHandle *
  592. GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
  593. const struct GNUNET_PeerIdentity *target,
  594. const struct GNUNET_MessageHeader *msg,
  595. GNUNET_DV_MessageSentCallback cb,
  596. void *cb_cls)
  597. {
  598. struct GNUNET_DV_TransmitHandle *th;
  599. struct GNUNET_DV_SendMessage *sm;
  600. struct ConnectedPeer *peer;
  601. if (ntohs (msg->size) + sizeof (struct GNUNET_DV_SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
  602. {
  603. GNUNET_break (0);
  604. return NULL;
  605. }
  606. LOG (GNUNET_ERROR_TYPE_DEBUG,
  607. "Asked to send %u bytes of type %u to %s via %p\n",
  608. (unsigned int) ntohs (msg->size),
  609. (unsigned int) ntohs (msg->type),
  610. GNUNET_i2s (target),
  611. sh->client);
  612. peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
  613. target);
  614. if (NULL == peer)
  615. {
  616. GNUNET_break (0);
  617. return NULL;
  618. }
  619. th = GNUNET_malloc (sizeof (struct GNUNET_DV_TransmitHandle) +
  620. sizeof (struct GNUNET_DV_SendMessage) +
  621. ntohs (msg->size));
  622. th->sh = sh;
  623. th->target = peer;
  624. th->cb = cb;
  625. th->cb_cls = cb_cls;
  626. th->msg = (const struct GNUNET_MessageHeader *) &th[1];
  627. sm = (struct GNUNET_DV_SendMessage *) &th[1];
  628. sm->header.type = htons (GNUNET_MESSAGE_TYPE_DV_SEND);
  629. sm->header.size = htons (sizeof (struct GNUNET_DV_SendMessage) +
  630. ntohs (msg->size));
  631. if (0 == sh->uid_gen)
  632. sh->uid_gen = 1;
  633. th->uid = sh->uid_gen;
  634. sm->uid = htonl (sh->uid_gen++);
  635. /* use memcpy here as 'target' may not be sufficiently aligned */
  636. memcpy (&sm->target, target, sizeof (struct GNUNET_PeerIdentity));
  637. memcpy (&sm[1], msg, ntohs (msg->size));
  638. GNUNET_CONTAINER_DLL_insert_tail (sh->th_head,
  639. sh->th_tail,
  640. th);
  641. start_transmit (sh);
  642. return th;
  643. }
  644. /**
  645. * Abort send operation (naturally, the message may have
  646. * already been transmitted; this only stops the 'cb'
  647. * from being called again).
  648. *
  649. * @param th send operation to cancel
  650. */
  651. void
  652. GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th)
  653. {
  654. struct GNUNET_DV_ServiceHandle *sh = th->sh;
  655. if (NULL == th->msg)
  656. GNUNET_CONTAINER_DLL_remove (th->target->head,
  657. th->target->tail,
  658. th);
  659. else
  660. GNUNET_CONTAINER_DLL_remove (sh->th_head,
  661. sh->th_tail,
  662. th);
  663. GNUNET_free (th);
  664. }
  665. /* end of dv_api.c */