2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file multicast/gnunet-service-multicast.c
21 * @brief program that does multicast
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_signatures.h"
27 #include "gnunet_applications.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_multicast_service.h"
31 #include "multicast.h"
34 * Handle to our current configuration.
36 static const struct GNUNET_CONFIGURATION_Handle *cfg;
41 static struct GNUNET_SERVICE_Handle *service;
46 static struct GNUNET_CADET_Handle *cadet;
49 * Identity of this peer.
51 static struct GNUNET_PeerIdentity this_peer;
54 * Handle to the statistics service.
56 static struct GNUNET_STATISTICS_Handle *stats;
59 * All connected origin clients.
60 * Group's pub_key_hash -> struct Origin * (uniq)
62 static struct GNUNET_CONTAINER_MultiHashMap *origins;
65 * All connected member clients.
66 * Group's pub_key_hash -> struct Member * (multi)
68 static struct GNUNET_CONTAINER_MultiHashMap *members;
71 * Connected member clients per group.
72 * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq)
74 static struct GNUNET_CONTAINER_MultiHashMap *group_members;
77 * Incoming CADET channels with connected children in the tree.
78 * Group's pub_key_hash -> struct Channel * (multi)
80 static struct GNUNET_CONTAINER_MultiHashMap *channels_in;
83 * Outgoing CADET channels connecting to parents in the tree.
84 * Group's pub_key_hash -> struct Channel * (multi)
86 static struct GNUNET_CONTAINER_MultiHashMap *channels_out;
89 * Incoming replay requests from CADET.
90 * Group's pub_key_hash ->
91 * H(fragment_id, message_id, fragment_offset, flags) -> struct Channel *
93 static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet;
96 * Incoming replay requests from clients.
97 * Group's pub_key_hash ->
98 * H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client *
100 static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client;
104 * Join status of a remote peer.
114 enum ChannelDirection
122 * Context for a CADET channel.
127 * Group the channel belongs to.
129 * Only set for outgoing channels.
136 struct GNUNET_CADET_Channel *channel;
140 * CADET transmission handle.
142 struct GNUNET_CADET_TransmitHandle *tmit_handle;
145 * Public key of the target group.
147 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
150 * Hash of @a group_pub_key.
152 struct GNUNET_HashCode group_pub_hash;
155 * Public key of the joining member.
157 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
160 * Remote peer identity.
162 struct GNUNET_PeerIdentity peer;
165 * Current window size, set by cadet_notify_window_change()
170 * Is the connection established?
175 * Is the remote peer admitted to the group?
176 * @see enum JoinStatus
181 * Number of messages waiting to be sent to CADET.
183 uint8_t msgs_pending;
187 * @see enum ChannelDirection
194 * List of connected clients.
198 struct ClientList *prev;
199 struct ClientList *next;
200 struct GNUNET_SERVICE_Client *client;
205 * Client context for an origin or member.
209 struct ClientList *clients_head;
210 struct ClientList *clients_tail;
213 * Public key of the group.
215 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
218 * Hash of @a pub_key.
220 struct GNUNET_HashCode pub_key_hash;
225 struct GNUNET_HashCode cadet_port_hash;
228 * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
230 uint8_t is_disconnected;
233 * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
238 struct Origin *origin;
239 struct Member *member;
245 * Client context for a group's origin.
252 * Private key of the group.
254 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
259 struct GNUNET_CADET_Port *cadet_port;
262 * Last message fragment ID sent to the group.
264 uint64_t max_fragment_id;
269 * Client context for a group member.
276 * Private key of the member.
278 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
281 * Public key of the member.
283 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
286 * Hash of @a pub_key.
288 struct GNUNET_HashCode pub_key_hash;
291 * Join request sent to the origin / members.
293 struct MulticastJoinRequestMessage *join_req;
296 * Join decision sent in reply to our request.
298 * Only a positive decision is stored here, in case of a negative decision the
299 * client is disconnected.
301 struct MulticastJoinDecisionMessageHeader *join_dcsn;
304 * CADET channel to the origin.
306 struct Channel *origin_channel;
309 * Peer identity of origin.
311 struct GNUNET_PeerIdentity origin;
314 * Peer identity of relays (other members to connect).
316 struct GNUNET_PeerIdentity *relays;
319 * Last request fragment ID sent to the origin.
321 uint64_t max_fragment_id;
324 * Number of @a relays.
326 uint32_t relay_count;
334 struct GNUNET_SERVICE_Client *client;
339 struct ReplayRequestKey
341 uint64_t fragment_id;
343 uint64_t fragment_offset;
348 static struct Channel *
349 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer);
352 cadet_channel_destroy (struct Channel *chn);
355 client_send_join_decision (struct Member *mem,
356 const struct MulticastJoinDecisionMessageHeader *hdcsn);
360 * Task run during shutdown.
365 shutdown_task (void *cls)
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371 GNUNET_CADET_disconnect (cadet);
376 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
379 /* FIXME: do more clean up here */
384 * Clean up origin data structures after a client disconnected.
387 cleanup_origin (struct Origin *orig)
389 struct Group *grp = &orig->group;
390 GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
391 if (NULL != orig->cadet_port)
393 GNUNET_CADET_close_port (orig->cadet_port);
394 orig->cadet_port = NULL;
401 * Clean up member data structures after a client disconnected.
404 cleanup_member (struct Member *mem)
406 struct Group *grp = &mem->group;
407 struct GNUNET_CONTAINER_MultiHashMap *
408 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
410 GNUNET_assert (NULL != grp_mem);
411 GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
413 if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
415 GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
417 GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
419 if (NULL != mem->join_dcsn)
421 GNUNET_free (mem->join_dcsn);
422 mem->join_dcsn = NULL;
424 if (NULL != mem->origin_channel)
426 GNUNET_CADET_channel_destroy (mem->origin_channel->channel);
427 mem->origin_channel = NULL;
429 GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
435 * Clean up group data structures after a client disconnected.
438 cleanup_group (struct Group *grp)
440 (GNUNET_YES == grp->is_origin)
441 ? cleanup_origin (grp->origin)
442 : cleanup_member (grp->member);
447 replay_key_hash (uint64_t fragment_id, uint64_t message_id,
448 uint64_t fragment_offset, uint64_t flags,
449 struct GNUNET_HashCode *key_hash)
451 struct ReplayRequestKey key = {
452 .fragment_id = fragment_id,
453 .message_id = message_id,
454 .fragment_offset = fragment_offset,
457 GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash);
462 * Remove channel from replay request hashmap.
467 * @return #GNUNET_YES if there are more entries to process,
468 * #GNUNET_NO when reached end of hashmap.
471 replay_req_remove_cadet (struct Channel *chn)
473 if (NULL == chn || NULL == chn->group)
474 return GNUNET_SYSERR;
476 struct GNUNET_CONTAINER_MultiHashMap *
477 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
478 &chn->group->pub_key_hash);
479 if (NULL == grp_replay_req)
482 struct GNUNET_CONTAINER_MultiHashMapIterator *
483 it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
484 struct GNUNET_HashCode key;
485 const struct Channel *c;
487 == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
492 GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn);
493 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
497 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
503 * Remove client from replay request hashmap.
508 * @return #GNUNET_YES if there are more entries to process,
509 * #GNUNET_NO when reached end of hashmap.
512 replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client)
514 struct GNUNET_CONTAINER_MultiHashMap *
515 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
517 if (NULL == grp_replay_req)
520 struct GNUNET_CONTAINER_MultiHashMapIterator *
521 it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
522 struct GNUNET_HashCode key;
523 const struct GNUNET_SERVICE_Client *c;
525 == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
530 GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client);
531 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
535 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
541 * Send message to a client.
544 client_send (struct GNUNET_SERVICE_Client *client,
545 const struct GNUNET_MessageHeader *msg)
547 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
548 "%p Sending message to client.\n", client);
550 struct GNUNET_MQ_Envelope *
551 env = GNUNET_MQ_msg_copy (msg);
553 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
559 * Send message to all clients connected to the group.
562 client_send_group_keep_envelope (const struct Group *grp,
563 struct GNUNET_MQ_Envelope *env)
565 struct ClientList *cli = grp->clients_head;
567 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
568 "%p Sending message to all clients of the group.\n",
572 GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client),
580 * Send message to all clients connected to the group and
581 * takes care of freeing @env.
584 client_send_group (const struct Group *grp,
585 struct GNUNET_MQ_Envelope *env)
587 client_send_group_keep_envelope (grp, env);
588 GNUNET_MQ_discard (env);
593 * Iterator callback for sending a message to origin clients.
596 client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
599 struct GNUNET_MQ_Envelope *env = cls;
600 struct Member *orig = origin;
602 client_send_group_keep_envelope (&orig->group, env);
608 * Iterator callback for sending a message to member clients.
611 client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
614 struct GNUNET_MQ_Envelope *env = cls;
615 struct Member *mem = member;
617 if (NULL != mem->join_dcsn)
618 { /* Only send message to admitted members */
619 client_send_group_keep_envelope (&mem->group, env);
626 * Send message to all origin and member clients connected to the group.
628 * @param pub_key_hash
629 * H(key_pub) of the group.
634 client_send_all (struct GNUNET_HashCode *pub_key_hash,
635 struct GNUNET_MQ_Envelope *env)
638 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
639 client_send_origin_cb,
641 n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash,
642 client_send_member_cb,
644 GNUNET_MQ_discard (env);
650 * Send message to a random origin client or a random member client.
652 * @param grp The group to send @a msg to.
653 * @param msg Message to send.
656 client_send_random (struct GNUNET_HashCode *pub_key_hash,
657 struct GNUNET_MQ_Envelope *env)
660 n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb,
663 n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb,
665 GNUNET_MQ_discard (env);
671 * Send message to all origin clients connected to the group.
673 * @param pub_key_hash
674 * H(key_pub) of the group.
679 client_send_origin (struct GNUNET_HashCode *pub_key_hash,
680 struct GNUNET_MQ_Envelope *env)
683 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
684 client_send_origin_cb,
691 * Send fragment acknowledgement to all clients of the channel.
693 * @param pub_key_hash
694 * H(key_pub) of the group.
697 client_send_ack (struct GNUNET_HashCode *pub_key_hash)
699 struct GNUNET_MQ_Envelope *env;
701 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
702 "Sending message ACK to client.\n");
703 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK);
704 client_send_all (pub_key_hash, env);
708 struct CadetTransmitClosure
711 const struct GNUNET_MessageHeader *msg;
716 * Send a message to a CADET channel.
718 * @param chn Channel.
719 * @param msg Message.
722 cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
724 struct GNUNET_MQ_Envelope *
725 env = GNUNET_MQ_msg_copy (msg);
727 GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env);
729 if (0 < chn->window_size)
731 client_send_ack (&chn->group_pub_hash);
736 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
737 "%p Queuing message. Pending messages: %u\n",
738 chn, chn->msgs_pending);
744 * Create CADET channel and send a join request.
747 cadet_send_join_request (struct Member *mem)
749 mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin);
750 cadet_send_channel (mem->origin_channel, &mem->join_req->header);
753 for (i = 0; i < mem->relay_count; i++)
756 chn = cadet_channel_create (&mem->group, &mem->relays[i]);
757 cadet_send_channel (chn, &mem->join_req->header);
763 cadet_send_join_decision_cb (void *cls,
764 const struct GNUNET_HashCode *group_pub_hash,
767 const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
768 struct Channel *chn = channel;
770 const struct MulticastJoinDecisionMessage *dcsn =
771 (struct MulticastJoinDecisionMessage *) &hdcsn[1];
773 if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key))
774 && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer)))
776 if (GNUNET_YES == ntohl (dcsn->is_admitted))
778 chn->join_status = JOIN_ADMITTED;
782 chn->join_status = JOIN_REFUSED;
784 cadet_send_channel (chn, &hdcsn->header);
788 // return GNUNET_YES to continue the multihashmap_get iteration
794 * Send join decision to a remote peer.
797 cadet_send_join_decision (struct Group *grp,
798 const struct MulticastJoinDecisionMessageHeader *hdcsn)
800 GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash,
801 &cadet_send_join_decision_cb,
807 * Iterator callback for sending a message to origin clients.
810 cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
813 const struct GNUNET_MessageHeader *msg = cls;
814 struct Channel *chn = channel;
815 if (JOIN_ADMITTED == chn->join_status)
816 cadet_send_channel (chn, msg);
822 * Send message to all connected children.
825 cadet_send_children (struct GNUNET_HashCode *pub_key_hash,
826 const struct GNUNET_MessageHeader *msg)
829 if (channels_in != NULL)
830 n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash,
831 cadet_send_cb, (void *) msg);
836 #if 0 // unused as yet
838 * Send message to all connected parents.
841 cadet_send_parents (struct GNUNET_HashCode *pub_key_hash,
842 const struct GNUNET_MessageHeader *msg)
845 if (channels_in != NULL)
846 n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash,
847 cadet_send_cb, (void *) msg);
854 * CADET channel connect handler.
856 * @see GNUNET_CADET_ConnectEventHandler()
859 cadet_notify_connect (void *cls,
860 struct GNUNET_CADET_Channel *channel,
861 const struct GNUNET_PeerIdentity *source)
863 struct Channel *chn = GNUNET_malloc (sizeof (struct Channel));
865 chn->channel = channel;
866 chn->direction = DIR_INCOMING;
867 chn->join_status = JOIN_NOT_ASKED;
869 GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn,
870 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
876 * CADET window size change handler.
878 * @see GNUNET_CADET_WindowSizeEventHandler()
881 cadet_notify_window_change (void *cls,
882 const struct GNUNET_CADET_Channel *channel,
885 struct Channel *chn = cls;
887 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
888 "%p Window size changed to %d. Pending messages: %u\n",
889 chn, window_size, chn->msgs_pending);
891 chn->is_connected = GNUNET_YES;
892 chn->window_size = (int32_t) window_size;
894 for (int i = 0; i < window_size; i++)
896 if (0 < chn->msgs_pending)
898 client_send_ack (&chn->group_pub_hash);
910 * CADET channel disconnect handler.
912 * @see GNUNET_CADET_DisconnectEventHandler()
915 cadet_notify_disconnect (void *cls,
916 const struct GNUNET_CADET_Channel *channel)
921 struct Channel *chn = cls;
922 if (NULL != chn->group)
924 if (GNUNET_NO == chn->group->is_origin)
926 struct Member *mem = (struct Member *) chn->group;
927 if (chn == mem->origin_channel)
928 mem->origin_channel = NULL;
935 ret = replay_req_remove_cadet (chn);
937 while (GNUNET_YES == ret);
944 check_cadet_join_request (void *cls,
945 const struct MulticastJoinRequestMessage *req)
947 struct Channel *chn = cls;
950 || JOIN_NOT_ASKED != chn->join_status)
952 return GNUNET_SYSERR;
955 uint16_t size = ntohs (req->header.size);
956 if (size < sizeof (*req))
959 return GNUNET_SYSERR;
961 if (ntohl (req->purpose.size) != (size
962 - sizeof (req->header)
963 - sizeof (req->reserved)
964 - sizeof (req->signature)))
967 return GNUNET_SYSERR;
970 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
971 &req->purpose, &req->signature,
972 &req->member_pub_key))
975 return GNUNET_SYSERR;
983 * Incoming join request message from CADET.
986 handle_cadet_join_request (void *cls,
987 const struct MulticastJoinRequestMessage *req)
989 struct Channel *chn = cls;
990 GNUNET_CADET_receive_done (chn->channel);
992 struct GNUNET_HashCode group_pub_hash;
993 GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash);
994 chn->group_pub_key = req->group_pub_key;
995 chn->group_pub_hash = group_pub_hash;
996 chn->member_pub_key = req->member_pub_key;
997 chn->peer = req->peer;
998 chn->join_status = JOIN_WAITING;
1000 client_send_all (&group_pub_hash,
1001 GNUNET_MQ_msg_copy (&req->header));
1006 check_cadet_join_decision (void *cls,
1007 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1009 uint16_t size = ntohs (hdcsn->header.size);
1010 if (size < sizeof (struct MulticastJoinDecisionMessageHeader) +
1011 sizeof (struct MulticastJoinDecisionMessage))
1013 GNUNET_break_op (0);
1014 return GNUNET_SYSERR;
1017 struct Channel *chn = cls;
1021 return GNUNET_SYSERR;
1023 if (NULL == chn->group || GNUNET_NO != chn->group->is_origin)
1026 return GNUNET_SYSERR;
1028 switch (chn->join_status)
1031 return GNUNET_SYSERR;
1036 case JOIN_NOT_ASKED:
1046 * Incoming join decision message from CADET.
1049 handle_cadet_join_decision (void *cls,
1050 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1052 const struct MulticastJoinDecisionMessage *
1053 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1055 struct Channel *chn = cls;
1056 GNUNET_CADET_receive_done (chn->channel);
1058 // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer?
1059 struct Member *mem = (struct Member *) chn->group;
1060 client_send_join_decision (mem, hdcsn);
1061 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1063 chn->join_status = JOIN_ADMITTED;
1067 chn->join_status = JOIN_REFUSED;
1068 cadet_channel_destroy (chn);
1074 check_cadet_message (void *cls,
1075 const struct GNUNET_MULTICAST_MessageHeader *msg)
1077 uint16_t size = ntohs (msg->header.size);
1078 if (size < sizeof (*msg))
1080 GNUNET_break_op (0);
1081 return GNUNET_SYSERR;
1084 struct Channel *chn = cls;
1088 return GNUNET_SYSERR;
1090 if (ntohl (msg->purpose.size) != (size
1091 - sizeof (msg->header)
1092 - sizeof (msg->hop_counter)
1093 - sizeof (msg->signature)))
1095 GNUNET_break_op (0);
1096 return GNUNET_SYSERR;
1099 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1100 &msg->purpose, &msg->signature,
1101 &chn->group_pub_key))
1103 GNUNET_break_op (0);
1104 return GNUNET_SYSERR;
1112 * Incoming multicast message from CADET.
1115 handle_cadet_message (void *cls,
1116 const struct GNUNET_MULTICAST_MessageHeader *msg)
1118 struct Channel *chn = cls;
1119 GNUNET_CADET_receive_done (chn->channel);
1120 client_send_all (&chn->group_pub_hash,
1121 GNUNET_MQ_msg_copy (&msg->header));
1126 check_cadet_request (void *cls,
1127 const struct GNUNET_MULTICAST_RequestHeader *req)
1129 uint16_t size = ntohs (req->header.size);
1130 if (size < sizeof (*req))
1132 GNUNET_break_op (0);
1133 return GNUNET_SYSERR;
1136 struct Channel *chn = cls;
1140 return GNUNET_SYSERR;
1142 if (ntohl (req->purpose.size) != (size
1143 - sizeof (req->header)
1144 - sizeof (req->member_pub_key)
1145 - sizeof (req->signature)))
1147 GNUNET_break_op (0);
1148 return GNUNET_SYSERR;
1151 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1152 &req->purpose, &req->signature,
1153 &req->member_pub_key))
1155 GNUNET_break_op (0);
1156 return GNUNET_SYSERR;
1164 * Incoming multicast request message from CADET.
1167 handle_cadet_request (void *cls,
1168 const struct GNUNET_MULTICAST_RequestHeader *req)
1170 struct Channel *chn = cls;
1171 GNUNET_CADET_receive_done (chn->channel);
1172 client_send_origin (&chn->group_pub_hash,
1173 GNUNET_MQ_msg_copy (&req->header));
1177 // FIXME: do checks in handle_cadet_replay_request
1179 //check_cadet_replay_request (void *cls,
1180 // const struct MulticastReplayRequestMessage *req)
1182 // uint16_t size = ntohs (req->header.size);
1183 // if (size < sizeof (*req))
1185 // GNUNET_break_op (0);
1186 // return GNUNET_SYSERR;
1189 // struct Channel *chn = cls;
1192 // GNUNET_break_op (0);
1193 // return GNUNET_SYSERR;
1196 // return GNUNET_OK;
1201 * Incoming multicast replay request from CADET.
1204 handle_cadet_replay_request (void *cls,
1205 const struct MulticastReplayRequestMessage *req)
1207 struct Channel *chn = cls;
1209 GNUNET_CADET_receive_done (chn->channel);
1211 struct MulticastReplayRequestMessage rep = *req;
1212 GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key));
1214 struct GNUNET_CONTAINER_MultiHashMap *
1215 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1216 &chn->group->pub_key_hash);
1217 if (NULL == grp_replay_req)
1219 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1220 GNUNET_CONTAINER_multihashmap_put (replay_req_cadet,
1221 &chn->group->pub_key_hash, grp_replay_req,
1222 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1224 struct GNUNET_HashCode key_hash;
1225 replay_key_hash (rep.fragment_id,
1227 rep.fragment_offset,
1230 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn,
1231 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1233 client_send_random (&chn->group_pub_hash,
1234 GNUNET_MQ_msg_copy (&rep.header));
1239 check_cadet_replay_response (void *cls,
1240 const struct MulticastReplayResponseMessage *res)
1242 struct Channel *chn = cls;
1246 return GNUNET_SYSERR;
1253 * Incoming multicast replay response from CADET.
1256 handle_cadet_replay_response (void *cls,
1257 const struct MulticastReplayResponseMessage *res)
1259 struct Channel *chn = cls;
1260 GNUNET_CADET_receive_done (chn->channel);
1262 /* @todo FIXME: got replay error response, send request to other members */
1267 group_set_cadet_port_hash (struct Group *grp)
1270 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1274 GNUNET_APPLICATION_TYPE_MULTICAST,
1276 GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash);
1282 * Create new outgoing CADET channel.
1285 * Peer to connect to.
1286 * @param group_pub_key
1287 * Public key of group the channel belongs to.
1288 * @param group_pub_hash
1289 * Hash of @a group_pub_key.
1293 static struct Channel *
1294 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
1296 struct Channel *chn = GNUNET_malloc (sizeof (*chn));
1298 chn->group_pub_key = grp->pub_key;
1299 chn->group_pub_hash = grp->pub_key_hash;
1301 chn->direction = DIR_OUTGOING;
1302 chn->is_connected = GNUNET_NO;
1303 chn->join_status = JOIN_WAITING;
1305 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1306 GNUNET_MQ_hd_var_size (cadet_message,
1307 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1308 struct GNUNET_MULTICAST_MessageHeader,
1311 GNUNET_MQ_hd_var_size (cadet_join_decision,
1312 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1313 struct MulticastJoinDecisionMessageHeader,
1316 GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1317 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1318 struct MulticastReplayRequestMessage,
1321 GNUNET_MQ_hd_var_size (cadet_replay_response,
1322 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1323 struct MulticastReplayResponseMessage,
1326 GNUNET_MQ_handler_end ()
1329 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
1330 &grp->cadet_port_hash,
1331 GNUNET_CADET_OPTION_RELIABLE,
1332 cadet_notify_window_change,
1333 cadet_notify_disconnect,
1335 GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn,
1336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1342 * Destroy outgoing CADET channel.
1345 cadet_channel_destroy (struct Channel *chn)
1347 GNUNET_CADET_channel_destroy (chn->channel);
1348 GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash);
1353 * Handle a connecting client starting an origin.
1356 handle_client_origin_start (void *cls,
1357 const struct MulticastOriginStartMessage *msg)
1359 struct Client *c = cls;
1360 struct GNUNET_SERVICE_Client *client = c->client;
1362 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1363 struct GNUNET_HashCode pub_key_hash;
1365 GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
1366 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
1369 orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
1374 orig = GNUNET_new (struct Origin);
1375 orig->priv_key = msg->group_key;
1376 orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
1378 grp = c->group = &orig->group;
1380 grp->is_origin = GNUNET_YES;
1381 grp->pub_key = pub_key;
1382 grp->pub_key_hash = pub_key_hash;
1383 grp->is_disconnected = GNUNET_NO;
1385 GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
1386 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1388 group_set_cadet_port_hash (grp);
1390 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1391 GNUNET_MQ_hd_var_size (cadet_message,
1392 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1393 struct GNUNET_MULTICAST_MessageHeader,
1396 GNUNET_MQ_hd_var_size (cadet_request,
1397 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
1398 struct GNUNET_MULTICAST_RequestHeader,
1401 GNUNET_MQ_hd_var_size (cadet_join_request,
1402 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1403 struct MulticastJoinRequestMessage,
1406 GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1407 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1408 struct MulticastReplayRequestMessage,
1411 GNUNET_MQ_hd_var_size (cadet_replay_response,
1412 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1413 struct MulticastReplayResponseMessage,
1416 GNUNET_MQ_handler_end ()
1420 orig->cadet_port = GNUNET_CADET_open_port (cadet,
1421 &grp->cadet_port_hash,
1422 cadet_notify_connect,
1424 cadet_notify_window_change,
1425 cadet_notify_disconnect,
1433 struct ClientList *cl = GNUNET_new (struct ClientList);
1434 cl->client = client;
1435 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1438 "%p Client connected as origin to group %s.\n",
1439 orig, GNUNET_h2s (&grp->pub_key_hash));
1440 GNUNET_SERVICE_client_continue (client);
1445 check_client_member_join (void *cls,
1446 const struct MulticastMemberJoinMessage *msg)
1448 uint16_t msg_size = ntohs (msg->header.size);
1449 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1450 uint32_t relay_count = ntohl (msg->relay_count);
1452 if (0 != relay_count)
1454 if (UINT32_MAX / relay_count < sizeof (*relays)){
1455 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1456 "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n",
1457 (unsigned long)relay_count,
1459 return GNUNET_SYSERR;
1462 uint32_t relay_size = relay_count * sizeof (*relays);
1463 struct GNUNET_MessageHeader *join_msg = NULL;
1464 uint16_t join_msg_size = 0;
1465 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1468 join_msg = (struct GNUNET_MessageHeader *)
1469 (((char *) &msg[1]) + relay_size);
1470 join_msg_size = ntohs (join_msg->size);
1471 if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){
1472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1473 "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n",
1474 (unsigned)join_msg_size,
1475 (unsigned long)sizeof (struct MulticastJoinRequestMessage));
1476 return GNUNET_SYSERR;
1479 if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){
1480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1481 "msg_size does not match real size of message!\n");
1482 return GNUNET_SYSERR;
1490 * Handle a connecting client joining a group.
1493 handle_client_member_join (void *cls,
1494 const struct MulticastMemberJoinMessage *msg)
1496 struct Client *c = cls;
1497 struct GNUNET_SERVICE_Client *client = c->client;
1499 uint16_t msg_size = ntohs (msg->header.size);
1501 struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
1502 struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
1504 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
1505 GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
1506 GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash);
1508 struct GNUNET_CONTAINER_MultiHashMap *
1509 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
1510 struct Member *mem = NULL;
1513 if (NULL != grp_mem)
1515 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
1520 mem = GNUNET_new (struct Member);
1521 mem->origin = msg->origin;
1522 mem->priv_key = msg->member_key;
1523 mem->pub_key = mem_pub_key;
1524 mem->pub_key_hash = mem_pub_key_hash;
1525 mem->max_fragment_id = 0; // FIXME
1527 grp = c->group = &mem->group;
1529 grp->is_origin = GNUNET_NO;
1530 grp->pub_key = msg->group_pub_key;
1531 grp->pub_key_hash = pub_key_hash;
1532 grp->is_disconnected = GNUNET_NO;
1533 group_set_cadet_port_hash (grp);
1535 if (NULL == grp_mem)
1537 grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1538 GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
1539 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1541 GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
1542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1544 // FIXME: should the members hash map have option UNIQUE_FAST?
1545 GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
1546 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1553 struct ClientList *cl = GNUNET_new (struct ClientList);
1554 cl->client = client;
1555 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1557 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1559 "Client connected to group %s as member %s (%s). size = %d\n",
1560 GNUNET_h2s (&grp->pub_key_hash),
1561 GNUNET_h2s2 (&mem->pub_key_hash),
1563 GNUNET_CONTAINER_multihashmap_size (members));
1566 if (NULL != mem->join_dcsn)
1567 { /* Already got a join decision, send it to client. */
1568 struct GNUNET_MQ_Envelope *
1569 env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header);
1571 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1575 { /* First client of the group, send join request. */
1576 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1577 uint32_t relay_count = ntohl (msg->relay_count);
1578 uint16_t relay_size = relay_count * sizeof (*relays);
1579 struct GNUNET_MessageHeader *join_msg = NULL;
1580 uint16_t join_msg_size = 0;
1581 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1584 join_msg = (struct GNUNET_MessageHeader *)
1585 (((char *) &msg[1]) + relay_size);
1586 join_msg_size = ntohs (join_msg->size);
1589 uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size;
1590 struct MulticastJoinRequestMessage *
1591 req = GNUNET_malloc (req_msg_size);
1592 req->header.size = htons (req_msg_size);
1593 req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
1594 req->group_pub_key = grp->pub_key;
1595 req->peer = this_peer;
1596 GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key);
1597 if (0 < join_msg_size)
1598 GNUNET_memcpy (&req[1], join_msg, join_msg_size);
1600 req->member_pub_key = mem->pub_key;
1601 req->purpose.size = htonl (req_msg_size
1602 - sizeof (req->header)
1603 - sizeof (req->reserved)
1604 - sizeof (req->signature));
1605 req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1607 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
1610 /* FIXME: handle error */
1614 if (NULL != mem->join_req)
1615 GNUNET_free (mem->join_req);
1616 mem->join_req = req;
1619 client_send_origin (&grp->pub_key_hash,
1620 GNUNET_MQ_msg_copy (&mem->join_req->header)))
1621 { /* No local origins, send to remote origin */
1622 cadet_send_join_request (mem);
1625 GNUNET_SERVICE_client_continue (client);
1630 client_send_join_decision (struct Member *mem,
1631 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1633 client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header));
1635 const struct MulticastJoinDecisionMessage *
1636 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1637 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1638 { /* Member admitted, store join_decision. */
1639 uint16_t dcsn_size = ntohs (dcsn->header.size);
1640 mem->join_dcsn = GNUNET_malloc (dcsn_size);
1641 GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size);
1644 { /* Refused entry, but replay would be still possible for past members. */
1650 check_client_join_decision (void *cls,
1651 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1658 * Join decision from client.
1661 handle_client_join_decision (void *cls,
1662 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1664 struct Client *c = cls;
1665 struct GNUNET_SERVICE_Client *client = c->client;
1666 struct Group *grp = c->group;
1671 GNUNET_SERVICE_client_drop (client);
1674 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1676 "%p got join decision from client for group %s..\n",
1677 grp, GNUNET_h2s (&grp->pub_key_hash));
1679 struct GNUNET_CONTAINER_MultiHashMap *
1680 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
1681 &grp->pub_key_hash);
1682 struct Member *mem = NULL;
1683 if (NULL != grp_mem)
1685 struct GNUNET_HashCode member_key_hash;
1686 GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key),
1688 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
1689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1690 "%p ..and member %s: %p\n",
1691 grp, GNUNET_h2s (&member_key_hash), mem);
1695 { /* Found local member */
1696 client_send_join_decision (mem, hdcsn);
1699 { /* Look for remote member */
1700 cadet_send_join_decision (grp, hdcsn);
1702 GNUNET_SERVICE_client_continue (client);
1707 handle_client_part_request (void *cls,
1708 const struct GNUNET_MessageHeader *msg)
1710 struct Client *c = cls;
1711 struct GNUNET_SERVICE_Client *client = c->client;
1712 struct Group *grp = c->group;
1713 struct GNUNET_MQ_Envelope *env;
1718 GNUNET_SERVICE_client_drop (client);
1721 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 "%p got part request from client for group %s.\n",
1724 grp, GNUNET_h2s (&grp->pub_key_hash));
1725 grp->is_disconnected = GNUNET_YES;
1726 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK);
1727 client_send_group (grp, env);
1728 GNUNET_SERVICE_client_continue (client);
1733 check_client_multicast_message (void *cls,
1734 const struct GNUNET_MULTICAST_MessageHeader *msg)
1741 * Incoming message from a client.
1744 handle_client_multicast_message (void *cls,
1745 const struct GNUNET_MULTICAST_MessageHeader *msg)
1747 // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages?
1748 struct Client *c = cls;
1749 struct GNUNET_SERVICE_Client *client = c->client;
1750 struct Group *grp = c->group;
1755 GNUNET_SERVICE_client_drop (client);
1758 GNUNET_assert (GNUNET_YES == grp->is_origin);
1759 struct Origin *orig = grp->origin;
1761 // FIXME: use GNUNET_MQ_msg_copy
1762 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1763 struct GNUNET_MULTICAST_MessageHeader *
1764 out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header);
1765 out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
1766 out->purpose.size = htonl (ntohs (out->header.size)
1767 - sizeof (out->header)
1768 - sizeof (out->hop_counter)
1769 - sizeof (out->signature));
1770 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
1772 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
1778 client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header));
1779 cadet_send_children (&grp->pub_key_hash, &out->header);
1780 client_send_ack (&grp->pub_key_hash);
1783 GNUNET_SERVICE_client_continue (client);
1788 check_client_multicast_request (void *cls,
1789 const struct GNUNET_MULTICAST_RequestHeader *req)
1796 * Incoming request from a client.
1799 handle_client_multicast_request (void *cls,
1800 const struct GNUNET_MULTICAST_RequestHeader *req)
1802 struct Client *c = cls;
1803 struct GNUNET_SERVICE_Client *client = c->client;
1804 struct Group *grp = c->group;
1809 GNUNET_SERVICE_client_drop (client);
1812 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1813 GNUNET_assert (GNUNET_NO == grp->is_origin);
1814 struct Member *mem = grp->member;
1816 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1817 struct GNUNET_MULTICAST_RequestHeader *
1818 out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header);
1819 out->member_pub_key = mem->pub_key;
1820 out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1821 out->purpose.size = htonl (ntohs (out->header.size)
1822 - sizeof (out->header)
1823 - sizeof (out->member_pub_key)
1824 - sizeof (out->signature));
1825 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1827 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1833 uint8_t send_ack = GNUNET_YES;
1835 client_send_origin (&grp->pub_key_hash,
1836 GNUNET_MQ_msg_copy (&out->header)))
1837 { /* No local origins, send to remote origin */
1838 if (NULL != mem->origin_channel)
1840 cadet_send_channel (mem->origin_channel, &out->header);
1841 send_ack = GNUNET_NO;
1845 /* FIXME: not yet connected to origin */
1846 GNUNET_SERVICE_client_drop (client);
1851 if (GNUNET_YES == send_ack)
1853 client_send_ack (&grp->pub_key_hash);
1856 GNUNET_SERVICE_client_continue (client);
1861 * Incoming replay request from a client.
1864 handle_client_replay_request (void *cls,
1865 const struct MulticastReplayRequestMessage *rep)
1867 struct Client *c = cls;
1868 struct GNUNET_SERVICE_Client *client = c->client;
1869 struct Group *grp = c->group;
1874 GNUNET_SERVICE_client_drop (client);
1877 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1878 GNUNET_assert (GNUNET_NO == grp->is_origin);
1879 struct Member *mem = grp->member;
1881 struct GNUNET_CONTAINER_MultiHashMap *
1882 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1883 &grp->pub_key_hash);
1884 if (NULL == grp_replay_req)
1886 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1887 GNUNET_CONTAINER_multihashmap_put (replay_req_client,
1888 &grp->pub_key_hash, grp_replay_req,
1889 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1892 struct GNUNET_HashCode key_hash;
1893 replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset,
1894 rep->flags, &key_hash);
1895 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client,
1896 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1899 client_send_origin (&grp->pub_key_hash,
1900 GNUNET_MQ_msg_copy (&rep->header)))
1901 { /* No local origin, replay from remote members / origin. */
1902 if (NULL != mem->origin_channel)
1904 cadet_send_channel (mem->origin_channel, &rep->header);
1908 /* FIXME: not yet connected to origin */
1911 GNUNET_SERVICE_client_drop (client);
1915 GNUNET_SERVICE_client_continue (client);
1920 cadet_send_replay_response_cb (void *cls,
1921 const struct GNUNET_HashCode *key_hash,
1924 struct Channel *chn = value;
1925 struct GNUNET_MessageHeader *msg = cls;
1927 cadet_send_channel (chn, msg);
1933 client_send_replay_response_cb (void *cls,
1934 const struct GNUNET_HashCode *key_hash,
1937 struct GNUNET_SERVICE_Client *client = value;
1938 struct GNUNET_MessageHeader *msg = cls;
1940 client_send (client, msg);
1946 check_client_replay_response_end (void *cls,
1947 const struct MulticastReplayResponseMessage *res)
1954 * End of replay response from a client.
1957 handle_client_replay_response_end (void *cls,
1958 const struct MulticastReplayResponseMessage *res)
1960 struct Client *c = cls;
1961 struct GNUNET_SERVICE_Client *client = c->client;
1962 struct Group *grp = c->group;
1967 GNUNET_SERVICE_client_drop (client);
1970 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1972 struct GNUNET_HashCode key_hash;
1973 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
1974 res->flags, &key_hash);
1976 struct GNUNET_CONTAINER_MultiHashMap *
1977 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1978 &grp->pub_key_hash);
1979 if (NULL != grp_replay_req_cadet)
1981 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash);
1983 struct GNUNET_CONTAINER_MultiHashMap *
1984 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1985 &grp->pub_key_hash);
1986 if (NULL != grp_replay_req_client)
1988 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash);
1990 GNUNET_SERVICE_client_continue (client);
1995 check_client_replay_response (void *cls,
1996 const struct MulticastReplayResponseMessage *res)
1998 const struct GNUNET_MessageHeader *msg;
1999 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2001 msg = GNUNET_MQ_extract_nested_mh (res);
2004 return GNUNET_SYSERR;
2012 * Incoming replay response from a client.
2014 * Respond with a multicast message on success, or otherwise with an error code.
2017 handle_client_replay_response (void *cls,
2018 const struct MulticastReplayResponseMessage *res)
2020 struct Client *c = cls;
2021 struct GNUNET_SERVICE_Client *client = c->client;
2022 struct Group *grp = c->group;
2027 GNUNET_SERVICE_client_drop (client);
2030 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
2032 const struct GNUNET_MessageHeader *msg = &res->header;
2033 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2035 msg = GNUNET_MQ_extract_nested_mh (res);
2038 struct GNUNET_HashCode key_hash;
2039 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
2040 res->flags, &key_hash);
2042 struct GNUNET_CONTAINER_MultiHashMap *
2043 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
2044 &grp->pub_key_hash);
2045 if (NULL != grp_replay_req_cadet)
2047 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash,
2048 cadet_send_replay_response_cb,
2051 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2053 struct GNUNET_CONTAINER_MultiHashMap *
2054 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
2055 &grp->pub_key_hash);
2056 if (NULL != grp_replay_req_client)
2058 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash,
2059 client_send_replay_response_cb,
2065 handle_client_replay_response_end (c, res);
2068 GNUNET_SERVICE_client_continue (client);
2073 * A new client connected.
2076 * @param client client to add
2077 * @param mq message queue for @a client
2081 client_notify_connect (void *cls,
2082 struct GNUNET_SERVICE_Client *client,
2083 struct GNUNET_MQ_Handle *mq)
2085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
2086 /* FIXME: send connect ACK */
2088 struct Client *c = GNUNET_new (struct Client);
2096 * Called whenever a client is disconnected.
2097 * Frees our resources associated with that client.
2099 * @param cls closure
2100 * @param client identification of the client
2101 * @param app_ctx must match @a client
2104 client_notify_disconnect (void *cls,
2105 struct GNUNET_SERVICE_Client *client,
2108 struct Client *c = app_ctx;
2109 struct Group *grp = c->group;
2114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2115 "%p User context is NULL in client_disconnect()\n", grp);
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "%p Client (%s) disconnected from group %s\n",
2122 grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
2123 GNUNET_h2s (&grp->pub_key_hash));
2125 // FIXME (due to protocol change): here we must not remove all clients,
2126 // only the one we were notified about!
2127 struct ClientList *cl = grp->clients_head;
2130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2131 "iterating clients for group %p\n",
2133 if (cl->client == client)
2135 GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
2142 while (GNUNET_YES == replay_req_remove_client (grp, client));
2144 if (NULL == grp->clients_head)
2145 { /* Last client disconnected. */
2146 cleanup_group (grp);
2154 * @param cls closure
2155 * @param server the initialized server
2156 * @param cfg configuration to use
2160 const struct GNUNET_CONFIGURATION_Handle *c,
2161 struct GNUNET_SERVICE_Handle *svc)
2165 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
2167 stats = GNUNET_STATISTICS_create ("multicast", cfg);
2168 origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2169 members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2170 group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2171 channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2172 channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2173 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2174 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2176 cadet = GNUNET_CADET_connect (cfg);
2178 GNUNET_assert (NULL != cadet);
2180 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2186 * Define "main" method using service macro.
2190 GNUNET_SERVICE_OPTION_NONE,
2192 &client_notify_connect,
2193 &client_notify_disconnect,
2195 GNUNET_MQ_hd_fixed_size (client_origin_start,
2196 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START,
2197 struct MulticastOriginStartMessage,
2199 GNUNET_MQ_hd_var_size (client_member_join,
2200 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN,
2201 struct MulticastMemberJoinMessage,
2203 GNUNET_MQ_hd_var_size (client_join_decision,
2204 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
2205 struct MulticastJoinDecisionMessageHeader,
2207 GNUNET_MQ_hd_fixed_size (client_part_request,
2208 GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST,
2209 struct GNUNET_MessageHeader,
2211 GNUNET_MQ_hd_var_size (client_multicast_message,
2212 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
2213 struct GNUNET_MULTICAST_MessageHeader,
2215 GNUNET_MQ_hd_var_size (client_multicast_request,
2216 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
2217 struct GNUNET_MULTICAST_RequestHeader,
2219 GNUNET_MQ_hd_fixed_size (client_replay_request,
2220 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
2221 struct MulticastReplayRequestMessage,
2223 GNUNET_MQ_hd_var_size (client_replay_response,
2224 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
2225 struct MulticastReplayResponseMessage,
2227 GNUNET_MQ_hd_var_size (client_replay_response_end,
2228 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END,
2229 struct MulticastReplayResponseMessage,
2232 /* end of gnunet-service-multicast.c */