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);
1451 if (UINT32_MAX / relay_count < sizeof (*relays)){
1452 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1453 "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n",
1454 (unsigned long)relay_count,
1456 return GNUNET_SYSERR;
1458 uint32_t relay_size = relay_count * sizeof (*relays);
1459 struct GNUNET_MessageHeader *join_msg = NULL;
1460 uint16_t join_msg_size = 0;
1461 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1464 join_msg = (struct GNUNET_MessageHeader *)
1465 (((char *) &msg[1]) + relay_size);
1466 join_msg_size = ntohs (join_msg->size);
1467 if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){
1468 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1469 "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n",
1470 (unsigned)join_msg_size,
1471 (unsigned long)sizeof (struct MulticastJoinRequestMessage));
1472 return GNUNET_SYSERR;
1475 if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){
1476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1477 "msg_size does not match real size of message!\n");
1478 return GNUNET_SYSERR;
1486 * Handle a connecting client joining a group.
1489 handle_client_member_join (void *cls,
1490 const struct MulticastMemberJoinMessage *msg)
1492 struct Client *c = cls;
1493 struct GNUNET_SERVICE_Client *client = c->client;
1495 uint16_t msg_size = ntohs (msg->header.size);
1497 struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
1498 struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
1500 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
1501 GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
1502 GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash);
1504 struct GNUNET_CONTAINER_MultiHashMap *
1505 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
1506 struct Member *mem = NULL;
1509 if (NULL != grp_mem)
1511 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
1516 mem = GNUNET_new (struct Member);
1517 mem->origin = msg->origin;
1518 mem->priv_key = msg->member_key;
1519 mem->pub_key = mem_pub_key;
1520 mem->pub_key_hash = mem_pub_key_hash;
1521 mem->max_fragment_id = 0; // FIXME
1523 grp = c->group = &mem->group;
1525 grp->is_origin = GNUNET_NO;
1526 grp->pub_key = msg->group_pub_key;
1527 grp->pub_key_hash = pub_key_hash;
1528 grp->is_disconnected = GNUNET_NO;
1529 group_set_cadet_port_hash (grp);
1531 if (NULL == grp_mem)
1533 grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1534 GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
1535 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1537 GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
1538 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1540 // FIXME: should the members hash map have option UNIQUE_FAST?
1541 GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
1542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1549 struct ClientList *cl = GNUNET_new (struct ClientList);
1550 cl->client = client;
1551 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1553 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
1554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1555 "Client connected to group %s as member %s (%s). size = %d\n",
1556 GNUNET_h2s (&grp->pub_key_hash),
1557 GNUNET_h2s2 (&mem->pub_key_hash),
1559 GNUNET_CONTAINER_multihashmap_size (members));
1562 if (NULL != mem->join_dcsn)
1563 { /* Already got a join decision, send it to client. */
1564 struct GNUNET_MQ_Envelope *
1565 env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header);
1567 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1571 { /* First client of the group, send join request. */
1572 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1573 uint32_t relay_count = ntohl (msg->relay_count);
1574 uint16_t relay_size = relay_count * sizeof (*relays);
1575 struct GNUNET_MessageHeader *join_msg = NULL;
1576 uint16_t join_msg_size = 0;
1577 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1580 join_msg = (struct GNUNET_MessageHeader *)
1581 (((char *) &msg[1]) + relay_size);
1582 join_msg_size = ntohs (join_msg->size);
1585 uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size;
1586 struct MulticastJoinRequestMessage *
1587 req = GNUNET_malloc (req_msg_size);
1588 req->header.size = htons (req_msg_size);
1589 req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
1590 req->group_pub_key = grp->pub_key;
1591 req->peer = this_peer;
1592 GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key);
1593 if (0 < join_msg_size)
1594 GNUNET_memcpy (&req[1], join_msg, join_msg_size);
1596 req->member_pub_key = mem->pub_key;
1597 req->purpose.size = htonl (req_msg_size
1598 - sizeof (req->header)
1599 - sizeof (req->reserved)
1600 - sizeof (req->signature));
1601 req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1603 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
1606 /* FIXME: handle error */
1610 if (NULL != mem->join_req)
1611 GNUNET_free (mem->join_req);
1612 mem->join_req = req;
1615 client_send_origin (&grp->pub_key_hash,
1616 GNUNET_MQ_msg_copy (&mem->join_req->header)))
1617 { /* No local origins, send to remote origin */
1618 cadet_send_join_request (mem);
1621 GNUNET_SERVICE_client_continue (client);
1626 client_send_join_decision (struct Member *mem,
1627 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1629 client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header));
1631 const struct MulticastJoinDecisionMessage *
1632 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1633 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1634 { /* Member admitted, store join_decision. */
1635 uint16_t dcsn_size = ntohs (dcsn->header.size);
1636 mem->join_dcsn = GNUNET_malloc (dcsn_size);
1637 GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size);
1640 { /* Refused entry, but replay would be still possible for past members. */
1646 check_client_join_decision (void *cls,
1647 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1654 * Join decision from client.
1657 handle_client_join_decision (void *cls,
1658 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1660 struct Client *c = cls;
1661 struct GNUNET_SERVICE_Client *client = c->client;
1662 struct Group *grp = c->group;
1667 GNUNET_SERVICE_client_drop (client);
1670 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1672 "%p got join decision from client for group %s..\n",
1673 grp, GNUNET_h2s (&grp->pub_key_hash));
1675 struct GNUNET_CONTAINER_MultiHashMap *
1676 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
1677 &grp->pub_key_hash);
1678 struct Member *mem = NULL;
1679 if (NULL != grp_mem)
1681 struct GNUNET_HashCode member_key_hash;
1682 GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key),
1684 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
1685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686 "%p ..and member %s: %p\n",
1687 grp, GNUNET_h2s (&member_key_hash), mem);
1691 { /* Found local member */
1692 client_send_join_decision (mem, hdcsn);
1695 { /* Look for remote member */
1696 cadet_send_join_decision (grp, hdcsn);
1698 GNUNET_SERVICE_client_continue (client);
1703 handle_client_part_request (void *cls,
1704 const struct GNUNET_MessageHeader *msg)
1706 struct Client *c = cls;
1707 struct GNUNET_SERVICE_Client *client = c->client;
1708 struct Group *grp = c->group;
1709 struct GNUNET_MQ_Envelope *env;
1714 GNUNET_SERVICE_client_drop (client);
1717 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1719 "%p got part request from client for group %s.\n",
1720 grp, GNUNET_h2s (&grp->pub_key_hash));
1721 grp->is_disconnected = GNUNET_YES;
1722 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK);
1723 client_send_group (grp, env);
1724 GNUNET_SERVICE_client_continue (client);
1729 check_client_multicast_message (void *cls,
1730 const struct GNUNET_MULTICAST_MessageHeader *msg)
1737 * Incoming message from a client.
1740 handle_client_multicast_message (void *cls,
1741 const struct GNUNET_MULTICAST_MessageHeader *msg)
1743 // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages?
1744 struct Client *c = cls;
1745 struct GNUNET_SERVICE_Client *client = c->client;
1746 struct Group *grp = c->group;
1751 GNUNET_SERVICE_client_drop (client);
1754 GNUNET_assert (GNUNET_YES == grp->is_origin);
1755 struct Origin *orig = grp->origin;
1757 // FIXME: use GNUNET_MQ_msg_copy
1758 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1759 struct GNUNET_MULTICAST_MessageHeader *
1760 out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header);
1761 out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
1762 out->purpose.size = htonl (ntohs (out->header.size)
1763 - sizeof (out->header)
1764 - sizeof (out->hop_counter)
1765 - sizeof (out->signature));
1766 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
1768 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
1774 client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header));
1775 cadet_send_children (&grp->pub_key_hash, &out->header);
1776 client_send_ack (&grp->pub_key_hash);
1779 GNUNET_SERVICE_client_continue (client);
1784 check_client_multicast_request (void *cls,
1785 const struct GNUNET_MULTICAST_RequestHeader *req)
1792 * Incoming request from a client.
1795 handle_client_multicast_request (void *cls,
1796 const struct GNUNET_MULTICAST_RequestHeader *req)
1798 struct Client *c = cls;
1799 struct GNUNET_SERVICE_Client *client = c->client;
1800 struct Group *grp = c->group;
1805 GNUNET_SERVICE_client_drop (client);
1808 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1809 GNUNET_assert (GNUNET_NO == grp->is_origin);
1810 struct Member *mem = grp->member;
1812 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1813 struct GNUNET_MULTICAST_RequestHeader *
1814 out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header);
1815 out->member_pub_key = mem->pub_key;
1816 out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1817 out->purpose.size = htonl (ntohs (out->header.size)
1818 - sizeof (out->header)
1819 - sizeof (out->member_pub_key)
1820 - sizeof (out->signature));
1821 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1823 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1829 uint8_t send_ack = GNUNET_YES;
1831 client_send_origin (&grp->pub_key_hash,
1832 GNUNET_MQ_msg_copy (&out->header)))
1833 { /* No local origins, send to remote origin */
1834 if (NULL != mem->origin_channel)
1836 cadet_send_channel (mem->origin_channel, &out->header);
1837 send_ack = GNUNET_NO;
1841 /* FIXME: not yet connected to origin */
1842 GNUNET_SERVICE_client_drop (client);
1847 if (GNUNET_YES == send_ack)
1849 client_send_ack (&grp->pub_key_hash);
1852 GNUNET_SERVICE_client_continue (client);
1857 * Incoming replay request from a client.
1860 handle_client_replay_request (void *cls,
1861 const struct MulticastReplayRequestMessage *rep)
1863 struct Client *c = cls;
1864 struct GNUNET_SERVICE_Client *client = c->client;
1865 struct Group *grp = c->group;
1870 GNUNET_SERVICE_client_drop (client);
1873 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1874 GNUNET_assert (GNUNET_NO == grp->is_origin);
1875 struct Member *mem = grp->member;
1877 struct GNUNET_CONTAINER_MultiHashMap *
1878 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1879 &grp->pub_key_hash);
1880 if (NULL == grp_replay_req)
1882 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1883 GNUNET_CONTAINER_multihashmap_put (replay_req_client,
1884 &grp->pub_key_hash, grp_replay_req,
1885 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1888 struct GNUNET_HashCode key_hash;
1889 replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset,
1890 rep->flags, &key_hash);
1891 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client,
1892 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1895 client_send_origin (&grp->pub_key_hash,
1896 GNUNET_MQ_msg_copy (&rep->header)))
1897 { /* No local origin, replay from remote members / origin. */
1898 if (NULL != mem->origin_channel)
1900 cadet_send_channel (mem->origin_channel, &rep->header);
1904 /* FIXME: not yet connected to origin */
1907 GNUNET_SERVICE_client_drop (client);
1911 GNUNET_SERVICE_client_continue (client);
1916 cadet_send_replay_response_cb (void *cls,
1917 const struct GNUNET_HashCode *key_hash,
1920 struct Channel *chn = value;
1921 struct GNUNET_MessageHeader *msg = cls;
1923 cadet_send_channel (chn, msg);
1929 client_send_replay_response_cb (void *cls,
1930 const struct GNUNET_HashCode *key_hash,
1933 struct GNUNET_SERVICE_Client *client = value;
1934 struct GNUNET_MessageHeader *msg = cls;
1936 client_send (client, msg);
1942 check_client_replay_response_end (void *cls,
1943 const struct MulticastReplayResponseMessage *res)
1950 * End of replay response from a client.
1953 handle_client_replay_response_end (void *cls,
1954 const struct MulticastReplayResponseMessage *res)
1956 struct Client *c = cls;
1957 struct GNUNET_SERVICE_Client *client = c->client;
1958 struct Group *grp = c->group;
1963 GNUNET_SERVICE_client_drop (client);
1966 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1968 struct GNUNET_HashCode key_hash;
1969 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
1970 res->flags, &key_hash);
1972 struct GNUNET_CONTAINER_MultiHashMap *
1973 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1974 &grp->pub_key_hash);
1975 if (NULL != grp_replay_req_cadet)
1977 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash);
1979 struct GNUNET_CONTAINER_MultiHashMap *
1980 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1981 &grp->pub_key_hash);
1982 if (NULL != grp_replay_req_client)
1984 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash);
1986 GNUNET_SERVICE_client_continue (client);
1991 check_client_replay_response (void *cls,
1992 const struct MulticastReplayResponseMessage *res)
1994 const struct GNUNET_MessageHeader *msg;
1995 if (GNUNET_MULTICAST_REC_OK == res->error_code)
1997 msg = GNUNET_MQ_extract_nested_mh (res);
2000 return GNUNET_SYSERR;
2008 * Incoming replay response from a client.
2010 * Respond with a multicast message on success, or otherwise with an error code.
2013 handle_client_replay_response (void *cls,
2014 const struct MulticastReplayResponseMessage *res)
2016 struct Client *c = cls;
2017 struct GNUNET_SERVICE_Client *client = c->client;
2018 struct Group *grp = c->group;
2023 GNUNET_SERVICE_client_drop (client);
2026 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
2028 const struct GNUNET_MessageHeader *msg = &res->header;
2029 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2031 msg = GNUNET_MQ_extract_nested_mh (res);
2034 struct GNUNET_HashCode key_hash;
2035 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
2036 res->flags, &key_hash);
2038 struct GNUNET_CONTAINER_MultiHashMap *
2039 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
2040 &grp->pub_key_hash);
2041 if (NULL != grp_replay_req_cadet)
2043 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash,
2044 cadet_send_replay_response_cb,
2047 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2049 struct GNUNET_CONTAINER_MultiHashMap *
2050 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
2051 &grp->pub_key_hash);
2052 if (NULL != grp_replay_req_client)
2054 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash,
2055 client_send_replay_response_cb,
2061 handle_client_replay_response_end (c, res);
2064 GNUNET_SERVICE_client_continue (client);
2069 * A new client connected.
2072 * @param client client to add
2073 * @param mq message queue for @a client
2077 client_notify_connect (void *cls,
2078 struct GNUNET_SERVICE_Client *client,
2079 struct GNUNET_MQ_Handle *mq)
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
2082 /* FIXME: send connect ACK */
2084 struct Client *c = GNUNET_new (struct Client);
2092 * Called whenever a client is disconnected.
2093 * Frees our resources associated with that client.
2095 * @param cls closure
2096 * @param client identification of the client
2097 * @param app_ctx must match @a client
2100 client_notify_disconnect (void *cls,
2101 struct GNUNET_SERVICE_Client *client,
2104 struct Client *c = app_ctx;
2105 struct Group *grp = c->group;
2110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2111 "%p User context is NULL in client_disconnect()\n", grp);
2116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2117 "%p Client (%s) disconnected from group %s\n",
2118 grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
2119 GNUNET_h2s (&grp->pub_key_hash));
2121 // FIXME (due to protocol change): here we must not remove all clients,
2122 // only the one we were notified about!
2123 struct ClientList *cl = grp->clients_head;
2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2127 "iterating clients for group %p\n",
2129 if (cl->client == client)
2131 GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
2138 while (GNUNET_YES == replay_req_remove_client (grp, client));
2140 if (NULL == grp->clients_head)
2141 { /* Last client disconnected. */
2142 cleanup_group (grp);
2150 * @param cls closure
2151 * @param server the initialized server
2152 * @param cfg configuration to use
2156 const struct GNUNET_CONFIGURATION_Handle *c,
2157 struct GNUNET_SERVICE_Handle *svc)
2161 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
2163 stats = GNUNET_STATISTICS_create ("multicast", cfg);
2164 origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2165 members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2166 group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2167 channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2168 channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2169 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2170 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2172 cadet = GNUNET_CADET_connect (cfg);
2174 GNUNET_assert (NULL != cadet);
2176 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2182 * Define "main" method using service macro.
2186 GNUNET_SERVICE_OPTION_NONE,
2188 &client_notify_connect,
2189 &client_notify_disconnect,
2191 GNUNET_MQ_hd_fixed_size (client_origin_start,
2192 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START,
2193 struct MulticastOriginStartMessage,
2195 GNUNET_MQ_hd_var_size (client_member_join,
2196 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN,
2197 struct MulticastMemberJoinMessage,
2199 GNUNET_MQ_hd_var_size (client_join_decision,
2200 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
2201 struct MulticastJoinDecisionMessageHeader,
2203 GNUNET_MQ_hd_fixed_size (client_part_request,
2204 GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST,
2205 struct GNUNET_MessageHeader,
2207 GNUNET_MQ_hd_var_size (client_multicast_message,
2208 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
2209 struct GNUNET_MULTICAST_MessageHeader,
2211 GNUNET_MQ_hd_var_size (client_multicast_request,
2212 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
2213 struct GNUNET_MULTICAST_RequestHeader,
2215 GNUNET_MQ_hd_fixed_size (client_replay_request,
2216 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
2217 struct MulticastReplayRequestMessage,
2219 GNUNET_MQ_hd_var_size (client_replay_response,
2220 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
2221 struct MulticastReplayResponseMessage,
2223 GNUNET_MQ_hd_var_size (client_replay_response_end,
2224 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END,
2225 struct MulticastReplayResponseMessage,
2228 /* end of gnunet-service-multicast.c */