2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file multicast/multicast_api.c
23 * @brief Multicast service; implements multicast groups using CADET connections.
24 * @author Christian Grothoff
25 * @author Gabor X Toth
29 #include "gnunet_util_lib.h"
30 #include "gnunet_multicast_service.h"
31 #include "multicast.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__)
37 * Handle for a request to send a message to all multicast group members
40 struct GNUNET_MULTICAST_OriginTransmitHandle
42 GNUNET_MULTICAST_OriginTransmitNotify notify;
44 struct GNUNET_MULTICAST_Origin *origin;
47 uint64_t group_generation;
48 uint64_t fragment_offset;
53 * Handle for a message to be delivered from a member to the origin.
55 struct GNUNET_MULTICAST_MemberTransmitHandle
57 GNUNET_MULTICAST_MemberTransmitNotify notify;
59 struct GNUNET_MULTICAST_Member *member;
62 uint64_t fragment_offset;
66 struct GNUNET_MULTICAST_Group
69 * Configuration to use.
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
74 * Client connection to the service.
76 struct GNUNET_CLIENT_MANAGER_Connection *client;
79 * Message to send on reconnect.
81 struct GNUNET_MessageHeader *connect_msg;
83 GNUNET_MULTICAST_JoinRequestCallback join_req_cb;
84 GNUNET_MULTICAST_MembershipTestCallback member_test_cb;
85 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
86 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
87 GNUNET_MULTICAST_MessageCallback message_cb;
91 * Function called after disconnected from the service.
93 GNUNET_ContinuationCallback disconnect_cb;
96 * Closure for @a disconnect_cb.
101 * Are we currently transmitting a message?
106 * Is this the origin or a member?
111 * Is this channel in the process of disconnecting from the service?
112 * #GNUNET_YES or #GNUNET_NO
114 uint8_t is_disconnecting;
119 * Handle for the origin of a multicast group.
121 struct GNUNET_MULTICAST_Origin
123 struct GNUNET_MULTICAST_Group grp;
124 struct GNUNET_MULTICAST_OriginTransmitHandle tmit;
126 GNUNET_MULTICAST_RequestCallback request_cb;
131 * Handle for a multicast group member.
133 struct GNUNET_MULTICAST_Member
135 struct GNUNET_MULTICAST_Group grp;
136 struct GNUNET_MULTICAST_MemberTransmitHandle tmit;
138 GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb;
141 * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle *
143 struct GNUNET_CONTAINER_MultiHashMap *replay_reqs;
145 uint64_t next_fragment_id;
150 * Handle that identifies a join request.
152 * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the
153 * corresponding calls to #GNUNET_MULTICAST_join_decision().
155 struct GNUNET_MULTICAST_JoinHandle
157 struct GNUNET_MULTICAST_Group *group;
160 * Public key of the member requesting join.
162 struct GNUNET_CRYPTO_EcdsaPublicKey member_key;
165 * Peer identity of the member requesting join.
167 struct GNUNET_PeerIdentity peer;
172 * Handle to pass back for the answer of a membership test.
174 struct GNUNET_MULTICAST_MembershipTestHandle
180 * Opaque handle to a replay request from the multicast service.
182 struct GNUNET_MULTICAST_ReplayHandle
184 struct GNUNET_MULTICAST_Group *grp;
185 struct MulticastReplayRequestMessage req;
190 * Handle for a replay request.
192 struct GNUNET_MULTICAST_MemberReplayHandle
195 GNUNET_MULTICAST_ResultCallback result_cb;
201 * Send first message to the service after connecting.
204 group_send_connect_msg (struct GNUNET_MULTICAST_Group *grp)
206 uint16_t cmsg_size = ntohs (grp->connect_msg->size);
207 struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
208 memcpy (cmsg, grp->connect_msg, cmsg_size);
209 GNUNET_CLIENT_MANAGER_transmit_now (grp->client, cmsg);
214 * Got disconnected from service. Reconnect.
217 group_recv_disconnect (void *cls,
218 struct GNUNET_CLIENT_MANAGER_Connection *client,
219 const struct GNUNET_MessageHeader *msg)
221 struct GNUNET_MULTICAST_Group *
222 grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
223 GNUNET_CLIENT_MANAGER_reconnect (client);
224 group_send_connect_msg (grp);
229 * Receive join request from service.
232 group_recv_join_request (void *cls,
233 struct GNUNET_CLIENT_MANAGER_Connection *client,
234 const struct GNUNET_MessageHeader *msg)
236 struct GNUNET_MULTICAST_Group *grp;
237 const struct MulticastJoinRequestMessage *jreq;
238 struct GNUNET_MULTICAST_JoinHandle *jh;
239 const struct GNUNET_MessageHeader *jmsg;
241 grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
247 if (NULL == grp->join_req_cb)
249 /* FIXME: this fails to check that 'msg' is well-formed! */
250 jreq = (const struct MulticastJoinRequestMessage *) msg;
251 if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size))
252 jmsg = (const struct GNUNET_MessageHeader *) &jreq[1];
255 jh = GNUNET_malloc (sizeof (*jh));
257 jh->member_key = jreq->member_key;
258 jh->peer = jreq->peer;
259 grp->join_req_cb (grp->cb_cls, &jreq->member_key, jmsg, jh);
264 * Receive multicast message from service.
267 group_recv_message (void *cls,
268 struct GNUNET_CLIENT_MANAGER_Connection *client,
269 const struct GNUNET_MessageHeader *msg)
271 struct GNUNET_MULTICAST_Group *
272 grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
273 struct GNUNET_MULTICAST_MessageHeader *
274 mmsg = (struct GNUNET_MULTICAST_MessageHeader *) msg;
276 if (GNUNET_YES == grp->is_disconnecting)
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Calling message callback with a message of size %u.\n",
281 ntohs (mmsg->header.size));
283 if (NULL != grp->message_cb)
284 grp->message_cb (grp->cb_cls, mmsg);
289 * Origin receives uniquest request from a member.
292 origin_recv_request (void *cls,
293 struct GNUNET_CLIENT_MANAGER_Connection *client,
294 const struct GNUNET_MessageHeader *msg)
296 struct GNUNET_MULTICAST_Group *grp;
297 struct GNUNET_MULTICAST_Origin *
298 orig = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
300 struct GNUNET_MULTICAST_RequestHeader *
301 req = (struct GNUNET_MULTICAST_RequestHeader *) msg;
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304 "Calling request callback with a request of size %u.\n",
305 ntohs (req->header.size));
307 if (NULL != orig->request_cb)
308 orig->request_cb (grp->cb_cls, req);
313 * Receive multicast replay request from service.
316 group_recv_replay_request (void *cls,
317 struct GNUNET_CLIENT_MANAGER_Connection *client,
318 const struct GNUNET_MessageHeader *msg)
320 struct GNUNET_MULTICAST_Group *
321 grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
322 struct MulticastReplayRequestMessage *
323 rep = (struct MulticastReplayRequestMessage *) msg;
325 if (GNUNET_YES == grp->is_disconnecting)
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n");
330 if (0 != rep->fragment_id)
332 if (NULL != grp->replay_frag_cb)
334 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
337 grp->replay_frag_cb (grp->cb_cls, &rep->member_key,
338 GNUNET_ntohll (rep->fragment_id),
339 GNUNET_ntohll (rep->flags), rh);
342 else if (0 != rep->message_id)
344 if (NULL != grp->replay_msg_cb)
346 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
349 grp->replay_msg_cb (grp->cb_cls, &rep->member_key,
350 GNUNET_ntohll (rep->message_id),
351 GNUNET_ntohll (rep->fragment_offset),
352 GNUNET_ntohll (rep->flags), rh);
359 * Receive multicast replay request from service.
362 member_recv_replay_response (void *cls,
363 struct GNUNET_CLIENT_MANAGER_Connection *client,
364 const struct GNUNET_MessageHeader *msg)
366 struct GNUNET_MULTICAST_Group *grp;
367 struct GNUNET_MULTICAST_Member *
368 mem = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
370 struct MulticastReplayResponseMessage *
371 res = (struct MulticastReplayResponseMessage *) msg;
373 if (GNUNET_YES == grp->is_disconnecting)
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n");
380 * Member receives join decision.
383 member_recv_join_decision (void *cls,
384 struct GNUNET_CLIENT_MANAGER_Connection *client,
385 const struct GNUNET_MessageHeader *msg)
387 struct GNUNET_MULTICAST_Group *grp;
388 struct GNUNET_MULTICAST_Member *
389 mem = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
392 const struct MulticastJoinDecisionMessageHeader *
393 hdcsn = (const struct MulticastJoinDecisionMessageHeader *) msg;
394 const struct MulticastJoinDecisionMessage *
395 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
397 uint16_t dcsn_size = ntohs (dcsn->header.size);
398 int is_admitted = ntohl (dcsn->is_admitted);
400 LOG (GNUNET_ERROR_TYPE_DEBUG,
401 "%p Member got join decision from multicast: %d\n",
404 const struct GNUNET_MessageHeader *join_resp = NULL;
405 uint16_t join_resp_size = 0;
407 uint16_t relay_count = ntohl (dcsn->relay_count);
408 const struct GNUNET_PeerIdentity *relays = NULL;
409 uint16_t relay_size = relay_count * sizeof (*relays);
412 if (dcsn_size < sizeof (*dcsn) + relay_size)
415 is_admitted = GNUNET_SYSERR;
419 relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
423 if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
425 join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size);
426 join_resp_size = ntohs (join_resp->size);
428 if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
430 LOG (GNUNET_ERROR_TYPE_DEBUG,
431 "Received invalid join decision message from multicast: %u < %u + %u + %u\n",
432 dcsn_size , sizeof (*dcsn), relay_size, join_resp_size);
434 is_admitted = GNUNET_SYSERR;
437 if (NULL != mem->join_dcsn_cb)
438 mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
439 relay_count, relays, join_resp);
442 //if (GNUNET_YES != is_admitted)
443 // GNUNET_MULTICAST_member_part (mem);
448 * Message handlers for an origin.
450 static struct GNUNET_CLIENT_MANAGER_MessageHandler origin_handlers[] =
452 { group_recv_disconnect, NULL, 0, 0, GNUNET_NO },
454 { group_recv_message, NULL,
455 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
456 sizeof (struct GNUNET_MULTICAST_MessageHeader), GNUNET_YES },
458 { origin_recv_request, NULL,
459 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
460 sizeof (struct GNUNET_MULTICAST_RequestHeader), GNUNET_YES },
462 { group_recv_join_request, NULL,
463 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
464 sizeof (struct MulticastJoinRequestMessage), GNUNET_YES },
466 { group_recv_replay_request, NULL,
467 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
468 sizeof (struct MulticastReplayRequestMessage), GNUNET_NO },
470 { NULL, NULL, 0, 0, GNUNET_NO }
475 * Message handlers for a member.
477 static struct GNUNET_CLIENT_MANAGER_MessageHandler member_handlers[] =
479 { group_recv_disconnect, NULL, 0, 0, GNUNET_NO },
481 { group_recv_message, NULL,
482 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
483 sizeof (struct GNUNET_MULTICAST_MessageHeader), GNUNET_YES },
485 { group_recv_join_request, NULL,
486 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
487 sizeof (struct MulticastJoinRequestMessage), GNUNET_YES },
489 { member_recv_join_decision, NULL,
490 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
491 sizeof (struct MulticastJoinDecisionMessage), GNUNET_YES },
493 { group_recv_replay_request, NULL,
494 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
495 sizeof (struct MulticastReplayRequestMessage), GNUNET_NO },
497 { member_recv_replay_response, NULL,
498 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
499 sizeof (struct MulticastReplayRequestMessage), GNUNET_NO },
501 { NULL, NULL, 0, 0, GNUNET_NO }
506 group_cleanup (struct GNUNET_MULTICAST_Group *grp)
508 GNUNET_free (grp->connect_msg);
509 if (NULL != grp->disconnect_cb)
510 grp->disconnect_cb (grp->disconnect_cls);
515 origin_cleanup (void *cls)
517 struct GNUNET_MULTICAST_Origin *orig = cls;
518 group_cleanup (&orig->grp);
524 member_cleanup (void *cls)
526 struct GNUNET_MULTICAST_Member *mem = cls;
527 group_cleanup (&mem->grp);
533 * Function to call with the decision made for a join request.
535 * Must be called once and only once in response to an invocation of the
536 * #GNUNET_MULTICAST_JoinRequestCallback.
539 * Join request handle.
541 * #GNUNET_YES if the join is approved,
542 * #GNUNET_NO if it is disapproved,
543 * #GNUNET_SYSERR if we cannot answer the request.
545 * Number of relays given.
547 * Array of suggested peers that might be useful relays to use
548 * when joining the multicast group (essentially a list of peers that
549 * are already part of the multicast group and might thus be willing
550 * to help with routing). If empty, only this local peer (which must
551 * be the multicast origin) is a good candidate for building the
552 * multicast tree. Note that it is unnecessary to specify our own
553 * peer identity in this array.
555 * Message to send in response to the joining peer;
556 * can also be used to redirect the peer to a different group at the
557 * application layer; this response is to be transmitted to the
558 * peer that issued the request even if admission is denied.
560 struct GNUNET_MULTICAST_ReplayHandle *
561 GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join,
563 uint16_t relay_count,
564 const struct GNUNET_PeerIdentity *relays,
565 const struct GNUNET_MessageHeader *join_resp)
567 struct GNUNET_MULTICAST_Group *grp = join->group;
568 uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
569 uint16_t relay_size = relay_count * sizeof (*relays);
571 struct MulticastJoinDecisionMessageHeader * hdcsn;
572 struct MulticastJoinDecisionMessage *dcsn;
573 hdcsn = GNUNET_malloc (sizeof (*hdcsn) + sizeof (*dcsn)
574 + relay_size + join_resp_size);
575 hdcsn->header.size = htons (sizeof (*hdcsn) + sizeof (*dcsn)
576 + relay_size + join_resp_size);
577 hdcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
578 hdcsn->member_key = join->member_key;
579 hdcsn->peer = join->peer;
581 dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
582 dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
583 dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
584 dcsn->is_admitted = htonl (is_admitted);
585 dcsn->relay_count = htonl (relay_count);
587 memcpy (&dcsn[1], relays, relay_size);
588 if (0 < join_resp_size)
589 memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
591 GNUNET_CLIENT_MANAGER_transmit (grp->client, &hdcsn->header);
598 * Call informing multicast about the decision taken for a membership test.
601 * Handle that was given for the query.
603 * #GNUNET_YES if peer was a member, #GNUNET_NO if peer was not a member,
604 * #GNUNET_SYSERR if we cannot answer the membership test.
607 GNUNET_MULTICAST_membership_test_result (struct GNUNET_MULTICAST_MembershipTestHandle *mth,
614 * Replay a message fragment for the multicast group.
617 * Replay handle identifying which replay operation was requested.
619 * Replayed message fragment, NULL if not found / an error occurred.
621 * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode
622 * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated.
625 GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
626 const struct GNUNET_MessageHeader *msg,
627 enum GNUNET_MULTICAST_ReplayErrorCode ec)
629 uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0;
630 struct MulticastReplayResponseMessage *
631 res = GNUNET_malloc (sizeof (*res) + msg_size);
632 *res = (struct MulticastReplayResponseMessage) {
634 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE),
635 .size = htons (sizeof (*res) + msg_size),
637 .fragment_id = rh->req.fragment_id,
638 .message_id = rh->req.message_id,
639 .fragment_offset = rh->req.fragment_offset,
640 .flags = rh->req.flags,
641 .error_code = htonl (ec),
644 if (GNUNET_MULTICAST_REC_OK == ec)
646 GNUNET_assert (NULL != msg);
647 memcpy (&res[1], msg, msg_size);
650 GNUNET_CLIENT_MANAGER_transmit (rh->grp->client, &res->header);
653 if (GNUNET_MULTICAST_REC_OK != ec)
659 * Indicate the end of the replay session.
661 * Invalidates the replay handle.
664 * Replay session to end.
667 GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
669 struct MulticastReplayResponseMessage end = {
671 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END),
672 .size = htons (sizeof (end)),
674 .fragment_id = rh->req.fragment_id,
675 .message_id = rh->req.message_id,
676 .fragment_offset = rh->req.fragment_offset,
677 .flags = rh->req.flags,
680 GNUNET_CLIENT_MANAGER_transmit (rh->grp->client, &end.header);
686 * Replay a message for the multicast group.
689 * Replay handle identifying which replay operation was requested.
691 * Function to call to get the message.
693 * Closure for @a notify.
696 GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
697 GNUNET_MULTICAST_ReplayTransmitNotify notify,
704 * Start a multicast group.
706 * Will advertise the origin in the P2P overlay network under the respective
707 * public key so that other peer can find this peer to join it. Peers that
708 * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
709 * either an existing group member or to the origin. If the joining is
710 * approved, the member is cleared for @e replay and will begin to receive
711 * messages transmitted to the group. If joining is disapproved, the failed
712 * candidate will be given a response. Members in the group can send messages
713 * to the origin (one at a time).
716 * Configuration to use.
718 * ECC key that will be used to sign messages for this
719 * multicast session; public key is used to identify the multicast group;
720 * @param max_fragment_id
721 * Maximum fragment ID already sent to the group.
723 * @param join_request_cb
724 * Function called to approve / disapprove joining of a peer.
725 * @param member_test_cb
726 * Function multicast can use to test group membership.
727 * @param replay_frag_cb
728 * Function that can be called to replay a message fragment.
729 * @param replay_msg_cb
730 * Function that can be called to replay a message.
732 * Function called with message fragments from group members.
734 * Function called with the message fragments sent to the
735 * network by GNUNET_MULTICAST_origin_to_all(). These message fragments
736 * should be stored for answering replay requests later.
738 * Closure for the various callbacks that follow.
740 * @return Handle for the origin, NULL on error.
742 struct GNUNET_MULTICAST_Origin *
743 GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
744 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
745 uint64_t max_fragment_id,
746 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
747 GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
748 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
749 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
750 GNUNET_MULTICAST_RequestCallback request_cb,
751 GNUNET_MULTICAST_MessageCallback message_cb,
754 struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
755 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
756 struct MulticastOriginStartMessage *start = GNUNET_malloc (sizeof (*start));
758 start->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
759 start->header.size = htons (sizeof (*start));
760 start->max_fragment_id = max_fragment_id;
761 memcpy (&start->group_key, priv_key, sizeof (*priv_key));
763 grp->connect_msg = (struct GNUNET_MessageHeader *) start;
764 grp->is_origin = GNUNET_YES;
768 grp->join_req_cb = join_request_cb;
769 grp->member_test_cb = member_test_cb;
770 grp->replay_frag_cb = replay_frag_cb;
771 grp->replay_msg_cb = replay_msg_cb;
772 grp->message_cb = message_cb;
774 orig->request_cb = request_cb;
776 grp->client = GNUNET_CLIENT_MANAGER_connect (cfg, "multicast", origin_handlers);
777 GNUNET_CLIENT_MANAGER_set_user_context_ (grp->client, orig, sizeof (*grp));
778 group_send_connect_msg (grp);
785 * Stop a multicast group.
788 * Multicast group to stop.
791 GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
792 GNUNET_ContinuationCallback stop_cb,
795 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
797 grp->is_disconnecting = GNUNET_YES;
798 grp->disconnect_cb = stop_cb;
799 grp->disconnect_cls = stop_cls;
801 GNUNET_CLIENT_MANAGER_disconnect (orig->grp.client, GNUNET_YES,
802 &origin_cleanup, orig);
807 origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
809 LOG (GNUNET_ERROR_TYPE_DEBUG, "origin_to_all()\n");
810 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
811 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
813 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
814 struct GNUNET_MULTICAST_MessageHeader *msg = GNUNET_malloc (buf_size);
815 int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
817 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
818 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
820 LOG (GNUNET_ERROR_TYPE_ERROR,
821 "OriginTransmitNotify() returned error or invalid message size.\n");
822 /* FIXME: handle error */
827 if (GNUNET_NO == ret && 0 == buf_size)
830 return; /* Transmission paused. */
833 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
834 msg->header.size = htons (sizeof (*msg) + buf_size);
835 msg->message_id = GNUNET_htonll (tmit->message_id);
836 msg->group_generation = tmit->group_generation;
837 msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
838 tmit->fragment_offset += sizeof (*msg) + buf_size;
840 GNUNET_CLIENT_MANAGER_transmit (grp->client, &msg->header);
845 * Send a message to the multicast group.
848 * Handle to the multicast group.
850 * Application layer ID for the message. Opaque to multicast.
851 * @param group_generation
852 * Group generation of the message.
853 * Documented in struct GNUNET_MULTICAST_MessageHeader.
855 * Function to call to get the message.
857 * Closure for @a notify.
859 * @return Message handle on success,
860 * NULL on error (i.e. another request is already pending).
862 struct GNUNET_MULTICAST_OriginTransmitHandle *
863 GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
865 uint64_t group_generation,
866 GNUNET_MULTICAST_OriginTransmitNotify notify,
870 if (GNUNET_YES == orig->grp.in_transmit)
872 orig->grp.in_transmit = GNUNET_YES;
875 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
877 tmit->message_id = message_id;
878 tmit->group_generation = group_generation;
879 tmit->notify = notify;
880 tmit->notify_cls = notify_cls;
882 origin_to_all (orig);
888 * Resume message transmission to multicast group.
891 * Transmission to cancel.
894 GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
896 origin_to_all (th->origin);
901 * Cancel request for message transmission to multicast group.
904 * Transmission to cancel.
907 GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
913 * Join a multicast group.
915 * The entity joining is always the local peer. Further information about the
916 * candidate can be provided in the @a join_request message. If the join fails, the
917 * @a message_cb is invoked with a (failure) response and then with NULL. If
918 * the join succeeds, outstanding (state) messages and ongoing multicast
919 * messages will be given to the @a message_cb until the member decides to part
920 * the group. The @a test_cb and @a replay_cb functions may be called at
921 * anytime by the multicast service to support relaying messages to other
922 * members of the group.
925 * Configuration to use.
927 * ECC public key that identifies the group to join.
929 * ECC key that identifies the member
930 * and used to sign requests sent to the origin.
932 * Peer ID of the origin to send unicast requsets to. If NULL,
933 * unicast requests are sent back via multiple hops on the reverse path
934 * of multicast messages.
936 * Number of peers in the @a relays array.
938 * Peer identities of members of the group, which serve as relays
939 * and can be used to join the group at. and send the @a join_request to.
940 * If empty, the @a join_request is sent directly to the @a origin.
942 * Application-dependent join message to be passed to the peer @a origin.
943 * @param join_request_cb
944 * Function called to approve / disapprove joining of a peer.
945 * @param join_decision_cb
946 * Function called to inform about the join decision.
947 * @param member_test_cb
948 * Function multicast can use to test group membership.
949 * @param replay_frag_cb
950 * Function that can be called to replay message fragments
951 * this peer already knows from this group. NULL if this
952 * client is unable to support replay.
953 * @param replay_msg_cb
954 * Function that can be called to replay message fragments
955 * this peer already knows from this group. NULL if this
956 * client is unable to support replay.
958 * Function to be called for all message fragments we
959 * receive from the group, excluding those our @a replay_cb
962 * Closure for callbacks.
964 * @return Handle for the member, NULL on error.
966 struct GNUNET_MULTICAST_Member *
967 GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
968 const struct GNUNET_CRYPTO_EddsaPublicKey *group_key,
969 const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key,
970 const struct GNUNET_PeerIdentity *origin,
971 uint16_t relay_count,
972 const struct GNUNET_PeerIdentity *relays,
973 const struct GNUNET_MessageHeader *join_msg,
974 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
975 GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
976 GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
977 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
978 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
979 GNUNET_MULTICAST_MessageCallback message_cb,
982 struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
983 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
985 uint16_t relay_size = relay_count * sizeof (*relays);
986 uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
987 struct MulticastMemberJoinMessage *
988 join = GNUNET_malloc (sizeof (*join) + relay_size + join_msg_size);
989 join->header.size = htons (sizeof (*join) + relay_size + join_msg_size);
990 join->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
991 join->group_key = *group_key;
992 join->member_key = *member_key;
993 join->origin = *origin;
994 join->relay_count = ntohl (relay_count);
996 memcpy (&join[1], relays, relay_size);
997 if (0 < join_msg_size)
998 memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
1000 grp->connect_msg = (struct GNUNET_MessageHeader *) join;
1001 grp->is_origin = GNUNET_NO;
1004 mem->join_dcsn_cb = join_decision_cb;
1005 grp->join_req_cb = join_request_cb;
1006 grp->member_test_cb = member_test_cb;
1007 grp->replay_frag_cb = replay_frag_cb;
1008 grp->replay_msg_cb = replay_msg_cb;
1009 grp->message_cb = message_cb;
1012 grp->client = GNUNET_CLIENT_MANAGER_connect (cfg, "multicast", member_handlers);
1013 GNUNET_CLIENT_MANAGER_set_user_context_ (grp->client, mem, sizeof (*grp));
1014 group_send_connect_msg (grp);
1021 * Part a multicast group.
1023 * Disconnects from all group members and invalidates the @a member handle.
1025 * An application-dependent part message can be transmitted beforehand using
1026 * #GNUNET_MULTICAST_member_to_origin())
1029 * Membership handle.
1032 GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
1033 GNUNET_ContinuationCallback part_cb,
1036 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1038 grp->is_disconnecting = GNUNET_YES;
1039 grp->disconnect_cb = part_cb;
1040 grp->disconnect_cls = part_cls;
1042 GNUNET_CLIENT_MANAGER_disconnect (mem->grp.client, GNUNET_YES,
1043 member_cleanup, mem);
1048 member_replay_request (struct GNUNET_MULTICAST_Member *mem,
1049 uint64_t fragment_id,
1050 uint64_t message_id,
1051 uint64_t fragment_offset,
1054 struct MulticastReplayRequestMessage rep = {
1056 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST),
1057 .size = htons (sizeof (rep)),
1059 .fragment_id = GNUNET_htonll (fragment_id),
1060 .message_id = GNUNET_htonll (message_id),
1061 .fragment_offset = GNUNET_htonll (fragment_offset),
1062 .flags = GNUNET_htonll (flags),
1064 GNUNET_CLIENT_MANAGER_transmit (mem->grp.client, &rep.header);
1069 * Request a fragment to be replayed by fragment ID.
1071 * Useful if messages below the @e max_known_fragment_id given when joining are
1072 * needed and not known to the client.
1075 * Membership handle.
1076 * @param fragment_id
1077 * ID of a message fragment that this client would like to see replayed.
1079 * Additional flags for the replay request.
1080 * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback
1082 * Function to call when the replayed message fragment arrives.
1084 * Closure for @a result_cb.
1086 * @return Replay request handle.
1088 struct GNUNET_MULTICAST_MemberReplayHandle *
1089 GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem,
1090 uint64_t fragment_id,
1092 GNUNET_MULTICAST_ResultCallback result_cb,
1095 member_replay_request (mem, fragment_id, 0, 0, flags);
1100 * Request a message fragment to be replayed.
1102 * Useful if messages below the @e max_known_fragment_id given when joining are
1103 * needed and not known to the client.
1106 * Membership handle.
1108 * ID of the message this client would like to see replayed.
1109 * @param fragment_offset
1110 * Offset of the fragment within the message to replay.
1112 * Additional flags for the replay request.
1113 * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback
1115 * Function to call for each replayed message fragment.
1117 * Closure for @a result_cb.
1119 * @return Replay request handle, NULL on error.
1121 struct GNUNET_MULTICAST_MemberReplayHandle *
1122 GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem,
1123 uint64_t message_id,
1124 uint64_t fragment_offset,
1126 GNUNET_MULTICAST_ResultCallback result_cb,
1129 member_replay_request (mem, 0, message_id, fragment_offset, flags);
1134 * Cancel a replay request.
1137 * Request to cancel.
1140 GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh)
1146 member_to_origin (struct GNUNET_MULTICAST_Member *mem)
1148 LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
1149 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1150 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1152 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
1153 struct GNUNET_MULTICAST_RequestHeader *req = GNUNET_malloc (buf_size);
1154 int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
1156 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
1157 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
1159 LOG (GNUNET_ERROR_TYPE_ERROR,
1160 "MemberTransmitNotify() returned error or invalid message size.\n");
1161 /* FIXME: handle error */
1166 if (GNUNET_NO == ret && 0 == buf_size)
1168 /* Transmission paused. */
1173 req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
1174 req->header.size = htons (sizeof (*req) + buf_size);
1175 req->request_id = GNUNET_htonll (tmit->request_id);
1176 req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
1177 tmit->fragment_offset += sizeof (*req) + buf_size;
1179 GNUNET_CLIENT_MANAGER_transmit (grp->client, &req->header);
1184 * Send a message to the origin of the multicast group.
1187 * Membership handle.
1189 * Application layer ID for the request. Opaque to multicast.
1191 * Callback to call to get the message.
1193 * Closure for @a notify.
1195 * @return Handle to cancel request, NULL on error (i.e. request already pending).
1197 struct GNUNET_MULTICAST_MemberTransmitHandle *
1198 GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
1199 uint64_t request_id,
1200 GNUNET_MULTICAST_MemberTransmitNotify notify,
1204 if (GNUNET_YES == mem->grp.in_transmit)
1206 mem->grp.in_transmit = GNUNET_YES;
1209 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1211 tmit->request_id = request_id;
1212 tmit->notify = notify;
1213 tmit->notify_cls = notify_cls;
1215 member_to_origin (mem);
1221 * Resume message transmission to origin.
1224 * Transmission to cancel.
1227 GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1229 member_to_origin (th->member);
1234 * Cancel request for message transmission to origin.
1237 * Transmission to cancel.
1240 GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1245 /* end of multicast_api.c */