2 This file is part of GNUnet.
3 Copyright (C) 2009 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/gnunet-service-multicast.c
23 * @brief program that does multicast
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_applications.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_cadet_service.h"
33 #include "gnunet_multicast_service.h"
34 #include "multicast.h"
37 * Handle to our current configuration.
39 static const struct GNUNET_CONFIGURATION_Handle *cfg;
44 static struct GNUNET_SERVER_Handle *server;
48 * Only used during initialization.
50 static struct GNUNET_CORE_Handle *core;
55 static struct GNUNET_CADET_Handle *cadet;
58 * Identity of this peer.
60 static struct GNUNET_PeerIdentity this_peer;
63 * Handle to the statistics service.
65 static struct GNUNET_STATISTICS_Handle *stats;
68 * Notification context, simplifies client broadcasts.
70 static struct GNUNET_SERVER_NotificationContext *nc;
73 * All connected origin clients.
74 * Group's pub_key_hash -> struct Origin * (uniq)
76 static struct GNUNET_CONTAINER_MultiHashMap *origins;
79 * All connected member clients.
80 * Group's pub_key_hash -> struct Member * (multi)
82 static struct GNUNET_CONTAINER_MultiHashMap *members;
85 * Connected member clients per group.
86 * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq)
88 static struct GNUNET_CONTAINER_MultiHashMap *group_members;
91 * Incoming CADET channels.
92 * Group's pub_key_hash -> struct Channel * (multi)
94 static struct GNUNET_CONTAINER_MultiHashMap *channels_in;
97 * Outgoing CADET channels.
98 * Group's pub_key_hash -> struct Channel * (multi)
100 static struct GNUNET_CONTAINER_MultiHashMap *channels_out;
103 * Join status of a remote peer.
113 enum ChannelDirection
121 * Context for a CADET channel.
126 * Group the channel belongs to.
128 * Only set for outgoing channels.
135 struct GNUNET_CADET_Channel *channel;
138 * CADET transmission handle.
140 struct GNUNET_CADET_TransmitHandle *tmit_handle;
143 * Public key of the target group.
145 struct GNUNET_CRYPTO_EddsaPublicKey group_key;
148 * Hash of @a group_key.
150 struct GNUNET_HashCode group_key_hash;
153 * Public key of the joining member.
155 struct GNUNET_CRYPTO_EcdsaPublicKey member_key;
158 * Remote peer identity.
160 struct GNUNET_PeerIdentity peer;
163 * Is the remote peer admitted to the group?
164 * @see enum JoinStatus
170 * @see enum ChannelDirection
177 * List of connected clients.
181 struct ClientList *prev;
182 struct ClientList *next;
183 struct GNUNET_SERVER_Client *client;
187 * Common part of the client context for both an origin and member.
191 struct ClientList *clients_head;
192 struct ClientList *clients_tail;
195 * Public key of the group.
197 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
200 * Hash of @a pub_key.
202 struct GNUNET_HashCode pub_key_hash;
205 * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
210 * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
212 uint8_t disconnected;
217 * Client context for a group's origin.
224 * Private key of the group.
226 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
229 * Last message fragment ID sent to the group.
231 uint64_t max_fragment_id;
236 * Client context for a group member.
243 * Private key of the member.
245 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
248 * Public key of the member.
250 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
253 * Hash of @a pub_key.
255 struct GNUNET_HashCode pub_key_hash;
258 * Join request sent to the origin / members.
260 struct MulticastJoinRequestMessage *join_req;
263 * Join decision sent in reply to our request.
265 * Only a positive decision is stored here, in case of a negative decision the
266 * client is disconnected.
268 struct MulticastJoinDecisionMessageHeader *join_dcsn;
271 * CADET channel to the origin.
273 struct Channel *origin_channel;
276 * Peer identity of origin.
278 struct GNUNET_PeerIdentity origin;
281 * Peer identity of relays (other members to connect).
283 struct GNUNET_PeerIdentity *relays;
286 * Last request fragment ID sent to the origin.
288 uint64_t max_fragment_id;
291 * Number of @a relays.
293 uint32_t relay_count;
298 * Task run during shutdown.
304 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
308 GNUNET_CORE_disconnect (core);
313 GNUNET_CADET_disconnect (cadet);
318 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
321 /* FIXME: do more clean up here */
326 * Clean up origin data structures after a client disconnected.
329 cleanup_origin (struct Origin *orig)
331 struct Group *grp = &orig->grp;
332 GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
337 * Clean up member data structures after a client disconnected.
340 cleanup_member (struct Member *mem)
342 struct Group *grp = &mem->grp;
343 struct GNUNET_CONTAINER_MultiHashMap *
344 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
346 GNUNET_assert (NULL != grp_mem);
347 GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
349 if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
351 GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
353 GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
355 if (NULL != mem->join_dcsn)
357 GNUNET_free (mem->join_dcsn);
358 mem->join_dcsn = NULL;
360 GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
365 * Clean up group data structures after a client disconnected.
368 cleanup_group (struct Group *grp)
370 (GNUNET_YES == grp->is_origin)
371 ? cleanup_origin ((struct Origin *) grp)
372 : cleanup_member ((struct Member *) grp);
379 * Called whenever a client is disconnected.
381 * Frees our resources associated with that client.
383 * @param cls Closure.
384 * @param client Client handle.
387 client_notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
393 = GNUNET_SERVER_client_get_user_context (client, struct Group);
397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398 "%p User context is NULL in client_disconnect()\n", grp);
403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404 "%p Client (%s) disconnected from group %s\n",
405 grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
406 GNUNET_h2s (&grp->pub_key_hash));
408 struct ClientList *cl = grp->clients_head;
411 if (cl->client == client)
413 GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
420 if (NULL == grp->clients_head)
421 { /* Last client disconnected. */
423 if (NULL != grp->tmit_head)
424 { /* Send pending messages via CADET before cleanup. */
425 transmit_message (grp);
437 * Send message to all clients connected to the group.
440 client_send_msg (const struct Group *grp,
441 const struct GNUNET_MessageHeader *msg)
443 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
444 "%p Sending message to clients.\n", grp);
446 struct ClientList *cl = grp->clients_head;
449 GNUNET_SERVER_notification_context_add (nc, cl->client);
450 GNUNET_SERVER_notification_context_unicast (nc, cl->client, msg, GNUNET_NO);
457 * Iterator callback for sending a message to origin clients.
460 client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
463 const struct GNUNET_MessageHeader *msg = cls;
464 struct Member *orig = origin;
466 client_send_msg (&orig->grp, msg);
472 * Iterator callback for sending a message to member clients.
475 client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
478 const struct GNUNET_MessageHeader *msg = cls;
479 struct Member *mem = member;
481 if (NULL != mem->join_dcsn)
482 { /* Only send message to admitted members */
483 client_send_msg (&mem->grp, msg);
490 * Send message to all origin and member clients connected to the group.
492 * @param grp The group to send @a msg to.
493 * @param msg Message to send.
496 client_send_all (struct GNUNET_HashCode *pub_key_hash,
497 const struct GNUNET_MessageHeader *msg)
501 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
502 client_send_origin_cb,
505 n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash,
506 client_send_member_cb,
513 * Send message to all origin clients connected to the group.
515 * @param grp The group to send @a msg to.
516 * @param msg Message to send.
519 client_send_origin (struct GNUNET_HashCode *pub_key_hash,
520 const struct GNUNET_MessageHeader *msg)
524 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
525 client_send_origin_cb,
532 * CADET is ready to transmit a message.
535 cadet_notify_transmit_ready (void *cls, size_t buf_size, void *buf)
539 /* FIXME: connection closed */
542 const struct GNUNET_MessageHeader *msg = cls;
543 uint16_t msg_size = ntohs (msg->size);
544 GNUNET_assert (msg_size <= buf_size);
545 memcpy (buf, msg, msg_size);
551 * Send a message to a CADET channel.
553 * @param chn Channel.
554 * @param msg Message.
557 cadet_send_msg (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
560 = GNUNET_CADET_notify_transmit_ready (chn->channel, GNUNET_NO,
561 GNUNET_TIME_UNIT_FOREVER_REL,
563 &cadet_notify_transmit_ready,
565 GNUNET_assert (NULL != chn->tmit_handle);
570 * Create new outgoing CADET channel.
573 * Peer to connect to.
575 * Public key of group the channel belongs to.
576 * @param group_key_hash
577 * Hash of @a group_key.
581 static struct Channel *
582 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
584 struct Channel *chn = GNUNET_malloc (sizeof (*chn));
586 chn->group_key = grp->pub_key;
587 chn->group_key_hash = grp->pub_key_hash;
589 chn->direction = DIR_OUTGOING;
590 chn->join_status = JOIN_WAITING;
591 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
592 GNUNET_APPLICATION_TYPE_MULTICAST,
593 GNUNET_CADET_OPTION_RELIABLE);
594 GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_key_hash, chn,
595 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
601 * Create CADET channel and send a join request.
604 cadet_send_join_request (struct Member *mem)
606 mem->origin_channel = cadet_channel_create (&mem->grp, &mem->origin);
607 cadet_send_msg (mem->origin_channel, &mem->join_req->header);
610 for (i = 0; i < mem->relay_count; i++)
613 chn = cadet_channel_create (&mem->grp, &mem->relays[i]);
614 cadet_send_msg (chn, &mem->join_req->header);
620 cadet_send_join_decision_cb (void *cls,
621 const struct GNUNET_HashCode *group_key_hash,
624 const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
625 struct Channel *chn = channel;
627 if (0 == memcmp (&hdcsn->member_key, &chn->member_key, sizeof (chn->member_key))
628 && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer)))
630 cadet_send_msg (chn, &hdcsn->header);
638 * Send join decision to a remote peer.
641 cadet_send_join_decision (struct Group *grp,
642 const struct MulticastJoinDecisionMessageHeader *hdcsn)
644 GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash,
645 &cadet_send_join_decision_cb,
651 * Iterator callback for sending a message to origin clients.
654 cadet_send_members_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
657 const struct GNUNET_MessageHeader *msg = cls;
658 struct Channel *chn = channel;
659 if (JOIN_ADMITTED == chn->join_status)
660 cadet_send_msg (chn, msg);
666 cadet_send_members (struct GNUNET_HashCode *pub_key_hash,
667 const struct GNUNET_MessageHeader *msg)
670 if (channels_in != NULL)
671 n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash,
672 cadet_send_members_cb,
678 * Handle a connecting client starting an origin.
681 client_recv_origin_start (void *cls, struct GNUNET_SERVER_Client *client,
682 const struct GNUNET_MessageHeader *m)
684 const struct MulticastOriginStartMessage *
685 msg = (const struct MulticastOriginStartMessage *) m;
687 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
688 struct GNUNET_HashCode pub_key_hash;
690 GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
691 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
694 orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
699 orig = GNUNET_new (struct Origin);
700 orig->priv_key = msg->group_key;
701 orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
703 grp->is_origin = GNUNET_YES;
704 grp->pub_key = pub_key;
705 grp->pub_key_hash = pub_key_hash;
707 GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
708 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
715 struct ClientList *cl = GNUNET_new (struct ClientList);
717 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "%p Client connected as origin to group %s.\n",
721 orig, GNUNET_h2s (&grp->pub_key_hash));
723 GNUNET_SERVER_client_set_user_context (client, grp);
724 GNUNET_SERVER_receive_done (client, GNUNET_OK);
729 * Handle a connecting client joining a group.
732 client_recv_member_join (void *cls, struct GNUNET_SERVER_Client *client,
733 const struct GNUNET_MessageHeader *m)
735 const struct MulticastMemberJoinMessage *
736 msg = (const struct MulticastMemberJoinMessage *) m;
737 uint16_t msg_size = ntohs (msg->header.size);
739 struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
740 struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
742 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
743 GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
744 GNUNET_CRYPTO_hash (&msg->group_key, sizeof (msg->group_key), &pub_key_hash);
746 struct GNUNET_CONTAINER_MultiHashMap *
747 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
748 struct Member *mem = NULL;
753 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
757 mem = GNUNET_new (struct Member);
758 mem->priv_key = msg->member_key;
759 mem->pub_key = mem_pub_key;
760 mem->pub_key_hash = mem_pub_key_hash;
761 mem->max_fragment_id = 0; // FIXME
764 grp->is_origin = GNUNET_NO;
765 grp->pub_key = msg->group_key;
766 grp->pub_key_hash = pub_key_hash;
770 grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
771 GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
772 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
774 GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
775 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
776 GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
777 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
784 struct ClientList *cl = GNUNET_new (struct ClientList);
786 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789 "%p Client connected to group %s..\n",
790 mem, GNUNET_h2s (&grp->pub_key_hash));
791 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793 "%p ..as member %s (%s).\n",
794 mem, GNUNET_h2s (&mem->pub_key_hash), str);
797 GNUNET_SERVER_client_set_user_context (client, grp);
799 if (NULL != mem->join_dcsn)
800 { /* Already got a join decision, send it to client. */
801 GNUNET_SERVER_notification_context_add (nc, client);
802 GNUNET_SERVER_notification_context_unicast (nc, client,
803 (struct GNUNET_MessageHeader *)
807 else if (grp->clients_head == grp->clients_tail)
808 { /* First client of the group, send join request. */
809 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
810 uint32_t relay_count = ntohl (msg->relay_count);
811 uint16_t relay_size = relay_count * sizeof (*relays);
812 struct GNUNET_MessageHeader *join_msg = NULL;
813 uint16_t join_msg_size = 0;
814 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
817 join_msg = (struct GNUNET_MessageHeader *)
818 (((char *) &msg[1]) + relay_size);
819 join_msg_size = ntohs (join_msg->size);
821 if (sizeof (*msg) + relay_size + join_msg_size != msg_size)
824 GNUNET_SERVER_client_disconnect (client);
828 struct MulticastJoinRequestMessage *
829 req = GNUNET_malloc (sizeof (*req) + join_msg_size);
830 req->header.size = htons (sizeof (*req) + join_msg_size);
831 req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
832 req->group_key = grp->pub_key;
833 req->peer = this_peer;
834 GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_key);
835 if (0 < join_msg_size)
836 memcpy (&req[1], join_msg, join_msg_size);
838 req->member_key = mem->pub_key;
839 req->purpose.size = htonl (msg_size
840 - sizeof (req->header)
841 - sizeof (req->reserved)
842 - sizeof (req->signature));
843 req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
845 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
848 /* FIXME: handle error */
852 if (NULL != mem->join_req)
853 GNUNET_free (mem->join_req);
856 if (0 == client_send_origin (&grp->pub_key_hash, &mem->join_req->header))
857 { /* No local origins, send to remote origin */
858 cadet_send_join_request (mem);
861 GNUNET_SERVER_receive_done (client, GNUNET_OK);
866 client_send_join_decision (struct Member *mem,
867 const struct MulticastJoinDecisionMessageHeader *hdcsn)
869 client_send_msg (&mem->grp, &hdcsn->header);
871 const struct MulticastJoinDecisionMessage *
872 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
873 if (GNUNET_YES == ntohl (dcsn->is_admitted))
874 { /* Member admitted, store join_decision. */
875 uint16_t dcsn_size = ntohs (dcsn->header.size);
876 mem->join_dcsn = GNUNET_malloc (dcsn_size);
877 memcpy (mem->join_dcsn, dcsn, dcsn_size);
880 { /* Refused entry, disconnect clients. */
882 struct ClientList *cl = mem->grp.clients_head;
885 struct GNUNET_SERVER_Client *client = cl->client;
887 GNUNET_SERVER_client_disconnect (client);
895 * Join decision from client.
898 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
899 const struct GNUNET_MessageHeader *m)
902 grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
903 const struct MulticastJoinDecisionMessageHeader *
904 hdcsn = (const struct MulticastJoinDecisionMessageHeader *) m;
909 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913 "%p Got join decision from client for group %s..\n",
914 grp, GNUNET_h2s (&grp->pub_key_hash));
916 struct GNUNET_CONTAINER_MultiHashMap *
917 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
919 struct Member *mem = NULL;
922 struct GNUNET_HashCode member_key_hash;
923 GNUNET_CRYPTO_hash (&hdcsn->member_key, sizeof (hdcsn->member_key),
925 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927 "%p ..and member %s: %p\n",
928 grp, GNUNET_h2s (&member_key_hash), mem);
931 { /* Found local member */
932 client_send_join_decision (mem, hdcsn);
935 { /* Look for remote member */
936 cadet_send_join_decision (grp, hdcsn);
938 GNUNET_SERVER_receive_done (client, GNUNET_OK);
943 * Incoming message from a client.
946 client_recv_multicast_message (void *cls, struct GNUNET_SERVER_Client *client,
947 const struct GNUNET_MessageHeader *m)
950 grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
951 struct GNUNET_MULTICAST_MessageHeader *out;
957 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
960 GNUNET_assert (GNUNET_YES == grp->is_origin);
961 orig = (struct Origin *) grp;
962 /* FIXME: yucky, should use separate message structs for P2P and CS! */
963 out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (m);
965 out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
966 out->purpose.size = htonl (ntohs (out->header.size)
967 - sizeof (out->header)
968 - sizeof (out->hop_counter)
969 - sizeof (out->signature));
970 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
972 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
978 client_send_all (&grp->pub_key_hash, &out->header);
979 cadet_send_members (&grp->pub_key_hash, &out->header);
982 GNUNET_SERVER_receive_done (client, GNUNET_OK);
987 * Incoming request from a client.
990 client_recv_multicast_request (void *cls, struct GNUNET_SERVER_Client *client,
991 const struct GNUNET_MessageHeader *m)
993 struct Group *grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
995 struct GNUNET_MULTICAST_RequestHeader *out;
1000 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1003 GNUNET_assert (GNUNET_NO == grp->is_origin);
1004 mem = (struct Member *) grp;
1005 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1006 out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (m);
1008 out->member_key = mem->pub_key;
1009 out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1010 out->purpose.size = htonl (ntohs (out->header.size)
1011 - sizeof (out->header)
1012 - sizeof (out->member_key)
1013 - sizeof (out->signature));
1014 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1016 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1022 if (0 == client_send_origin (&grp->pub_key_hash, &out->header))
1023 { /* No local origins, send to remote origin */
1024 if (NULL != mem->origin_channel)
1026 cadet_send_msg (mem->origin_channel, &out->header);
1030 /* FIXME: not yet connected to origin */
1031 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1037 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1042 * A new client connected.
1045 client_notify_connect (void *cls, struct GNUNET_SERVER_Client *client)
1047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
1048 /* FIXME: send connect ACK */
1053 * Message handlers for the server.
1055 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1056 { &client_recv_origin_start, NULL,
1057 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, 0 },
1059 { &client_recv_member_join, NULL,
1060 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, 0 },
1062 { &client_recv_join_decision, NULL,
1063 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, 0 },
1065 { &client_recv_multicast_message, NULL,
1066 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
1068 { &client_recv_multicast_request, NULL,
1069 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
1076 * New incoming CADET channel.
1079 cadet_notify_channel_new (void *cls,
1080 struct GNUNET_CADET_Channel *channel,
1081 const struct GNUNET_PeerIdentity *initiator,
1083 enum GNUNET_CADET_ChannelOption options)
1090 * CADET channel is being destroyed.
1093 cadet_notify_channel_end (void *cls,
1094 const struct GNUNET_CADET_Channel *channel,
1100 struct Channel *chn = ctx;
1101 if (NULL != chn->grp)
1103 if (GNUNET_NO == chn->grp->is_origin)
1105 struct Member *mem = (struct Member *) chn->grp;
1106 if (chn == mem->origin_channel)
1107 mem->origin_channel = NULL;
1115 * Incoming join request message from CADET.
1118 cadet_recv_join_request (void *cls,
1119 struct GNUNET_CADET_Channel *channel,
1121 const struct GNUNET_MessageHeader *m)
1123 const struct MulticastJoinRequestMessage *
1124 req = (const struct MulticastJoinRequestMessage *) m;
1125 uint16_t size = ntohs (m->size);
1126 if (size < sizeof (*req))
1128 GNUNET_break_op (0);
1129 return GNUNET_SYSERR;
1133 GNUNET_break_op (0);
1134 return GNUNET_SYSERR;
1136 if (ntohl (req->purpose.size) != (size
1137 - sizeof (req->header)
1138 - sizeof (req->reserved)
1139 - sizeof (req->signature)))
1141 GNUNET_break_op (0);
1142 return GNUNET_SYSERR;
1145 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1146 &req->purpose, &req->signature,
1149 GNUNET_break_op (0);
1150 return GNUNET_SYSERR;
1153 struct GNUNET_HashCode group_key_hash;
1154 GNUNET_CRYPTO_hash (&req->group_key, sizeof (req->group_key), &group_key_hash);
1156 struct Channel *chn = GNUNET_malloc (sizeof *chn);
1157 chn->channel = channel;
1158 chn->group_key = req->group_key;
1159 chn->group_key_hash = group_key_hash;
1160 chn->member_key = req->member_key;
1161 chn->peer = req->peer;
1162 chn->join_status = JOIN_WAITING;
1163 GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group_key_hash, chn,
1164 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1166 client_send_all (&group_key_hash, m);
1172 * Incoming join decision message from CADET.
1175 cadet_recv_join_decision (void *cls,
1176 struct GNUNET_CADET_Channel *channel,
1178 const struct GNUNET_MessageHeader *m)
1180 const struct MulticastJoinDecisionMessage *
1181 dcsn = (const struct MulticastJoinDecisionMessage *) m;
1182 uint16_t size = ntohs (m->size);
1183 if (size < sizeof (*dcsn))
1185 GNUNET_break_op (0);
1186 return GNUNET_SYSERR;
1188 struct Channel *chn = *ctx;
1191 GNUNET_break_op (0);
1192 return GNUNET_SYSERR;
1194 if (NULL == chn->grp || GNUNET_NO != chn->grp->is_origin)
1196 GNUNET_break_op (0);
1197 return GNUNET_SYSERR;
1199 switch (chn->join_status)
1202 return GNUNET_SYSERR;
1207 case JOIN_NOT_ASKED:
1212 struct MulticastJoinDecisionMessageHeader *
1213 hdcsn = GNUNET_malloc (sizeof (*hdcsn) + size);
1214 hdcsn->peer = chn->peer;
1215 memcpy (&hdcsn[1], dcsn, sizeof (*hdcsn) + size);
1217 struct Member *mem = (struct Member *) chn->grp;
1218 client_send_join_decision (mem, hdcsn);
1219 GNUNET_free (hdcsn);
1220 if (GNUNET_YES == ntohs (dcsn->is_admitted))
1222 chn->join_status = JOIN_ADMITTED;
1227 chn->join_status = JOIN_REFUSED;
1228 return GNUNET_SYSERR;
1233 * Incoming multicast message from CADET.
1236 cadet_recv_message (void *cls,
1237 struct GNUNET_CADET_Channel *channel,
1239 const struct GNUNET_MessageHeader *m)
1241 const struct GNUNET_MULTICAST_MessageHeader *
1242 msg = (const struct GNUNET_MULTICAST_MessageHeader *) m;
1243 uint16_t size = ntohs (m->size);
1244 if (size < sizeof (*msg))
1246 GNUNET_break_op (0);
1247 return GNUNET_SYSERR;
1249 struct Channel *chn = *ctx;
1252 GNUNET_break_op (0);
1253 return GNUNET_SYSERR;
1255 if (ntohl (msg->purpose.size) != (size
1256 - sizeof (msg->header)
1257 - sizeof (msg->hop_counter)
1258 - sizeof (msg->signature)))
1260 GNUNET_break_op (0);
1261 return GNUNET_SYSERR;
1264 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1265 &msg->purpose, &msg->signature,
1268 GNUNET_break_op (0);
1269 return GNUNET_SYSERR;
1272 client_send_all (&chn->group_key_hash, m);
1278 * Incoming multicast request message from CADET.
1281 cadet_recv_request (void *cls,
1282 struct GNUNET_CADET_Channel *channel,
1284 const struct GNUNET_MessageHeader *m)
1286 const struct GNUNET_MULTICAST_RequestHeader *
1287 req = (const struct GNUNET_MULTICAST_RequestHeader *) m;
1288 uint16_t size = ntohs (m->size);
1289 if (size < sizeof (*req))
1291 GNUNET_break_op (0);
1292 return GNUNET_SYSERR;
1294 struct Channel *chn = *ctx;
1297 GNUNET_break_op (0);
1298 return GNUNET_SYSERR;
1300 if (ntohl (req->purpose.size) != (size
1301 - sizeof (req->header)
1302 - sizeof (req->member_key)
1303 - sizeof (req->signature)))
1305 GNUNET_break_op (0);
1306 return GNUNET_SYSERR;
1309 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1310 &req->purpose, &req->signature,
1313 GNUNET_break_op (0);
1314 return GNUNET_SYSERR;
1317 client_send_origin (&chn->group_key_hash, m);
1323 * Message handlers for CADET.
1325 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1326 { &cadet_recv_join_request, GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, 0 },
1327 { &cadet_recv_message, GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
1328 { &cadet_recv_request, GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
1334 * Listening ports for CADET.
1336 static const uint32_t cadet_ports[] = { GNUNET_APPLICATION_TYPE_MULTICAST, 0 };
1340 * Connected to core service.
1343 core_connected_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1345 this_peer = *my_identity;
1347 stats = GNUNET_STATISTICS_create ("multicast", cfg);
1348 origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1349 members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1350 group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1351 channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1352 channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1354 cadet = GNUNET_CADET_connect (cfg, NULL,
1355 &cadet_notify_channel_new,
1356 &cadet_notify_channel_end,
1357 cadet_handlers, cadet_ports);
1359 nc = GNUNET_SERVER_notification_context_create (server, 1);
1360 GNUNET_SERVER_add_handlers (server, server_handlers);
1361 GNUNET_SERVER_disconnect_notify (server, &client_notify_disconnect, NULL);
1363 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1371 * @param cls closure
1372 * @param server the initialized server
1373 * @param cfg configuration to use
1376 run (void *cls, struct GNUNET_SERVER_Handle *srv,
1377 const struct GNUNET_CONFIGURATION_Handle *c)
1381 GNUNET_SERVER_connect_notify (server, &client_notify_connect, NULL);
1382 core = GNUNET_CORE_connect (cfg, NULL, &core_connected_cb, NULL, NULL,
1383 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1388 * The main function for the multicast service.
1390 * @param argc number of arguments from the command line
1391 * @param argv command line arguments
1392 * @return 0 ok, 1 on error
1395 main (int argc, char *const *argv)
1397 return (GNUNET_OK ==
1398 GNUNET_SERVICE_run (argc, argv, "multicast",
1399 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1402 /* end of gnunet-service-multicast.c */