You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1400 lines
41 KiB

  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013 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 multicast/multicast_api.c
  18. * @brief Multicast service; implements multicast groups using CADET connections.
  19. * @author Christian Grothoff
  20. * @author Gabor X Toth
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_multicast_service.h"
  25. #include "multicast.h"
  26. #define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__)
  27. /**
  28. * Handle for a request to send a message to all multicast group members
  29. * (from the origin).
  30. */
  31. struct GNUNET_MULTICAST_OriginTransmitHandle
  32. {
  33. GNUNET_MULTICAST_OriginTransmitNotify notify;
  34. void *notify_cls;
  35. struct GNUNET_MULTICAST_Origin *origin;
  36. uint64_t message_id;
  37. uint64_t group_generation;
  38. uint64_t fragment_offset;
  39. };
  40. /**
  41. * Handle for a message to be delivered from a member to the origin.
  42. */
  43. struct GNUNET_MULTICAST_MemberTransmitHandle
  44. {
  45. GNUNET_MULTICAST_MemberTransmitNotify notify;
  46. void *notify_cls;
  47. struct GNUNET_MULTICAST_Member *member;
  48. uint64_t request_id;
  49. uint64_t fragment_offset;
  50. };
  51. struct GNUNET_MULTICAST_Group
  52. {
  53. /**
  54. * Configuration to use.
  55. */
  56. const struct GNUNET_CONFIGURATION_Handle *cfg;
  57. /**
  58. * Client connection to the service.
  59. */
  60. struct GNUNET_MQ_Handle *mq;
  61. /**
  62. * Message to send on connect.
  63. */
  64. struct GNUNET_MQ_Envelope *connect_env;
  65. /**
  66. * Time to wait until we try to reconnect on failure.
  67. */
  68. struct GNUNET_TIME_Relative reconnect_delay;
  69. /**
  70. * Task for reconnecting when the listener fails.
  71. */
  72. struct GNUNET_SCHEDULER_Task *reconnect_task;
  73. GNUNET_MULTICAST_JoinRequestCallback join_req_cb;
  74. GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
  75. GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
  76. GNUNET_MULTICAST_MessageCallback message_cb;
  77. void *cb_cls;
  78. /**
  79. * Function called after disconnected from the service.
  80. */
  81. GNUNET_ContinuationCallback disconnect_cb;
  82. /**
  83. * Closure for @a disconnect_cb.
  84. */
  85. void *disconnect_cls;
  86. /**
  87. * Are we currently transmitting a message?
  88. */
  89. uint8_t in_transmit;
  90. /**
  91. * Number of MULTICAST_FRAGMENT_ACK messages we are still waiting for.
  92. */
  93. uint8_t acks_pending;
  94. /**
  95. * Is this the origin or a member?
  96. */
  97. uint8_t is_origin;
  98. /**
  99. * Is this channel in the process of disconnecting from the service?
  100. * #GNUNET_YES or #GNUNET_NO
  101. */
  102. uint8_t is_disconnecting;
  103. };
  104. /**
  105. * Handle for the origin of a multicast group.
  106. */
  107. struct GNUNET_MULTICAST_Origin
  108. {
  109. struct GNUNET_MULTICAST_Group grp;
  110. struct GNUNET_MULTICAST_OriginTransmitHandle tmit;
  111. GNUNET_MULTICAST_RequestCallback request_cb;
  112. };
  113. /**
  114. * Handle for a multicast group member.
  115. */
  116. struct GNUNET_MULTICAST_Member
  117. {
  118. struct GNUNET_MULTICAST_Group grp;
  119. struct GNUNET_MULTICAST_MemberTransmitHandle tmit;
  120. GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb;
  121. /**
  122. * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle *
  123. */
  124. struct GNUNET_CONTAINER_MultiHashMap *replay_reqs;
  125. uint64_t next_fragment_id;
  126. };
  127. /**
  128. * Handle that identifies a join request.
  129. *
  130. * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the
  131. * corresponding calls to #GNUNET_MULTICAST_join_decision().
  132. */
  133. struct GNUNET_MULTICAST_JoinHandle
  134. {
  135. struct GNUNET_MULTICAST_Group *group;
  136. /**
  137. * Public key of the member requesting join.
  138. */
  139. struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
  140. /**
  141. * Peer identity of the member requesting join.
  142. */
  143. struct GNUNET_PeerIdentity peer;
  144. };
  145. /**
  146. * Opaque handle to a replay request from the multicast service.
  147. */
  148. struct GNUNET_MULTICAST_ReplayHandle
  149. {
  150. struct GNUNET_MULTICAST_Group *grp;
  151. struct MulticastReplayRequestMessage req;
  152. };
  153. /**
  154. * Handle for a replay request.
  155. */
  156. struct GNUNET_MULTICAST_MemberReplayHandle
  157. {
  158. };
  159. static void
  160. origin_to_all (struct GNUNET_MULTICAST_Origin *orig);
  161. static void
  162. member_to_origin (struct GNUNET_MULTICAST_Member *mem);
  163. /**
  164. * Check join request message.
  165. */
  166. static int
  167. check_group_join_request (void *cls,
  168. const struct MulticastJoinRequestMessage *jreq)
  169. {
  170. uint16_t size = ntohs (jreq->header.size);
  171. if (sizeof (*jreq) == size)
  172. return GNUNET_OK;
  173. if (sizeof (*jreq) + sizeof (struct GNUNET_MessageHeader) <= size)
  174. return GNUNET_OK;
  175. return GNUNET_SYSERR;
  176. }
  177. /**
  178. * Receive join request from service.
  179. */
  180. static void
  181. handle_group_join_request (void *cls,
  182. const struct MulticastJoinRequestMessage *jreq)
  183. {
  184. struct GNUNET_MULTICAST_Group *grp = cls;
  185. struct GNUNET_MULTICAST_JoinHandle *jh;
  186. const struct GNUNET_MessageHeader *jmsg = NULL;
  187. if (NULL == grp)
  188. {
  189. GNUNET_break (0);
  190. return;
  191. }
  192. if (NULL == grp->join_req_cb)
  193. return;
  194. if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size))
  195. jmsg = (const struct GNUNET_MessageHeader *) &jreq[1];
  196. jh = GNUNET_malloc (sizeof (*jh));
  197. jh->group = grp;
  198. jh->member_pub_key = jreq->member_pub_key;
  199. jh->peer = jreq->peer;
  200. grp->join_req_cb (grp->cb_cls, &jreq->member_pub_key, jmsg, jh);
  201. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  202. }
  203. /**
  204. * Check multicast message.
  205. */
  206. static int
  207. check_group_message (void *cls,
  208. const struct GNUNET_MULTICAST_MessageHeader *mmsg)
  209. {
  210. return GNUNET_OK;
  211. }
  212. /**
  213. * Receive multicast message from service.
  214. */
  215. static void
  216. handle_group_message (void *cls,
  217. const struct GNUNET_MULTICAST_MessageHeader *mmsg)
  218. {
  219. struct GNUNET_MULTICAST_Group *grp = cls;
  220. if (GNUNET_YES == grp->is_disconnecting)
  221. return;
  222. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  223. "Calling message callback with a message of size %u.\n",
  224. ntohs (mmsg->header.size));
  225. if (NULL != grp->message_cb)
  226. grp->message_cb (grp->cb_cls, mmsg);
  227. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  228. }
  229. /**
  230. * Receive message/request fragment acknowledgement from service.
  231. */
  232. static void
  233. handle_group_fragment_ack (void *cls,
  234. const struct GNUNET_MessageHeader *msg)
  235. {
  236. struct GNUNET_MULTICAST_Group *grp = cls;
  237. LOG (GNUNET_ERROR_TYPE_DEBUG,
  238. "%p Got fragment ACK. in_transmit=%u, acks_pending=%u\n",
  239. grp, grp->in_transmit, grp->acks_pending);
  240. if (0 == grp->acks_pending)
  241. {
  242. LOG (GNUNET_ERROR_TYPE_DEBUG,
  243. "%p Ignoring extraneous fragment ACK.\n", grp);
  244. return;
  245. }
  246. grp->acks_pending--;
  247. if (GNUNET_YES != grp->in_transmit)
  248. return;
  249. if (GNUNET_YES == grp->is_origin)
  250. origin_to_all ((struct GNUNET_MULTICAST_Origin *) grp);
  251. else
  252. member_to_origin ((struct GNUNET_MULTICAST_Member *) grp);
  253. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  254. }
  255. /**
  256. * Check unicast request.
  257. */
  258. static int
  259. check_origin_request (void *cls,
  260. const struct GNUNET_MULTICAST_RequestHeader *req)
  261. {
  262. return GNUNET_OK;
  263. }
  264. /**
  265. * Origin receives unicast request from a member.
  266. */
  267. static void
  268. handle_origin_request (void *cls,
  269. const struct GNUNET_MULTICAST_RequestHeader *req)
  270. {
  271. struct GNUNET_MULTICAST_Group *grp;
  272. struct GNUNET_MULTICAST_Origin *orig = cls;
  273. grp = &orig->grp;
  274. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  275. "Calling request callback with a request of size %u.\n",
  276. ntohs (req->header.size));
  277. if (NULL != orig->request_cb)
  278. orig->request_cb (grp->cb_cls, req);
  279. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  280. }
  281. /**
  282. * Receive multicast replay request from service.
  283. */
  284. static void
  285. handle_group_replay_request (void *cls,
  286. const struct MulticastReplayRequestMessage *rep)
  287. {
  288. struct GNUNET_MULTICAST_Group *grp = cls;
  289. if (GNUNET_YES == grp->is_disconnecting)
  290. return;
  291. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n");
  292. if (0 != rep->fragment_id)
  293. {
  294. if (NULL != grp->replay_frag_cb)
  295. {
  296. struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
  297. rh->grp = grp;
  298. rh->req = *rep;
  299. grp->replay_frag_cb (grp->cb_cls, &rep->member_pub_key,
  300. GNUNET_ntohll (rep->fragment_id),
  301. GNUNET_ntohll (rep->flags), rh);
  302. }
  303. }
  304. else if (0 != rep->message_id)
  305. {
  306. if (NULL != grp->replay_msg_cb)
  307. {
  308. struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
  309. rh->grp = grp;
  310. rh->req = *rep;
  311. grp->replay_msg_cb (grp->cb_cls, &rep->member_pub_key,
  312. GNUNET_ntohll (rep->message_id),
  313. GNUNET_ntohll (rep->fragment_offset),
  314. GNUNET_ntohll (rep->flags), rh);
  315. }
  316. }
  317. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  318. }
  319. /**
  320. * Check replay response.
  321. */
  322. static int
  323. check_member_replay_response (void *cls,
  324. const struct MulticastReplayResponseMessage *res)
  325. {
  326. uint16_t size = ntohs (res->header.size);
  327. if (sizeof (*res) == size)
  328. return GNUNET_OK;
  329. if (sizeof (*res) + sizeof (struct GNUNET_MULTICAST_MessageHeader) <= size)
  330. return GNUNET_OK;
  331. return GNUNET_SYSERR;
  332. }
  333. /**
  334. * Receive replay response from service.
  335. */
  336. static void
  337. handle_member_replay_response (void *cls,
  338. const struct MulticastReplayResponseMessage *res)
  339. {
  340. struct GNUNET_MULTICAST_Group *grp;
  341. struct GNUNET_MULTICAST_Member *mem = cls;
  342. grp = &mem->grp;
  343. if (GNUNET_YES == grp->is_disconnecting)
  344. return;
  345. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n");
  346. // FIXME: return result
  347. }
  348. /**
  349. * Check join decision.
  350. */
  351. static int
  352. check_member_join_decision (void *cls,
  353. const struct MulticastJoinDecisionMessageHeader *hdcsn)
  354. {
  355. return GNUNET_OK; // checked in handle below
  356. }
  357. /**
  358. * Member receives join decision.
  359. */
  360. static void
  361. handle_member_join_decision (void *cls,
  362. const struct MulticastJoinDecisionMessageHeader *hdcsn)
  363. {
  364. struct GNUNET_MULTICAST_Group *grp;
  365. struct GNUNET_MULTICAST_Member *mem = cls;
  366. grp = &mem->grp;
  367. const struct MulticastJoinDecisionMessage *
  368. dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
  369. uint16_t dcsn_size = ntohs (dcsn->header.size);
  370. int is_admitted = ntohl (dcsn->is_admitted);
  371. LOG (GNUNET_ERROR_TYPE_DEBUG,
  372. "%p Member got join decision from multicast: %d\n",
  373. mem, is_admitted);
  374. const struct GNUNET_MessageHeader *join_resp = NULL;
  375. uint16_t join_resp_size = 0;
  376. uint16_t relay_count = ntohl (dcsn->relay_count);
  377. const struct GNUNET_PeerIdentity *relays = NULL;
  378. uint16_t relay_size = relay_count * sizeof (*relays);
  379. if (0 < relay_count)
  380. {
  381. if (dcsn_size < sizeof (*dcsn) + relay_size)
  382. {
  383. GNUNET_break_op (0);
  384. is_admitted = GNUNET_SYSERR;
  385. }
  386. else
  387. {
  388. relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
  389. }
  390. }
  391. if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
  392. {
  393. join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size);
  394. join_resp_size = ntohs (join_resp->size);
  395. }
  396. if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
  397. {
  398. LOG (GNUNET_ERROR_TYPE_DEBUG,
  399. "Received invalid join decision message from multicast: %u < %u + %u + %u\n",
  400. dcsn_size , sizeof (*dcsn), relay_size, join_resp_size);
  401. GNUNET_break_op (0);
  402. is_admitted = GNUNET_SYSERR;
  403. }
  404. if (NULL != mem->join_dcsn_cb)
  405. mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
  406. relay_count, relays, join_resp);
  407. // FIXME:
  408. //if (GNUNET_YES != is_admitted)
  409. // GNUNET_MULTICAST_member_part (mem);
  410. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  411. }
  412. static void
  413. group_cleanup (struct GNUNET_MULTICAST_Group *grp)
  414. {
  415. if (NULL != grp->connect_env)
  416. {
  417. GNUNET_MQ_discard (grp->connect_env);
  418. grp->connect_env = NULL;
  419. }
  420. if (NULL != grp->mq)
  421. {
  422. GNUNET_MQ_destroy (grp->mq);
  423. grp->mq = NULL;
  424. }
  425. if (NULL != grp->disconnect_cb)
  426. {
  427. grp->disconnect_cb (grp->disconnect_cls);
  428. grp->disconnect_cb = NULL;
  429. }
  430. GNUNET_free (grp);
  431. }
  432. static void
  433. handle_group_part_ack (void *cls,
  434. const struct GNUNET_MessageHeader *msg)
  435. {
  436. struct GNUNET_MULTICAST_Group *grp = cls;
  437. group_cleanup (grp);
  438. }
  439. /**
  440. * Function to call with the decision made for a join request.
  441. *
  442. * Must be called once and only once in response to an invocation of the
  443. * #GNUNET_MULTICAST_JoinRequestCallback.
  444. *
  445. * @param join
  446. * Join request handle.
  447. * @param is_admitted
  448. * #GNUNET_YES if the join is approved,
  449. * #GNUNET_NO if it is disapproved,
  450. * #GNUNET_SYSERR if we cannot answer the request.
  451. * @param relay_count
  452. * Number of relays given.
  453. * @param relays
  454. * Array of suggested peers that might be useful relays to use
  455. * when joining the multicast group (essentially a list of peers that
  456. * are already part of the multicast group and might thus be willing
  457. * to help with routing). If empty, only this local peer (which must
  458. * be the multicast origin) is a good candidate for building the
  459. * multicast tree. Note that it is unnecessary to specify our own
  460. * peer identity in this array.
  461. * @param join_resp
  462. * Message to send in response to the joining peer;
  463. * can also be used to redirect the peer to a different group at the
  464. * application layer; this response is to be transmitted to the
  465. * peer that issued the request even if admission is denied.
  466. */
  467. struct GNUNET_MULTICAST_ReplayHandle *
  468. GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join,
  469. int is_admitted,
  470. uint16_t relay_count,
  471. const struct GNUNET_PeerIdentity *relays,
  472. const struct GNUNET_MessageHeader *join_resp)
  473. {
  474. struct GNUNET_MULTICAST_Group *grp = join->group;
  475. uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
  476. uint16_t relay_size = relay_count * sizeof (*relays);
  477. struct MulticastJoinDecisionMessageHeader *hdcsn;
  478. struct MulticastJoinDecisionMessage *dcsn;
  479. struct GNUNET_MQ_Envelope *
  480. env = GNUNET_MQ_msg_extra (hdcsn, sizeof (*dcsn) + relay_size + join_resp_size,
  481. GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
  482. hdcsn->member_pub_key = join->member_pub_key;
  483. hdcsn->peer = join->peer;
  484. dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
  485. dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
  486. dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
  487. dcsn->is_admitted = htonl (is_admitted);
  488. dcsn->relay_count = htonl (relay_count);
  489. if (0 < relay_size)
  490. GNUNET_memcpy (&dcsn[1], relays, relay_size);
  491. if (0 < join_resp_size)
  492. GNUNET_memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
  493. GNUNET_MQ_send (grp->mq, env);
  494. GNUNET_free (join);
  495. return NULL;
  496. }
  497. /**
  498. * Replay a message fragment for the multicast group.
  499. *
  500. * @param rh
  501. * Replay handle identifying which replay operation was requested.
  502. * @param msg
  503. * Replayed message fragment, NULL if not found / an error occurred.
  504. * @param ec
  505. * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode
  506. * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated.
  507. */
  508. void
  509. GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
  510. const struct GNUNET_MessageHeader *msg,
  511. enum GNUNET_MULTICAST_ReplayErrorCode ec)
  512. {
  513. uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0;
  514. struct MulticastReplayResponseMessage *res;
  515. struct GNUNET_MQ_Envelope *
  516. env = GNUNET_MQ_msg_extra (res, msg_size,
  517. GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE);
  518. res->fragment_id = rh->req.fragment_id;
  519. res->message_id = rh->req.message_id;
  520. res->fragment_offset = rh->req.fragment_offset;
  521. res->flags = rh->req.flags;
  522. res->error_code = htonl (ec);
  523. if (GNUNET_MULTICAST_REC_OK == ec)
  524. {
  525. GNUNET_assert (NULL != msg);
  526. GNUNET_memcpy (&res[1], msg, msg_size);
  527. }
  528. GNUNET_MQ_send (rh->grp->mq, env);
  529. if (GNUNET_MULTICAST_REC_OK != ec)
  530. GNUNET_free (rh);
  531. }
  532. /**
  533. * Indicate the end of the replay session.
  534. *
  535. * Invalidates the replay handle.
  536. *
  537. * @param rh
  538. * Replay session to end.
  539. */
  540. void
  541. GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
  542. {
  543. struct MulticastReplayResponseMessage *end;
  544. struct GNUNET_MQ_Envelope *
  545. env = GNUNET_MQ_msg (end, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END);
  546. end->fragment_id = rh->req.fragment_id;
  547. end->message_id = rh->req.message_id;
  548. end->fragment_offset = rh->req.fragment_offset;
  549. end->flags = rh->req.flags;
  550. GNUNET_MQ_send (rh->grp->mq, env);
  551. GNUNET_free (rh);
  552. }
  553. /**
  554. * Replay a message for the multicast group.
  555. *
  556. * @param rh
  557. * Replay handle identifying which replay operation was requested.
  558. * @param notify
  559. * Function to call to get the message.
  560. * @param notify_cls
  561. * Closure for @a notify.
  562. */
  563. void
  564. GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
  565. GNUNET_MULTICAST_ReplayTransmitNotify notify,
  566. void *notify_cls)
  567. {
  568. }
  569. static void
  570. origin_connect (struct GNUNET_MULTICAST_Origin *orig);
  571. static void
  572. origin_reconnect (void *cls)
  573. {
  574. origin_connect (cls);
  575. }
  576. /**
  577. * Origin client disconnected from service.
  578. *
  579. * Reconnect after backoff period.
  580. */
  581. static void
  582. origin_disconnected (void *cls, enum GNUNET_MQ_Error error)
  583. {
  584. struct GNUNET_MULTICAST_Origin *orig = cls;
  585. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  586. LOG (GNUNET_ERROR_TYPE_DEBUG,
  587. "Origin client disconnected (%d), re-connecting\n",
  588. (int) error);
  589. if (NULL != grp->mq)
  590. {
  591. GNUNET_MQ_destroy (grp->mq);
  592. grp->mq = NULL;
  593. }
  594. grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
  595. origin_reconnect,
  596. orig);
  597. grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
  598. }
  599. /**
  600. * Connect to service as origin.
  601. */
  602. static void
  603. origin_connect (struct GNUNET_MULTICAST_Origin *orig)
  604. {
  605. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  606. struct GNUNET_MQ_MessageHandler handlers[] = {
  607. GNUNET_MQ_hd_var_size (group_message,
  608. GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
  609. struct GNUNET_MULTICAST_MessageHeader,
  610. grp),
  611. GNUNET_MQ_hd_var_size (origin_request,
  612. GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
  613. struct GNUNET_MULTICAST_RequestHeader,
  614. orig),
  615. GNUNET_MQ_hd_fixed_size (group_fragment_ack,
  616. GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
  617. struct GNUNET_MessageHeader,
  618. grp),
  619. GNUNET_MQ_hd_var_size (group_join_request,
  620. GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
  621. struct MulticastJoinRequestMessage,
  622. grp),
  623. GNUNET_MQ_hd_fixed_size (group_part_ack,
  624. GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
  625. struct GNUNET_MessageHeader,
  626. grp),
  627. GNUNET_MQ_hd_fixed_size (group_replay_request,
  628. GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
  629. struct MulticastReplayRequestMessage,
  630. grp),
  631. GNUNET_MQ_handler_end ()
  632. };
  633. grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
  634. handlers, origin_disconnected, orig);
  635. GNUNET_assert (NULL != grp->mq);
  636. GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
  637. }
  638. /**
  639. * Start a multicast group.
  640. *
  641. * Will advertise the origin in the P2P overlay network under the respective
  642. * public key so that other peer can find this peer to join it. Peers that
  643. * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
  644. * either an existing group member or to the origin. If the joining is
  645. * approved, the member is cleared for @e replay and will begin to receive
  646. * messages transmitted to the group. If joining is disapproved, the failed
  647. * candidate will be given a response. Members in the group can send messages
  648. * to the origin (one at a time).
  649. *
  650. * @param cfg
  651. * Configuration to use.
  652. * @param priv_key
  653. * ECC key that will be used to sign messages for this
  654. * multicast session; public key is used to identify the multicast group;
  655. * @param max_fragment_id
  656. * Maximum fragment ID already sent to the group.
  657. * 0 for a new group.
  658. * @param join_request_cb
  659. * Function called to approve / disapprove joining of a peer.
  660. * @param replay_frag_cb
  661. * Function that can be called to replay a message fragment.
  662. * @param replay_msg_cb
  663. * Function that can be called to replay a message.
  664. * @param request_cb
  665. * Function called with message fragments from group members.
  666. * @param message_cb
  667. * Function called with the message fragments sent to the
  668. * network by GNUNET_MULTICAST_origin_to_all(). These message fragments
  669. * should be stored for answering replay requests later.
  670. * @param cls
  671. * Closure for the various callbacks that follow.
  672. *
  673. * @return Handle for the origin, NULL on error.
  674. */
  675. struct GNUNET_MULTICAST_Origin *
  676. GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
  677. const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
  678. uint64_t max_fragment_id,
  679. GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
  680. GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
  681. GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
  682. GNUNET_MULTICAST_RequestCallback request_cb,
  683. GNUNET_MULTICAST_MessageCallback message_cb,
  684. void *cls)
  685. {
  686. struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
  687. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  688. struct MulticastOriginStartMessage *start;
  689. grp->connect_env = GNUNET_MQ_msg (start,
  690. GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
  691. start->max_fragment_id = max_fragment_id;
  692. start->group_key = *priv_key;
  693. grp->cfg = cfg;
  694. grp->is_origin = GNUNET_YES;
  695. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  696. grp->cb_cls = cls;
  697. grp->join_req_cb = join_request_cb;
  698. grp->replay_frag_cb = replay_frag_cb;
  699. grp->replay_msg_cb = replay_msg_cb;
  700. grp->message_cb = message_cb;
  701. orig->request_cb = request_cb;
  702. origin_connect (orig);
  703. return orig;
  704. }
  705. /**
  706. * Stop a multicast group.
  707. *
  708. * @param origin
  709. * Multicast group to stop.
  710. */
  711. void
  712. GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
  713. GNUNET_ContinuationCallback stop_cb,
  714. void *stop_cls)
  715. {
  716. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  717. struct GNUNET_MQ_Envelope *env;
  718. grp->is_disconnecting = GNUNET_YES;
  719. grp->disconnect_cb = stop_cb;
  720. grp->disconnect_cls = stop_cls;
  721. env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
  722. GNUNET_MQ_send (grp->mq, env);
  723. }
  724. static void
  725. origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
  726. {
  727. LOG (GNUNET_ERROR_TYPE_DEBUG, "%p origin_to_all()\n", orig);
  728. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  729. struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
  730. GNUNET_assert (GNUNET_YES == grp->in_transmit);
  731. size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
  732. struct GNUNET_MULTICAST_MessageHeader *msg;
  733. struct GNUNET_MQ_Envelope *
  734. env = GNUNET_MQ_msg_extra (msg, buf_size - sizeof(*msg),
  735. GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  736. int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
  737. if (! (GNUNET_YES == ret || GNUNET_NO == ret)
  738. || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
  739. {
  740. LOG (GNUNET_ERROR_TYPE_ERROR,
  741. "%p OriginTransmitNotify() returned error or invalid message size.\n",
  742. orig);
  743. /* FIXME: handle error */
  744. GNUNET_MQ_discard (env);
  745. return;
  746. }
  747. if (GNUNET_NO == ret && 0 == buf_size)
  748. {
  749. LOG (GNUNET_ERROR_TYPE_DEBUG,
  750. "%p OriginTransmitNotify() - transmission paused.\n", orig);
  751. GNUNET_MQ_discard (env);
  752. return; /* Transmission paused. */
  753. }
  754. msg->header.size = htons (sizeof (*msg) + buf_size);
  755. msg->message_id = GNUNET_htonll (tmit->message_id);
  756. msg->group_generation = tmit->group_generation;
  757. msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
  758. tmit->fragment_offset += sizeof (*msg) + buf_size;
  759. grp->acks_pending++;
  760. GNUNET_MQ_send (grp->mq, env);
  761. if (GNUNET_YES == ret)
  762. grp->in_transmit = GNUNET_NO;
  763. }
  764. /**
  765. * Send a message to the multicast group.
  766. *
  767. * @param orig
  768. * Handle to the multicast group.
  769. * @param message_id
  770. * Application layer ID for the message. Opaque to multicast.
  771. * @param group_generation
  772. * Group generation of the message.
  773. * Documented in struct GNUNET_MULTICAST_MessageHeader.
  774. * @param notify
  775. * Function to call to get the message.
  776. * @param notify_cls
  777. * Closure for @a notify.
  778. *
  779. * @return Message handle on success,
  780. * NULL on error (i.e. another request is already pending).
  781. */
  782. struct GNUNET_MULTICAST_OriginTransmitHandle *
  783. GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
  784. uint64_t message_id,
  785. uint64_t group_generation,
  786. GNUNET_MULTICAST_OriginTransmitNotify notify,
  787. void *notify_cls)
  788. {
  789. struct GNUNET_MULTICAST_Group *grp = &orig->grp;
  790. if (GNUNET_YES == grp->in_transmit)
  791. return NULL;
  792. grp->in_transmit = GNUNET_YES;
  793. struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
  794. tmit->origin = orig;
  795. tmit->message_id = message_id;
  796. tmit->fragment_offset = 0;
  797. tmit->group_generation = group_generation;
  798. tmit->notify = notify;
  799. tmit->notify_cls = notify_cls;
  800. origin_to_all (orig);
  801. return tmit;
  802. }
  803. /**
  804. * Resume message transmission to multicast group.
  805. *
  806. * @param th
  807. * Transmission to cancel.
  808. */
  809. void
  810. GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
  811. {
  812. struct GNUNET_MULTICAST_Group *grp = &th->origin->grp;
  813. if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
  814. return;
  815. origin_to_all (th->origin);
  816. }
  817. /**
  818. * Cancel request for message transmission to multicast group.
  819. *
  820. * @param th
  821. * Transmission to cancel.
  822. */
  823. void
  824. GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
  825. {
  826. th->origin->grp.in_transmit = GNUNET_NO;
  827. }
  828. static void
  829. member_connect (struct GNUNET_MULTICAST_Member *mem);
  830. static void
  831. member_reconnect (void *cls)
  832. {
  833. member_connect (cls);
  834. }
  835. /**
  836. * Member client disconnected from service.
  837. *
  838. * Reconnect after backoff period.
  839. */
  840. static void
  841. member_disconnected (void *cls, enum GNUNET_MQ_Error error)
  842. {
  843. struct GNUNET_MULTICAST_Member *mem = cls;
  844. struct GNUNET_MULTICAST_Group *grp = &mem->grp;
  845. LOG (GNUNET_ERROR_TYPE_DEBUG,
  846. "Member client disconnected (%d), re-connecting\n",
  847. (int) error);
  848. GNUNET_MQ_destroy (grp->mq);
  849. grp->mq = NULL;
  850. grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
  851. member_reconnect,
  852. mem);
  853. grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
  854. }
  855. /**
  856. * Connect to service as member.
  857. */
  858. static void
  859. member_connect (struct GNUNET_MULTICAST_Member *mem)
  860. {
  861. struct GNUNET_MULTICAST_Group *grp = &mem->grp;
  862. struct GNUNET_MQ_MessageHandler handlers[] = {
  863. GNUNET_MQ_hd_var_size (group_message,
  864. GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
  865. struct GNUNET_MULTICAST_MessageHeader,
  866. grp),
  867. GNUNET_MQ_hd_fixed_size (group_fragment_ack,
  868. GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
  869. struct GNUNET_MessageHeader,
  870. grp),
  871. GNUNET_MQ_hd_var_size (group_join_request,
  872. GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
  873. struct MulticastJoinRequestMessage,
  874. grp),
  875. GNUNET_MQ_hd_var_size (member_join_decision,
  876. GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
  877. struct MulticastJoinDecisionMessageHeader,
  878. mem),
  879. GNUNET_MQ_hd_fixed_size (group_part_ack,
  880. GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
  881. struct GNUNET_MessageHeader,
  882. grp),
  883. GNUNET_MQ_hd_fixed_size (group_replay_request,
  884. GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
  885. struct MulticastReplayRequestMessage,
  886. grp),
  887. GNUNET_MQ_hd_var_size (member_replay_response,
  888. GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
  889. struct MulticastReplayResponseMessage,
  890. mem),
  891. GNUNET_MQ_handler_end ()
  892. };
  893. grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
  894. handlers, member_disconnected, mem);
  895. GNUNET_assert (NULL != grp->mq);
  896. GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
  897. }
  898. /**
  899. * Join a multicast group.
  900. *
  901. * The entity joining is always the local peer. Further information about the
  902. * candidate can be provided in the @a join_request message. If the join fails, the
  903. * @a message_cb is invoked with a (failure) response and then with NULL. If
  904. * the join succeeds, outstanding (state) messages and ongoing multicast
  905. * messages will be given to the @a message_cb until the member decides to part
  906. * the group. The @a replay_cb function may be called at any time by the
  907. * multicast service to support relaying messages to other members of the group.
  908. *
  909. * @param cfg
  910. * Configuration to use.
  911. * @param group_key
  912. * ECC public key that identifies the group to join.
  913. * @param member_key
  914. * ECC key that identifies the member
  915. * and used to sign requests sent to the origin.
  916. * @param origin
  917. * Peer ID of the origin to send unicast requsets to. If NULL,
  918. * unicast requests are sent back via multiple hops on the reverse path
  919. * of multicast messages.
  920. * @param relay_count
  921. * Number of peers in the @a relays array.
  922. * @param relays
  923. * Peer identities of members of the group, which serve as relays
  924. * and can be used to join the group at. and send the @a join_request to.
  925. * If empty, the @a join_request is sent directly to the @a origin.
  926. * @param join_msg
  927. * Application-dependent join message to be passed to the peer @a origin.
  928. * @param join_request_cb
  929. * Function called to approve / disapprove joining of a peer.
  930. * @param join_decision_cb
  931. * Function called to inform about the join decision.
  932. * @param replay_frag_cb
  933. * Function that can be called to replay message fragments
  934. * this peer already knows from this group. NULL if this
  935. * client is unable to support replay.
  936. * @param replay_msg_cb
  937. * Function that can be called to replay message fragments
  938. * this peer already knows from this group. NULL if this
  939. * client is unable to support replay.
  940. * @param message_cb
  941. * Function to be called for all message fragments we
  942. * receive from the group, excluding those our @a replay_cb
  943. * already has.
  944. * @param cls
  945. * Closure for callbacks.
  946. *
  947. * @return Handle for the member, NULL on error.
  948. */
  949. struct GNUNET_MULTICAST_Member *
  950. GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
  951. const struct GNUNET_CRYPTO_EddsaPublicKey *group_pub_key,
  952. const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key,
  953. const struct GNUNET_PeerIdentity *origin,
  954. uint16_t relay_count,
  955. const struct GNUNET_PeerIdentity *relays,
  956. const struct GNUNET_MessageHeader *join_msg,
  957. GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
  958. GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
  959. GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
  960. GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
  961. GNUNET_MULTICAST_MessageCallback message_cb,
  962. void *cls)
  963. {
  964. struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
  965. struct GNUNET_MULTICAST_Group *grp = &mem->grp;
  966. uint16_t relay_size = relay_count * sizeof (*relays);
  967. uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
  968. struct MulticastMemberJoinMessage *join;
  969. grp->connect_env = GNUNET_MQ_msg_extra (join, relay_size + join_msg_size,
  970. GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
  971. join->group_pub_key = *group_pub_key;
  972. join->member_key = *member_key;
  973. join->origin = *origin;
  974. join->relay_count = ntohl (relay_count);
  975. if (0 < relay_size)
  976. GNUNET_memcpy (&join[1], relays, relay_size);
  977. if (0 < join_msg_size)
  978. GNUNET_memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
  979. grp->cfg = cfg;
  980. grp->is_origin = GNUNET_NO;
  981. grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
  982. mem->join_dcsn_cb = join_decision_cb;
  983. grp->join_req_cb = join_request_cb;
  984. grp->replay_frag_cb = replay_frag_cb;
  985. grp->replay_msg_cb = replay_msg_cb;
  986. grp->message_cb = message_cb;
  987. grp->cb_cls = cls;
  988. member_connect (mem);
  989. return mem;
  990. }
  991. /**
  992. * Part a multicast group.
  993. *
  994. * Disconnects from all group members and invalidates the @a member handle.
  995. *
  996. * An application-dependent part message can be transmitted beforehand using
  997. * #GNUNET_MULTICAST_member_to_origin())
  998. *
  999. * @param member
  1000. * Membership handle.
  1001. */
  1002. void
  1003. GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
  1004. GNUNET_ContinuationCallback part_cb,
  1005. void *part_cls)
  1006. {
  1007. struct GNUNET_MULTICAST_Group *grp = &mem->grp;
  1008. struct GNUNET_MQ_Envelope *env;
  1009. mem->join_dcsn_cb = NULL;
  1010. grp->join_req_cb = NULL;
  1011. grp->message_cb = NULL;
  1012. grp->replay_msg_cb = NULL;
  1013. grp->replay_frag_cb = NULL;
  1014. grp->is_disconnecting = GNUNET_YES;
  1015. grp->disconnect_cb = part_cb;
  1016. grp->disconnect_cls = part_cls;
  1017. env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
  1018. GNUNET_MQ_send (grp->mq, env);
  1019. }
  1020. void
  1021. member_replay_request (struct GNUNET_MULTICAST_Member *mem,
  1022. uint64_t fragment_id,
  1023. uint64_t message_id,
  1024. uint64_t fragment_offset,
  1025. uint64_t flags)
  1026. {
  1027. struct MulticastReplayRequestMessage *rep;
  1028. struct GNUNET_MQ_Envelope *
  1029. env = GNUNET_MQ_msg (rep, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST);
  1030. rep->fragment_id = GNUNET_htonll (fragment_id);
  1031. rep->message_id = GNUNET_htonll (message_id);
  1032. rep->fragment_offset = GNUNET_htonll (fragment_offset);
  1033. rep->flags = GNUNET_htonll (flags);
  1034. GNUNET_MQ_send (mem->grp.mq, env);
  1035. }
  1036. /**
  1037. * Request a fragment to be replayed by fragment ID.
  1038. *
  1039. * Useful if messages below the @e max_known_fragment_id given when joining are
  1040. * needed and not known to the client.
  1041. *
  1042. * @param member
  1043. * Membership handle.
  1044. * @param fragment_id
  1045. * ID of a message fragment that this client would like to see replayed.
  1046. * @param flags
  1047. * Additional flags for the replay request.
  1048. * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback
  1049. *
  1050. * @return Replay request handle.
  1051. */
  1052. struct GNUNET_MULTICAST_MemberReplayHandle *
  1053. GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem,
  1054. uint64_t fragment_id,
  1055. uint64_t flags)
  1056. {
  1057. member_replay_request (mem, fragment_id, 0, 0, flags);
  1058. // FIXME: return something useful
  1059. return NULL;
  1060. }
  1061. /**
  1062. * Request a message fragment to be replayed.
  1063. *
  1064. * Useful if messages below the @e max_known_fragment_id given when joining are
  1065. * needed and not known to the client.
  1066. *
  1067. * @param member
  1068. * Membership handle.
  1069. * @param message_id
  1070. * ID of the message this client would like to see replayed.
  1071. * @param fragment_offset
  1072. * Offset of the fragment within the message to replay.
  1073. * @param flags
  1074. * Additional flags for the replay request.
  1075. * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback
  1076. *
  1077. * @return Replay request handle, NULL on error.
  1078. */
  1079. struct GNUNET_MULTICAST_MemberReplayHandle *
  1080. GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem,
  1081. uint64_t message_id,
  1082. uint64_t fragment_offset,
  1083. uint64_t flags)
  1084. {
  1085. member_replay_request (mem, 0, message_id, fragment_offset, flags);
  1086. // FIXME: return something useful
  1087. return NULL;
  1088. }
  1089. static void
  1090. member_to_origin (struct GNUNET_MULTICAST_Member *mem)
  1091. {
  1092. LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
  1093. struct GNUNET_MULTICAST_Group *grp = &mem->grp;
  1094. struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
  1095. GNUNET_assert (GNUNET_YES == grp->in_transmit);
  1096. size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
  1097. struct GNUNET_MULTICAST_RequestHeader *req;
  1098. struct GNUNET_MQ_Envelope *
  1099. env = GNUNET_MQ_msg_extra (req, buf_size - sizeof(*req),
  1100. GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
  1101. int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
  1102. if (! (GNUNET_YES == ret || GNUNET_NO == ret)
  1103. || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
  1104. {
  1105. LOG (GNUNET_ERROR_TYPE_ERROR,
  1106. "MemberTransmitNotify() returned error or invalid message size. "
  1107. "ret=%d, buf_size=%u\n", ret, buf_size);
  1108. /* FIXME: handle error */
  1109. GNUNET_MQ_discard (env);
  1110. return;
  1111. }
  1112. if (GNUNET_NO == ret && 0 == buf_size)
  1113. {
  1114. /* Transmission paused. */
  1115. GNUNET_MQ_discard (env);
  1116. return;
  1117. }
  1118. req->header.size = htons (sizeof (*req) + buf_size);
  1119. req->request_id = GNUNET_htonll (tmit->request_id);
  1120. req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
  1121. tmit->fragment_offset += sizeof (*req) + buf_size;
  1122. GNUNET_MQ_send (grp->mq, env);
  1123. if (GNUNET_YES == ret)
  1124. grp->in_transmit = GNUNET_NO;
  1125. }
  1126. /**
  1127. * Send a message to the origin of the multicast group.
  1128. *
  1129. * @param mem
  1130. * Membership handle.
  1131. * @param request_id
  1132. * Application layer ID for the request. Opaque to multicast.
  1133. * @param notify
  1134. * Callback to call to get the message.
  1135. * @param notify_cls
  1136. * Closure for @a notify.
  1137. *
  1138. * @return Handle to cancel request, NULL on error (i.e. request already pending).
  1139. */
  1140. struct GNUNET_MULTICAST_MemberTransmitHandle *
  1141. GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
  1142. uint64_t request_id,
  1143. GNUNET_MULTICAST_MemberTransmitNotify notify,
  1144. void *notify_cls)
  1145. {
  1146. if (GNUNET_YES == mem->grp.in_transmit)
  1147. return NULL;
  1148. mem->grp.in_transmit = GNUNET_YES;
  1149. struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
  1150. tmit->member = mem;
  1151. tmit->request_id = request_id;
  1152. tmit->fragment_offset = 0;
  1153. tmit->notify = notify;
  1154. tmit->notify_cls = notify_cls;
  1155. member_to_origin (mem);
  1156. return tmit;
  1157. }
  1158. /**
  1159. * Resume message transmission to origin.
  1160. *
  1161. * @param th
  1162. * Transmission to cancel.
  1163. */
  1164. void
  1165. GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
  1166. {
  1167. struct GNUNET_MULTICAST_Group *grp = &th->member->grp;
  1168. if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
  1169. return;
  1170. member_to_origin (th->member);
  1171. }
  1172. /**
  1173. * Cancel request for message transmission to origin.
  1174. *
  1175. * @param th
  1176. * Transmission to cancel.
  1177. */
  1178. void
  1179. GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
  1180. {
  1181. th->member->grp.in_transmit = GNUNET_NO;
  1182. }
  1183. /* end of multicast_api.c */