added logging
[oweals/gnunet.git] / src / multicast / gnunet-service-multicast.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file multicast/gnunet-service-multicast.c
23  * @brief program that does multicast
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_applications.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_multicast_service.h"
33 #include "multicast.h"
34
35 /**
36  * Handle to our current configuration.
37  */
38 static const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40 /**
41  * Service handle.
42  */
43 static struct GNUNET_SERVICE_Handle *service;
44
45 /**
46  * CADET handle.
47  */
48 static struct GNUNET_CADET_Handle *cadet;
49
50 /**
51  * Identity of this peer.
52  */
53 static struct GNUNET_PeerIdentity this_peer;
54
55 /**
56  * Handle to the statistics service.
57  */
58 static struct GNUNET_STATISTICS_Handle *stats;
59
60 /**
61  * All connected origin clients.
62  * Group's pub_key_hash -> struct Origin * (uniq)
63  */
64 static struct GNUNET_CONTAINER_MultiHashMap *origins;
65
66 /**
67  * All connected member clients.
68  * Group's pub_key_hash -> struct Member * (multi)
69  */
70 static struct GNUNET_CONTAINER_MultiHashMap *members;
71
72 /**
73  * Connected member clients per group.
74  * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq)
75  */
76 static struct GNUNET_CONTAINER_MultiHashMap *group_members;
77
78 /**
79  * Incoming CADET channels with connected children in the tree.
80  * Group's pub_key_hash -> struct Channel * (multi)
81  */
82 static struct GNUNET_CONTAINER_MultiHashMap *channels_in;
83
84 /**
85  * Outgoing CADET channels connecting to parents in the tree.
86  * Group's pub_key_hash -> struct Channel * (multi)
87  */
88 static struct GNUNET_CONTAINER_MultiHashMap *channels_out;
89
90 /**
91  * Incoming replay requests from CADET.
92  * Group's pub_key_hash ->
93  *   H(fragment_id, message_id, fragment_offset, flags) -> struct Channel *
94  */
95 static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet;
96
97 /**
98  * Incoming replay requests from clients.
99  * Group's pub_key_hash ->
100  *   H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client *
101  */
102 static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client;
103
104
105 /**
106  * Join status of a remote peer.
107  */
108 enum JoinStatus
109 {
110   JOIN_REFUSED  = -1,
111   JOIN_NOT_ASKED = 0,
112   JOIN_WAITING   = 1,
113   JOIN_ADMITTED  = 2,
114 };
115
116 enum ChannelDirection
117 {
118   DIR_INCOMING = 0,
119   DIR_OUTGOING = 1,
120 };
121
122
123 /**
124  * Context for a CADET channel.
125  */
126 struct Channel
127 {
128   /**
129    * Group the channel belongs to.
130    *
131    * Only set for outgoing channels.
132    */
133   struct Group *group;
134
135   /**
136    * CADET channel.
137    */
138   struct GNUNET_CADET_Channel *channel;
139
140   /**
141    * CADET transmission handle.
142    */
143   struct GNUNET_CADET_TransmitHandle *tmit_handle;
144
145   /**
146    * Public key of the target group.
147    */
148   struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
149
150   /**
151    * Hash of @a group_pub_key.
152    */
153   struct GNUNET_HashCode group_pub_hash;
154
155   /**
156    * Public key of the joining member.
157    */
158   struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
159
160   /**
161    * Remote peer identity.
162    */
163   struct GNUNET_PeerIdentity peer;
164
165   /**
166    * Current window size, set by cadet_notify_window_change()
167    */
168   int32_t window_size;
169
170   /**
171    * Is the connection established?
172    */
173   int8_t is_connected;
174
175   /**
176    * Is the remote peer admitted to the group?
177    * @see enum JoinStatus
178    */
179   int8_t join_status;
180
181   /**
182    * Number of messages waiting to be sent to CADET.
183    */
184   uint8_t msgs_pending;
185
186   /**
187    * Channel direction.
188    * @see enum ChannelDirection
189    */
190   uint8_t direction;
191 };
192
193
194 /**
195  * List of connected clients.
196  */
197 struct ClientList
198 {
199   struct ClientList *prev;
200   struct ClientList *next;
201   struct GNUNET_SERVICE_Client *client;
202 };
203
204
205 /**
206  * Client context for an origin or member.
207  */
208 struct Group
209 {
210   struct ClientList *clients_head;
211   struct ClientList *clients_tail;
212
213   /**
214    * Public key of the group.
215    */
216   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
217
218   /**
219    * Hash of @a pub_key.
220    */
221   struct GNUNET_HashCode pub_key_hash;
222
223   /**
224    * CADET port hash.
225    */
226   struct GNUNET_HashCode cadet_port_hash;
227
228   /**
229    * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
230    */
231   uint8_t disconnected;
232
233   /**
234    * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
235    */
236   uint8_t is_origin;
237
238   union {
239     struct Origin *origin;
240     struct Member *member;
241   };
242 };
243
244
245 /**
246 * Client context for a group's origin.
247  */
248 struct Origin
249 {
250   struct Group group;
251
252   /**
253    * Private key of the group.
254    */
255   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
256
257   /**
258    * CADET port.
259    */
260   struct GNUNET_CADET_Port *cadet_port;
261
262   /**
263    * Last message fragment ID sent to the group.
264    */
265   uint64_t max_fragment_id;
266 };
267
268
269 /**
270  * Client context for a group member.
271  */
272 struct Member
273 {
274   struct Group group;
275
276   /**
277    * Private key of the member.
278    */
279   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
280
281   /**
282    * Public key of the member.
283    */
284   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
285
286   /**
287    * Hash of @a pub_key.
288    */
289   struct GNUNET_HashCode pub_key_hash;
290
291   /**
292    * Join request sent to the origin / members.
293    */
294   struct MulticastJoinRequestMessage *join_req;
295
296   /**
297    * Join decision sent in reply to our request.
298    *
299    * Only a positive decision is stored here, in case of a negative decision the
300    * client is disconnected.
301    */
302   struct MulticastJoinDecisionMessageHeader *join_dcsn;
303
304   /**
305    * CADET channel to the origin.
306    */
307   struct Channel *origin_channel;
308
309   /**
310    * Peer identity of origin.
311    */
312   struct GNUNET_PeerIdentity origin;
313
314   /**
315    * Peer identity of relays (other members to connect).
316    */
317   struct GNUNET_PeerIdentity *relays;
318
319   /**
320    * Last request fragment ID sent to the origin.
321    */
322   uint64_t max_fragment_id;
323
324   /**
325    * Number of @a relays.
326    */
327   uint32_t relay_count;
328 };
329
330
331 /**
332  * Client context.
333  */
334 struct Client {
335   struct GNUNET_SERVICE_Client *client;
336   struct Group *group;
337 };
338
339
340 struct ReplayRequestKey
341 {
342   uint64_t fragment_id;
343   uint64_t message_id;
344   uint64_t fragment_offset;
345   uint64_t flags;
346 };
347
348
349 static struct Channel *
350 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer);
351
352 static void
353 cadet_channel_destroy (struct Channel *chn);
354
355 static void
356 client_send_join_decision (struct Member *mem,
357                            const struct MulticastJoinDecisionMessageHeader *hdcsn);
358
359
360 /**
361  * Task run during shutdown.
362  *
363  * @param cls unused
364  */
365 static void
366 shutdown_task (void *cls)
367 {
368   if (NULL != cadet)
369   {
370     GNUNET_CADET_disconnect (cadet);
371     cadet = NULL;
372   }
373   if (NULL != stats)
374   {
375     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
376     stats = NULL;
377   }
378   /* FIXME: do more clean up here */
379 }
380
381
382 /**
383  * Clean up origin data structures after a client disconnected.
384  */
385 static void
386 cleanup_origin (struct Origin *orig)
387 {
388   struct Group *grp = &orig->group;
389   GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
390   if (NULL != orig->cadet_port)
391   {
392     GNUNET_CADET_close_port (orig->cadet_port);
393     orig->cadet_port = NULL;
394   }
395   GNUNET_free (orig);
396 }
397
398
399 /**
400  * Clean up member data structures after a client disconnected.
401  */
402 static void
403 cleanup_member (struct Member *mem)
404 {
405   struct Group *grp = &mem->group;
406   struct GNUNET_CONTAINER_MultiHashMap *
407     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
408                                                  &grp->pub_key_hash);
409   GNUNET_assert (NULL != grp_mem);
410   GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
411
412   if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
413   {
414     GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
415                                           grp_mem);
416     GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
417   }
418   if (NULL != mem->join_dcsn)
419   {
420     GNUNET_free (mem->join_dcsn);
421     mem->join_dcsn = NULL;
422   }
423   GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
424   GNUNET_free (mem);
425 }
426
427
428 /**
429  * Clean up group data structures after a client disconnected.
430  */
431 static void
432 cleanup_group (struct Group *grp)
433 {
434   (GNUNET_YES == grp->is_origin)
435     ? cleanup_origin (grp->origin)
436     : cleanup_member (grp->member);
437 }
438
439
440 void
441 replay_key_hash (uint64_t fragment_id, uint64_t message_id,
442                  uint64_t fragment_offset, uint64_t flags,
443                  struct GNUNET_HashCode *key_hash)
444 {
445   struct ReplayRequestKey key = {
446     .fragment_id = fragment_id,
447     .message_id = message_id,
448     .fragment_offset = fragment_offset,
449     .flags = flags,
450   };
451   GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash);
452 }
453
454
455 /**
456  * Remove channel from replay request hashmap.
457  *
458  * @param chn
459  *        Channel to remove.
460  *
461  * @return #GNUNET_YES if there are more entries to process,
462  *         #GNUNET_NO when reached end of hashmap.
463  */
464 static int
465 replay_req_remove_cadet (struct Channel *chn)
466 {
467   if (NULL == chn || NULL == chn->group)
468     return GNUNET_SYSERR;
469
470   struct GNUNET_CONTAINER_MultiHashMap *
471     grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
472                                                         &chn->group->pub_key_hash);
473   if (NULL == grp_replay_req)
474     return GNUNET_NO;
475
476   struct GNUNET_CONTAINER_MultiHashMapIterator *
477     it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
478   struct GNUNET_HashCode key;
479   const struct Channel *c;
480   while (GNUNET_YES
481          == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
482                                                          (const void **) &c))
483   {
484     if (c == chn)
485     {
486       GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn);
487       GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
488       return GNUNET_YES;
489     }
490   }
491   GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
492   return GNUNET_NO;
493 }
494
495
496 /**
497  * Remove client from replay request hashmap.
498  *
499  * @param client
500  *        Client to remove.
501  *
502  * @return #GNUNET_YES if there are more entries to process,
503  *         #GNUNET_NO when reached end of hashmap.
504  */
505 static int
506 replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client)
507 {
508   struct GNUNET_CONTAINER_MultiHashMap *
509     grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
510                                                         &grp->pub_key_hash);
511   if (NULL == grp_replay_req)
512     return GNUNET_NO;
513
514   struct GNUNET_CONTAINER_MultiHashMapIterator *
515     it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
516   struct GNUNET_HashCode key;
517   const struct GNUNET_SERVICE_Client *c;
518   while (GNUNET_YES
519          == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
520                                                          (const void **) &c))
521   {
522     if (c == client)
523     {
524       GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client);
525       GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
526       return GNUNET_YES;
527     }
528   }
529   GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
530   return GNUNET_NO;
531 }
532
533
534 /**
535  * Send message to a client.
536  */
537 static void
538 client_send (struct GNUNET_SERVICE_Client *client,
539              const struct GNUNET_MessageHeader *msg)
540 {
541   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
542               "%p Sending message to client.\n", client);
543
544   struct GNUNET_MQ_Envelope *
545     env = GNUNET_MQ_msg_copy (msg);
546
547   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
548                   env);
549 }
550
551
552 /**
553  * Send message to all clients connected to the group.
554  */
555 static void
556 client_send_group_keep_envelope (const struct Group *grp,
557                                  struct GNUNET_MQ_Envelope *env)
558 {
559   struct ClientList *cli = grp->clients_head;
560
561   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
562               "%p Sending message of type %u to all clients of the group.\n",
563               grp,
564               ntohs (env->mh->type));
565   while (NULL != cli)
566   {
567     GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client),
568                          env);
569     cli = cli->next;
570   }
571 }
572
573
574 /**
575  * Send message to all clients connected to the group and
576  * takes care of freeing @env.
577  */
578 static void
579 client_send_group (const struct Group *grp,
580                    struct GNUNET_MQ_Envelope *env)
581 {
582   client_send_group_keep_envelope (grp, env);
583   GNUNET_MQ_discard (env);
584 }
585
586
587 /**
588  * Iterator callback for sending a message to origin clients.
589  */
590 static int
591 client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
592                        void *origin)
593 {
594   struct GNUNET_MQ_Envelope *env = cls;
595   struct Member *orig = origin;
596
597   client_send_group_keep_envelope (&orig->group, env);
598   return GNUNET_YES;
599 }
600
601
602 /**
603  * Iterator callback for sending a message to member clients.
604  */
605 static int
606 client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
607                        void *member)
608 {
609   struct GNUNET_MQ_Envelope *env = cls;
610   struct Member *mem = member;
611
612   if (NULL != mem->join_dcsn)
613   { /* Only send message to admitted members */
614     client_send_group_keep_envelope (&mem->group, env);
615   }
616   return GNUNET_YES;
617 }
618
619
620 /**
621  * Send message to all origin and member clients connected to the group.
622  *
623  * @param pub_key_hash
624  *        H(key_pub) of the group.
625  * @param msg
626  *        Message to send.
627  */
628 static int
629 client_send_all (struct GNUNET_HashCode *pub_key_hash,
630                  struct GNUNET_MQ_Envelope *env)
631 {
632   int n = 0;
633   n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
634                                                    client_send_origin_cb,
635                                                    (void *) env);
636   n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash,
637                                                    client_send_member_cb,
638                                                    (void *) env);
639   GNUNET_MQ_discard (env);
640   return n;
641 }
642
643
644 /**
645  * Send message to a random origin client or a random member client.
646  *
647  * @param grp  The group to send @a msg to.
648  * @param msg  Message to send.
649  */
650 static int
651 client_send_random (struct GNUNET_HashCode *pub_key_hash,
652                     struct GNUNET_MQ_Envelope *env)
653 {
654   int n = 0;
655   n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb,
656                                                  (void *) env);
657   if (n <= 0)
658     n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb,
659                                                    (void *) env);
660   return n;
661 }
662
663
664 /**
665  * Send message to all origin clients connected to the group.
666  *
667  * @param pub_key_hash
668  *        H(key_pub) of the group.
669  * @param msg
670  *        Message to send.
671  */
672 static int
673 client_send_origin (struct GNUNET_HashCode *pub_key_hash,
674                     struct GNUNET_MQ_Envelope *env)
675 {
676   int n = 0;
677   n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
678                                                    client_send_origin_cb,
679                                                    (void *) env);
680   return n;
681 }
682
683
684 /**
685  * Send fragment acknowledgement to all clients of the channel.
686  *
687  * @param pub_key_hash
688  *        H(key_pub) of the group.
689  */
690 static void
691 client_send_ack (struct GNUNET_HashCode *pub_key_hash)
692 {
693   struct GNUNET_MQ_Envelope *env;
694
695   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
696               "Sending message ACK to client.\n");
697   env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK);
698   client_send_all (pub_key_hash, env);
699 }
700
701
702 struct CadetTransmitClosure
703 {
704   struct Channel *chn;
705   const struct GNUNET_MessageHeader *msg;
706 };
707
708
709 /**
710  * Send a message to a CADET channel.
711  *
712  * @param chn  Channel.
713  * @param msg  Message.
714  */
715 static void
716 cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
717 {
718   struct GNUNET_MQ_Envelope *
719     env = GNUNET_MQ_msg_copy (msg);
720
721   GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env);
722
723   if (0 < chn->window_size)
724   {
725     client_send_ack (&chn->group_pub_hash);
726   }
727   else
728   {
729     chn->msgs_pending++;
730     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
731                 "%p Queuing message. Pending messages: %u\n",
732                 chn, chn->msgs_pending);
733   }
734 }
735
736
737 /**
738  * Create CADET channel and send a join request.
739  */
740 static void
741 cadet_send_join_request (struct Member *mem)
742 {
743   mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin);
744   cadet_send_channel (mem->origin_channel, &mem->join_req->header);
745
746   uint32_t i;
747   for (i = 0; i < mem->relay_count; i++)
748   {
749     struct Channel *
750       chn = cadet_channel_create (&mem->group, &mem->relays[i]);
751     cadet_send_channel (chn, &mem->join_req->header);
752   }
753 }
754
755
756 static int
757 cadet_send_join_decision_cb (void *cls,
758                              const struct GNUNET_HashCode *group_pub_hash,
759                              void *channel)
760 {
761   const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
762   struct Channel *chn = channel;
763
764   const struct MulticastJoinDecisionMessage *dcsn =
765     (struct MulticastJoinDecisionMessage *) &hdcsn[1];
766
767   if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key))
768       && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer)))
769   {
770     if (GNUNET_YES == ntohl (dcsn->is_admitted))
771     {
772       chn->join_status = JOIN_ADMITTED;
773     }
774     else
775     {
776       chn->join_status = JOIN_REFUSED;
777     }
778     cadet_send_channel (chn, &hdcsn->header);
779     return GNUNET_YES;
780   }
781
782   // return GNUNET_YES to continue the multihashmap_get iteration
783   return GNUNET_YES;
784 }
785
786
787 /**
788  * Send join decision to a remote peer.
789  */
790 static void
791 cadet_send_join_decision (struct Group *grp,
792                           const struct MulticastJoinDecisionMessageHeader *hdcsn)
793 {
794   GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash,
795                                               &cadet_send_join_decision_cb,
796                                               (void *) hdcsn);
797 }
798
799
800 /**
801  * Iterator callback for sending a message to origin clients.
802  */
803 static int
804 cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
805                void *channel)
806 {
807   const struct GNUNET_MessageHeader *msg = cls;
808   struct Channel *chn = channel;
809   if (JOIN_ADMITTED == chn->join_status)
810     cadet_send_channel (chn, msg);
811   return GNUNET_YES;
812 }
813
814
815 /**
816  * Send message to all connected children.
817  */
818 static int
819 cadet_send_children (struct GNUNET_HashCode *pub_key_hash,
820                      const struct GNUNET_MessageHeader *msg)
821 {
822   int n = 0;
823   if (channels_in != NULL)
824     n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash,
825                                                      cadet_send_cb, (void *) msg);
826   return n;
827 }
828
829
830 #if 0       // unused as yet
831 /**
832  * Send message to all connected parents.
833  */
834 static int
835 cadet_send_parents (struct GNUNET_HashCode *pub_key_hash,
836                     const struct GNUNET_MessageHeader *msg)
837 {
838   int n = 0;
839   if (channels_in != NULL)
840     n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash,
841                                                      cadet_send_cb, (void *) msg);
842   return n;
843 }
844 #endif
845
846
847 /**
848  * CADET channel connect handler.
849  *
850  * @see GNUNET_CADET_ConnectEventHandler()
851  */
852 static void *
853 cadet_notify_connect (void *cls,
854                       struct GNUNET_CADET_Channel *channel,
855                       const struct GNUNET_PeerIdentity *source)
856 {
857   struct Channel *chn = GNUNET_malloc (sizeof (struct Channel));
858   chn->group = cls;
859   chn->channel = channel;
860   chn->direction = DIR_INCOMING;
861   chn->join_status = JOIN_NOT_ASKED;
862       
863   GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn,
864                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
865   return chn;
866 }
867
868
869 /**
870  * CADET window size change handler.
871  *
872  * @see GNUNET_CADET_WindowSizeEventHandler()
873  */
874 static void
875 cadet_notify_window_change (void *cls,
876                             const struct GNUNET_CADET_Channel *channel,
877                             int window_size)
878 {
879   struct Channel *chn = cls;
880
881   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
882               "%p Window size changed to %d.  Pending messages: %u\n",
883               chn, window_size, chn->msgs_pending);
884
885   chn->is_connected = GNUNET_YES;
886   chn->window_size = (int32_t) window_size;
887
888   for (int i = 0; i < window_size; i++)
889   {
890     if (0 < chn->msgs_pending)
891     {
892       client_send_ack (&chn->group_pub_hash);
893       chn->msgs_pending--;
894     }
895     else
896     {
897       break;
898     }
899   }
900 }
901
902
903 /**
904  * CADET channel disconnect handler.
905  *
906  * @see GNUNET_CADET_DisconnectEventHandler()
907  */
908 static void
909 cadet_notify_disconnect (void *cls,
910                          const struct GNUNET_CADET_Channel *channel)
911 {
912   if (NULL == cls)
913     return;
914
915   struct Channel *chn = cls;
916   if (NULL != chn->group)
917   {
918     if (GNUNET_NO == chn->group->is_origin)
919     {
920       struct Member *mem = (struct Member *) chn->group;
921       if (chn == mem->origin_channel)
922         mem->origin_channel = NULL;
923     }
924   }
925
926   int ret;
927   do
928   {
929     ret = replay_req_remove_cadet (chn);
930   }
931   while (GNUNET_YES == ret);
932
933   GNUNET_free (chn);
934 }
935
936
937 static int
938 check_cadet_join_request (void *cls,
939                           const struct MulticastJoinRequestMessage *req)
940 {
941   struct Channel *chn = cls;
942
943   if (NULL == chn
944       || JOIN_NOT_ASKED != chn->join_status)
945   {
946     return GNUNET_SYSERR;
947   }
948
949   uint16_t size = ntohs (req->header.size);
950   if (size < sizeof (*req))
951   {
952     GNUNET_break_op (0);
953     return GNUNET_SYSERR;
954   }
955   if (ntohl (req->purpose.size) != (size
956                                     - sizeof (req->header)
957                                     - sizeof (req->reserved)
958                                     - sizeof (req->signature)))
959   {
960     GNUNET_break_op (0);
961     return GNUNET_SYSERR;
962   }
963   if (GNUNET_OK !=
964       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
965                                   &req->purpose, &req->signature,
966                                   &req->member_pub_key))
967   {
968     GNUNET_break_op (0);
969     return GNUNET_SYSERR;
970   }
971
972   return GNUNET_OK;
973 }
974
975
976 /**
977  * Incoming join request message from CADET.
978  */
979 static void
980 handle_cadet_join_request (void *cls,
981                            const struct MulticastJoinRequestMessage *req)
982 {
983   struct Channel *chn = cls;
984   GNUNET_CADET_receive_done (chn->channel);
985
986   struct GNUNET_HashCode group_pub_hash;
987   GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash);
988   chn->group_pub_key = req->group_pub_key;
989   chn->group_pub_hash = group_pub_hash;
990   chn->member_pub_key = req->member_pub_key;
991   chn->peer = req->peer;
992   chn->join_status = JOIN_WAITING;
993
994   client_send_all (&group_pub_hash,
995                    GNUNET_MQ_msg_copy (&req->header));
996 }
997
998
999 static int
1000 check_cadet_join_decision (void *cls,
1001                            const struct MulticastJoinDecisionMessageHeader *hdcsn)
1002 {
1003   uint16_t size = ntohs (hdcsn->header.size);
1004   if (size < sizeof (struct MulticastJoinDecisionMessageHeader) +
1005              sizeof (struct MulticastJoinDecisionMessage))
1006   {
1007     GNUNET_break_op (0);
1008     return GNUNET_SYSERR;
1009   }
1010
1011   struct Channel *chn = cls;
1012   if (NULL == chn)
1013   {
1014     GNUNET_break (0);
1015     return GNUNET_SYSERR;
1016   }
1017   if (NULL == chn->group || GNUNET_NO != chn->group->is_origin)
1018   {
1019     GNUNET_break (0);
1020     return GNUNET_SYSERR;
1021   }
1022   switch (chn->join_status)
1023   {
1024   case JOIN_REFUSED:
1025     return GNUNET_SYSERR;
1026
1027   case JOIN_ADMITTED:
1028     return GNUNET_OK;
1029
1030   case JOIN_NOT_ASKED:
1031   case JOIN_WAITING:
1032     break;
1033   }
1034
1035   return GNUNET_OK;
1036 }
1037
1038
1039 /**
1040  * Incoming join decision message from CADET.
1041  */
1042 static void
1043 handle_cadet_join_decision (void *cls,
1044                             const struct MulticastJoinDecisionMessageHeader *hdcsn)
1045 {
1046   const struct MulticastJoinDecisionMessage *
1047     dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1048
1049   struct Channel *chn = cls;
1050   GNUNET_CADET_receive_done (chn->channel);
1051
1052   // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer?
1053   struct Member *mem = (struct Member *) chn->group;
1054   client_send_join_decision (mem, hdcsn);
1055   if (GNUNET_YES == ntohl (dcsn->is_admitted))
1056   {
1057     chn->join_status = JOIN_ADMITTED;
1058   }
1059   else
1060   {
1061     chn->join_status = JOIN_REFUSED;
1062     cadet_channel_destroy (chn);
1063   }
1064 }
1065
1066
1067 static int
1068 check_cadet_message (void *cls,
1069                      const struct GNUNET_MULTICAST_MessageHeader *msg)
1070 {
1071   uint16_t size = ntohs (msg->header.size);
1072   if (size < sizeof (*msg))
1073   {
1074     GNUNET_break_op (0);
1075     return GNUNET_SYSERR;
1076   }
1077
1078   struct Channel *chn = cls;
1079   if (NULL == chn)
1080   {
1081     GNUNET_break (0);
1082     return GNUNET_SYSERR;
1083   }
1084   if (ntohl (msg->purpose.size) != (size
1085                                     - sizeof (msg->header)
1086                                     - sizeof (msg->hop_counter)
1087                                     - sizeof (msg->signature)))
1088   {
1089     GNUNET_break_op (0);
1090     return GNUNET_SYSERR;
1091   }
1092   if (GNUNET_OK !=
1093       GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1094                                   &msg->purpose, &msg->signature,
1095                                   &chn->group_pub_key))
1096   {
1097     GNUNET_break_op (0);
1098     return GNUNET_SYSERR;
1099   }
1100
1101   return GNUNET_OK;
1102 }
1103
1104
1105 /**
1106  * Incoming multicast message from CADET.
1107  */
1108 static void
1109 handle_cadet_message (void *cls,
1110                       const struct GNUNET_MULTICAST_MessageHeader *msg)
1111 {
1112   struct Channel *chn = cls;
1113   GNUNET_CADET_receive_done (chn->channel);
1114   client_send_all (&chn->group_pub_hash,
1115                    GNUNET_MQ_msg_copy (&msg->header));
1116 }
1117
1118
1119 static int
1120 check_cadet_request (void *cls,
1121                      const struct GNUNET_MULTICAST_RequestHeader *req)
1122 {
1123   uint16_t size = ntohs (req->header.size);
1124   if (size < sizeof (*req))
1125   {
1126     GNUNET_break_op (0);
1127     return GNUNET_SYSERR;
1128   }
1129
1130   struct Channel *chn = cls;
1131   if (NULL == chn)
1132   {
1133     GNUNET_break (0);
1134     return GNUNET_SYSERR;
1135   }
1136   if (ntohl (req->purpose.size) != (size
1137                                     - sizeof (req->header)
1138                                     - sizeof (req->member_pub_key)
1139                                     - sizeof (req->signature)))
1140   {
1141     GNUNET_break_op (0);
1142     return GNUNET_SYSERR;
1143   }
1144   if (GNUNET_OK !=
1145       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1146                                   &req->purpose, &req->signature,
1147                                   &req->member_pub_key))
1148   {
1149     GNUNET_break_op (0);
1150     return GNUNET_SYSERR;
1151   }
1152
1153   return GNUNET_OK;
1154 }
1155
1156
1157 /**
1158  * Incoming multicast request message from CADET.
1159  */
1160 static void
1161 handle_cadet_request (void *cls,
1162                       const struct GNUNET_MULTICAST_RequestHeader *req)
1163 {
1164   struct Channel *chn = cls;
1165   GNUNET_CADET_receive_done (chn->channel);
1166   client_send_origin (&chn->group_pub_hash,
1167                       GNUNET_MQ_msg_copy (&req->header));
1168 }
1169
1170
1171 // FIXME: do checks in handle_cadet_replay_request
1172 //static int
1173 //check_cadet_replay_request (void *cls,
1174 //                            const struct MulticastReplayRequestMessage *req)
1175 //{
1176 //  uint16_t size = ntohs (req->header.size);
1177 //  if (size < sizeof (*req))
1178 //  {
1179 //    GNUNET_break_op (0);
1180 //    return GNUNET_SYSERR;
1181 //  }
1182 //
1183 //  struct Channel *chn = cls;
1184 //  if (NULL == chn)
1185 //  {
1186 //    GNUNET_break_op (0);
1187 //    return GNUNET_SYSERR;
1188 //  }
1189 //
1190 //  return GNUNET_OK;
1191 //}
1192
1193
1194 /**
1195  * Incoming multicast replay request from CADET.
1196  */
1197 static void
1198 handle_cadet_replay_request (void *cls,
1199                              const struct MulticastReplayRequestMessage *req)
1200 {
1201   struct Channel *chn = cls;
1202
1203   GNUNET_CADET_receive_done (chn->channel);
1204
1205   struct MulticastReplayRequestMessage rep = *req;
1206   GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key));
1207
1208   struct GNUNET_CONTAINER_MultiHashMap *
1209     grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1210                                                         &chn->group->pub_key_hash);
1211   if (NULL == grp_replay_req)
1212   {
1213     grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1214     GNUNET_CONTAINER_multihashmap_put (replay_req_cadet,
1215                                        &chn->group->pub_key_hash, grp_replay_req,
1216                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1217   }
1218   struct GNUNET_HashCode key_hash;
1219   replay_key_hash (rep.fragment_id,
1220                    rep.message_id,
1221                    rep.fragment_offset,
1222                    rep.flags,
1223                    &key_hash);
1224   GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn,
1225                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1226
1227   client_send_random (&chn->group_pub_hash,
1228                       GNUNET_MQ_msg_copy (&rep.header));
1229 }
1230
1231
1232 static int
1233 check_cadet_replay_response (void *cls,
1234                              const struct MulticastReplayResponseMessage *res)
1235 {
1236   struct Channel *chn = cls;
1237   if (NULL == chn)
1238   {
1239     GNUNET_break (0);
1240     return GNUNET_SYSERR;
1241   }
1242   return GNUNET_OK;
1243 }
1244
1245
1246 /**
1247  * Incoming multicast replay response from CADET.
1248  */
1249 static void
1250 handle_cadet_replay_response (void *cls,
1251                               const struct MulticastReplayResponseMessage *res)
1252 {
1253   struct Channel *chn = cls;
1254   GNUNET_CADET_receive_done (chn->channel);
1255
1256   /* @todo FIXME: got replay error response, send request to other members */
1257 }
1258
1259
1260 static void
1261 group_set_cadet_port_hash (struct Group *grp)
1262 {
1263   struct CadetPort {
1264     struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1265     uint32_t app_type;
1266   } port = {
1267     grp->pub_key,
1268     GNUNET_APPLICATION_TYPE_MULTICAST,
1269   };
1270   GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash);
1271 }
1272
1273
1274
1275 /**
1276  * Create new outgoing CADET channel.
1277  *
1278  * @param peer
1279  *        Peer to connect to.
1280  * @param group_pub_key
1281  *        Public key of group the channel belongs to.
1282  * @param group_pub_hash
1283  *        Hash of @a group_pub_key.
1284  *
1285  * @return Channel.
1286  */
1287 static struct Channel *
1288 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
1289 {
1290   struct Channel *chn = GNUNET_malloc (sizeof (*chn));
1291   chn->group = grp;
1292   chn->group_pub_key = grp->pub_key;
1293   chn->group_pub_hash = grp->pub_key_hash;
1294   chn->peer = *peer;
1295   chn->direction = DIR_OUTGOING;
1296   chn->is_connected = GNUNET_NO;
1297   chn->join_status = JOIN_WAITING;
1298
1299   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1300     GNUNET_MQ_hd_var_size (cadet_message,
1301                            GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1302                            struct GNUNET_MULTICAST_MessageHeader,
1303                            chn),
1304
1305     GNUNET_MQ_hd_var_size (cadet_join_decision,
1306                            GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1307                            struct MulticastJoinDecisionMessageHeader,
1308                            chn),
1309
1310     GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1311                              GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1312                              struct MulticastReplayRequestMessage,
1313                              chn),
1314
1315     GNUNET_MQ_hd_var_size (cadet_replay_response,
1316                            GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1317                            struct MulticastReplayResponseMessage,
1318                            chn),
1319
1320     GNUNET_MQ_handler_end ()
1321   };
1322
1323   chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
1324                                               &grp->cadet_port_hash,
1325                                               GNUNET_CADET_OPTION_RELIABLE,
1326                                               cadet_notify_window_change,
1327                                               cadet_notify_disconnect,
1328                                               cadet_handlers);
1329   GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn,
1330                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1331   return chn;
1332 }
1333
1334
1335 /**
1336  * Destroy outgoing CADET channel.
1337  */
1338 static void
1339 cadet_channel_destroy (struct Channel *chn)
1340 {
1341   GNUNET_CADET_channel_destroy (chn->channel);
1342   GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash);
1343   GNUNET_free (chn);
1344 }
1345
1346 /**
1347  * Handle a connecting client starting an origin.
1348  */
1349 static void
1350 handle_client_origin_start (void *cls,
1351                             const struct MulticastOriginStartMessage *msg)
1352 {
1353   struct Client *c = cls;
1354   struct GNUNET_SERVICE_Client *client = c->client;
1355
1356   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1357   struct GNUNET_HashCode pub_key_hash;
1358
1359   GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
1360   GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
1361
1362   struct Origin *
1363     orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
1364   struct Group *grp;
1365
1366   if (NULL == orig)
1367   {
1368     orig = GNUNET_new (struct Origin);
1369     orig->priv_key = msg->group_key;
1370     orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
1371
1372     grp = c->group = &orig->group;
1373     grp->origin = orig;
1374     grp->is_origin = GNUNET_YES;
1375     grp->pub_key = pub_key;
1376     grp->pub_key_hash = pub_key_hash;
1377
1378     GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
1379                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1380
1381     group_set_cadet_port_hash (grp);
1382
1383     struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1384       GNUNET_MQ_hd_var_size (cadet_message,
1385                              GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1386                              struct GNUNET_MULTICAST_MessageHeader,
1387                              grp),
1388
1389       GNUNET_MQ_hd_var_size (cadet_request,
1390                              GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
1391                              struct GNUNET_MULTICAST_RequestHeader,
1392                              grp),
1393
1394       GNUNET_MQ_hd_var_size (cadet_join_request,
1395                              GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1396                              struct MulticastJoinRequestMessage,
1397                              grp),
1398
1399       GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1400                                GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1401                                struct MulticastReplayRequestMessage,
1402                                grp),
1403
1404       GNUNET_MQ_hd_var_size (cadet_replay_response,
1405                              GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1406                              struct MulticastReplayResponseMessage,
1407                              grp),
1408
1409       GNUNET_MQ_handler_end ()
1410     };
1411
1412
1413     orig->cadet_port = GNUNET_CADET_open_port (cadet,
1414                                                &grp->cadet_port_hash,
1415                                                cadet_notify_connect,
1416                                                grp,
1417                                                cadet_notify_window_change,
1418                                                cadet_notify_disconnect,
1419                                                cadet_handlers);
1420   }
1421   else
1422   {
1423     grp = &orig->group;
1424   }
1425
1426   struct ClientList *cl = GNUNET_new (struct ClientList);
1427   cl->client = client;
1428   GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1429
1430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1431               "%p Client connected as origin to group %s.\n",
1432               orig, GNUNET_h2s (&grp->pub_key_hash));
1433   GNUNET_SERVICE_client_continue (client);
1434 }
1435
1436
1437 static int
1438 check_client_member_join (void *cls,
1439                           const struct MulticastMemberJoinMessage *msg)
1440 {
1441   uint16_t msg_size = ntohs (msg->header.size);
1442   struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1443   uint32_t relay_count = ntohl (msg->relay_count);
1444   uint16_t relay_size = relay_count * sizeof (*relays);
1445   struct GNUNET_MessageHeader *join_msg = NULL;
1446   uint16_t join_msg_size = 0;
1447   if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1448       <= msg_size)
1449   {
1450     join_msg = (struct GNUNET_MessageHeader *)
1451       (((char *) &msg[1]) + relay_size);
1452     join_msg_size = ntohs (join_msg->size);
1453   }
1454   return
1455     msg_size == (sizeof (*msg) + relay_size + join_msg_size)
1456     ? GNUNET_OK
1457     : GNUNET_SYSERR;
1458 }
1459
1460
1461 /**
1462  * Handle a connecting client joining a group.
1463  */
1464 static void
1465 handle_client_member_join (void *cls,
1466                            const struct MulticastMemberJoinMessage *msg)
1467 {
1468   struct Client *c = cls;
1469   struct GNUNET_SERVICE_Client *client = c->client;
1470
1471   uint16_t msg_size = ntohs (msg->header.size);
1472
1473   struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
1474   struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
1475
1476   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
1477   GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
1478   GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash);
1479   
1480   struct GNUNET_CONTAINER_MultiHashMap *
1481     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
1482   struct Member *mem = NULL;
1483   struct Group *grp;
1484
1485   if (NULL != grp_mem)
1486   {
1487     mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
1488   }
1489   
1490   if (NULL == mem)
1491   {
1492     mem = GNUNET_new (struct Member);
1493     mem->origin = msg->origin;
1494     mem->priv_key = msg->member_key;
1495     mem->pub_key = mem_pub_key;
1496     mem->pub_key_hash = mem_pub_key_hash;
1497     mem->max_fragment_id = 0; // FIXME
1498
1499     grp = c->group = &mem->group;
1500     grp->member = mem;
1501     grp->is_origin = GNUNET_NO;
1502     grp->pub_key = msg->group_pub_key;
1503     grp->pub_key_hash = pub_key_hash;
1504     group_set_cadet_port_hash (grp);
1505   
1506     if (NULL == grp_mem)
1507     {
1508       grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1509       GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
1510                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1511     }
1512     GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
1513                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1514    
1515     // FIXME: should the members hash map have option UNIQUE_FAST?
1516     GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
1517                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1518   }
1519   else
1520   {
1521     grp = &mem->group;
1522   }
1523
1524   struct ClientList *cl = GNUNET_new (struct ClientList);
1525   cl->client = client;
1526   GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1527
1528   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
1529   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530               "Client connected to group %s as member %s (%s). size = %d\n",
1531               GNUNET_h2s (&grp->pub_key_hash),
1532               GNUNET_h2s2 (&mem->pub_key_hash),
1533               str,
1534               GNUNET_CONTAINER_multihashmap_size (members));
1535   GNUNET_free (str);
1536
1537   if (NULL != mem->join_dcsn)
1538   { /* Already got a join decision, send it to client. */
1539     struct GNUNET_MQ_Envelope *
1540       env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header);
1541
1542     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1543                     env);
1544   }
1545   else
1546   { /* First client of the group, send join request. */
1547     struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1548     uint32_t relay_count = ntohl (msg->relay_count);
1549     uint16_t relay_size = relay_count * sizeof (*relays);
1550     struct GNUNET_MessageHeader *join_msg = NULL;
1551     uint16_t join_msg_size = 0;
1552     if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1553         <= msg_size)
1554     {
1555       join_msg = (struct GNUNET_MessageHeader *)
1556         (((char *) &msg[1]) + relay_size);
1557       join_msg_size = ntohs (join_msg->size);
1558     }
1559
1560     uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size;
1561     struct MulticastJoinRequestMessage *
1562       req = GNUNET_malloc (req_msg_size);
1563     req->header.size = htons (req_msg_size);
1564     req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
1565     req->group_pub_key = grp->pub_key;
1566     req->peer = this_peer;
1567     GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key);
1568     if (0 < join_msg_size)
1569       GNUNET_memcpy (&req[1], join_msg, join_msg_size);
1570
1571     req->member_pub_key = mem->pub_key;
1572     req->purpose.size = htonl (req_msg_size
1573                                - sizeof (req->header)
1574                                - sizeof (req->reserved)
1575                                - sizeof (req->signature));
1576     req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1577
1578     if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
1579                                                &req->signature))
1580     {
1581       /* FIXME: handle error */
1582       GNUNET_assert (0);
1583     }
1584
1585     if (NULL != mem->join_req)
1586       GNUNET_free (mem->join_req);
1587     mem->join_req = req;
1588
1589     if (0 ==
1590         client_send_origin (&grp->pub_key_hash,
1591                             GNUNET_MQ_msg_copy (&mem->join_req->header)))
1592     { /* No local origins, send to remote origin */
1593       cadet_send_join_request (mem);
1594     }
1595   }
1596   GNUNET_SERVICE_client_continue (client);
1597 }
1598
1599
1600 static void
1601 client_send_join_decision (struct Member *mem,
1602                            const struct MulticastJoinDecisionMessageHeader *hdcsn)
1603 {
1604   client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header));
1605
1606   const struct MulticastJoinDecisionMessage *
1607     dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1608   if (GNUNET_YES == ntohl (dcsn->is_admitted))
1609   { /* Member admitted, store join_decision. */
1610     uint16_t dcsn_size = ntohs (dcsn->header.size);
1611     mem->join_dcsn = GNUNET_malloc (dcsn_size);
1612     GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size);
1613   }
1614   else
1615   { /* Refused entry, but replay would be still possible for past members. */
1616   }
1617 }
1618
1619
1620 static int
1621 check_client_join_decision (void *cls,
1622                             const struct MulticastJoinDecisionMessageHeader *hdcsn)
1623 {
1624   return GNUNET_OK;
1625 }
1626
1627
1628 /**
1629  * Join decision from client.
1630  */
1631 static void
1632 handle_client_join_decision (void *cls,
1633                              const struct MulticastJoinDecisionMessageHeader *hdcsn)
1634 {
1635   struct Client *c = cls;
1636   struct GNUNET_SERVICE_Client *client = c->client;
1637   struct Group *grp = c->group;
1638
1639   if (NULL == grp)
1640   {
1641     GNUNET_break (0);
1642     GNUNET_SERVICE_client_drop (client);
1643     return;
1644   }
1645   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1646               "%p got join decision from client for group %s..\n",
1647               grp, GNUNET_h2s (&grp->pub_key_hash));
1648
1649   struct GNUNET_CONTAINER_MultiHashMap *
1650     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
1651                                                  &grp->pub_key_hash);
1652   struct Member *mem = NULL;
1653   if (NULL != grp_mem)
1654   {
1655     struct GNUNET_HashCode member_key_hash;
1656     GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key),
1657                         &member_key_hash);
1658     mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
1659     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660                 "%p ..and member %s: %p\n",
1661                 grp, GNUNET_h2s (&member_key_hash), mem);
1662   }
1663   
1664   if (NULL != mem) 
1665   { /* Found local member */
1666     client_send_join_decision (mem, hdcsn);
1667   }
1668   else
1669   { /* Look for remote member */
1670     cadet_send_join_decision (grp, hdcsn);
1671   }
1672   GNUNET_SERVICE_client_continue (client);
1673 }
1674
1675
1676 static void
1677 handle_client_part_request (void *cls,
1678                             const struct GNUNET_MessageHeader *msg)
1679 {
1680   struct Client *c = cls;
1681   struct GNUNET_SERVICE_Client *client = c->client;
1682   struct Group *grp = c->group;
1683   struct GNUNET_MQ_Envelope *env;
1684
1685   if (NULL == grp)
1686   {
1687     GNUNET_break (0);
1688     GNUNET_SERVICE_client_drop (client);
1689     return;
1690   }
1691   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1692               "%p got part request from client for group %s.\n",
1693               grp, GNUNET_h2s (&grp->pub_key_hash));
1694   env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK);
1695   client_send_group (grp, env);
1696   GNUNET_SERVICE_client_continue (client);
1697 }
1698
1699
1700 static int
1701 check_client_multicast_message (void *cls,
1702                                 const struct GNUNET_MULTICAST_MessageHeader *msg)
1703 {
1704   return GNUNET_OK;
1705 }
1706
1707
1708 /**
1709  * Incoming message from a client.
1710  */
1711 static void
1712 handle_client_multicast_message (void *cls,
1713                                  const struct GNUNET_MULTICAST_MessageHeader *msg)
1714 {
1715   struct Client *c = cls;
1716   struct GNUNET_SERVICE_Client *client = c->client;
1717   struct Group *grp = c->group;
1718
1719   if (NULL == grp)
1720   {
1721     GNUNET_break (0);
1722     GNUNET_SERVICE_client_drop (client);
1723     return;
1724   }
1725   GNUNET_assert (GNUNET_YES == grp->is_origin);
1726   struct Origin *orig = grp->origin;
1727
1728   // FIXME: use GNUNET_MQ_msg_copy
1729   /* FIXME: yucky, should use separate message structs for P2P and CS! */
1730   struct GNUNET_MULTICAST_MessageHeader *
1731     out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header);
1732   out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
1733   out->purpose.size = htonl (ntohs (out->header.size)
1734                              - sizeof (out->header)
1735                              - sizeof (out->hop_counter)
1736                              - sizeof (out->signature));
1737   out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
1738
1739   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
1740                                              &out->signature))
1741   {
1742     GNUNET_assert (0);
1743   }
1744
1745   client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header));
1746   cadet_send_children (&grp->pub_key_hash, &out->header);
1747   client_send_ack (&grp->pub_key_hash);
1748   GNUNET_free (out);
1749
1750   GNUNET_SERVICE_client_continue (client);
1751 }
1752
1753
1754 static int
1755 check_client_multicast_request (void *cls,
1756                                 const struct GNUNET_MULTICAST_RequestHeader *req)
1757 {
1758   return GNUNET_OK;
1759 }
1760
1761
1762 /**
1763  * Incoming request from a client.
1764  */
1765 static void
1766 handle_client_multicast_request (void *cls,
1767                                  const struct GNUNET_MULTICAST_RequestHeader *req)
1768 {
1769   struct Client *c = cls;
1770   struct GNUNET_SERVICE_Client *client = c->client;
1771   struct Group *grp = c->group;
1772
1773   if (NULL == grp)
1774   {
1775     GNUNET_break (0);
1776     GNUNET_SERVICE_client_drop (client);
1777     return;
1778   }
1779   GNUNET_assert (GNUNET_NO == grp->is_origin);
1780   struct Member *mem = grp->member;
1781
1782   /* FIXME: yucky, should use separate message structs for P2P and CS! */
1783   struct GNUNET_MULTICAST_RequestHeader *
1784     out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header);
1785   out->member_pub_key = mem->pub_key;
1786   out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1787   out->purpose.size = htonl (ntohs (out->header.size)
1788                              - sizeof (out->header)
1789                              - sizeof (out->member_pub_key)
1790                              - sizeof (out->signature));
1791   out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1792
1793   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1794                                              &out->signature))
1795   {
1796     GNUNET_assert (0);
1797   }
1798
1799   uint8_t send_ack = GNUNET_YES;
1800   if (0 ==
1801       client_send_origin (&grp->pub_key_hash,
1802                           GNUNET_MQ_msg_copy (&out->header)))
1803   { /* No local origins, send to remote origin */
1804     if (NULL != mem->origin_channel)
1805     {
1806       cadet_send_channel (mem->origin_channel, &out->header);
1807       send_ack = GNUNET_NO;
1808     }
1809     else
1810     {
1811       /* FIXME: not yet connected to origin */
1812       GNUNET_SERVICE_client_drop (client);
1813       GNUNET_free (out);
1814       return;
1815     }
1816   }
1817   if (GNUNET_YES == send_ack)
1818   {
1819     client_send_ack (&grp->pub_key_hash);
1820   }
1821   GNUNET_free (out);
1822   GNUNET_SERVICE_client_continue (client);
1823 }
1824
1825
1826 /**
1827  * Incoming replay request from a client.
1828  */
1829 static void
1830 handle_client_replay_request (void *cls,
1831                               const struct MulticastReplayRequestMessage *rep)
1832 {
1833   struct Client *c = cls;
1834   struct GNUNET_SERVICE_Client *client = c->client;
1835   struct Group *grp = c->group;
1836
1837   if (NULL == grp)
1838   {
1839     GNUNET_break (0);
1840     GNUNET_SERVICE_client_drop (client);
1841     return;
1842   }
1843   GNUNET_assert (GNUNET_NO == grp->is_origin);
1844   struct Member *mem = grp->member;
1845
1846   struct GNUNET_CONTAINER_MultiHashMap *
1847     grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1848                                                         &grp->pub_key_hash);
1849   if (NULL == grp_replay_req)
1850   {
1851     grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1852     GNUNET_CONTAINER_multihashmap_put (replay_req_client,
1853                                        &grp->pub_key_hash, grp_replay_req,
1854                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1855   }
1856
1857   struct GNUNET_HashCode key_hash;
1858   replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset,
1859                    rep->flags, &key_hash);
1860   GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client,
1861                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1862
1863   if (0 ==
1864       client_send_origin (&grp->pub_key_hash,
1865                           GNUNET_MQ_msg_copy (&rep->header)))
1866   { /* No local origin, replay from remote members / origin. */
1867     if (NULL != mem->origin_channel)
1868     {
1869       cadet_send_channel (mem->origin_channel, &rep->header);
1870     }
1871     else
1872     {
1873       /* FIXME: not yet connected to origin */
1874       GNUNET_assert (0);
1875       GNUNET_SERVICE_client_drop (client);
1876       return;
1877     }
1878   }
1879   GNUNET_SERVICE_client_continue (client);
1880 }
1881
1882
1883 static int
1884 cadet_send_replay_response_cb (void *cls,
1885                                const struct GNUNET_HashCode *key_hash,
1886                                void *value)
1887 {
1888   struct Channel *chn = value;
1889   struct GNUNET_MessageHeader *msg = cls;
1890
1891   cadet_send_channel (chn, msg);
1892   return GNUNET_OK;
1893 }
1894
1895
1896 static int
1897 client_send_replay_response_cb (void *cls,
1898                                 const struct GNUNET_HashCode *key_hash,
1899                                 void *value)
1900 {
1901   struct GNUNET_SERVICE_Client *client = value;
1902   struct GNUNET_MessageHeader *msg = cls;
1903
1904   client_send (client, msg);
1905   return GNUNET_OK;
1906 }
1907
1908
1909 static int
1910 check_client_replay_response_end (void *cls,
1911                                   const struct MulticastReplayResponseMessage *res)
1912 {
1913   return GNUNET_OK;
1914 }
1915
1916
1917 /**
1918  * End of replay response from a client.
1919  */
1920 static void
1921 handle_client_replay_response_end (void *cls,
1922                                    const struct MulticastReplayResponseMessage *res)
1923 {
1924   struct Client *c = cls;
1925   struct GNUNET_SERVICE_Client *client = c->client;
1926   struct Group *grp = c->group;
1927
1928   if (NULL == grp)
1929   {
1930     GNUNET_break (0);
1931     GNUNET_SERVICE_client_drop (client);
1932     return;
1933   }
1934
1935   struct GNUNET_HashCode key_hash;
1936   replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
1937                    res->flags, &key_hash);
1938
1939   struct GNUNET_CONTAINER_MultiHashMap *
1940     grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1941                                                               &grp->pub_key_hash);
1942   if (NULL != grp_replay_req_cadet)
1943   {
1944     GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash);
1945   }
1946   struct GNUNET_CONTAINER_MultiHashMap *
1947     grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1948                                                                &grp->pub_key_hash);
1949   if (NULL != grp_replay_req_client)
1950   {
1951     GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash);
1952   }
1953   GNUNET_SERVICE_client_continue (client);
1954 }
1955
1956
1957 static int
1958 check_client_replay_response (void *cls,
1959                               const struct MulticastReplayResponseMessage *res)
1960 {
1961   const struct GNUNET_MessageHeader *msg = &res->header;
1962   if (GNUNET_MULTICAST_REC_OK == res->error_code)
1963   {
1964     msg = GNUNET_MQ_extract_nested_mh (res);
1965     if (NULL == msg)
1966     {
1967       return GNUNET_SYSERR;
1968     }
1969   }
1970   return GNUNET_OK;
1971 }
1972
1973
1974 /**
1975  * Incoming replay response from a client.
1976  *
1977  * Respond with a multicast message on success, or otherwise with an error code.
1978  */
1979 static void
1980 handle_client_replay_response (void *cls,
1981                                const struct MulticastReplayResponseMessage *res)
1982 {
1983   struct Client *c = cls;
1984   struct GNUNET_SERVICE_Client *client = c->client;
1985   struct Group *grp = c->group;
1986
1987   if (NULL == grp)
1988   {
1989     GNUNET_break (0);
1990     GNUNET_SERVICE_client_drop (client);
1991     return;
1992   }
1993
1994   const struct GNUNET_MessageHeader *msg = &res->header;
1995   if (GNUNET_MULTICAST_REC_OK == res->error_code)
1996   {
1997     msg = GNUNET_MQ_extract_nested_mh (res);
1998   }
1999
2000   struct GNUNET_HashCode key_hash;
2001   replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
2002                    res->flags, &key_hash);
2003
2004   struct GNUNET_CONTAINER_MultiHashMap *
2005     grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
2006                                                               &grp->pub_key_hash);
2007   if (NULL != grp_replay_req_cadet)
2008   {
2009     GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash,
2010                                                 cadet_send_replay_response_cb,
2011                                                 (void *) msg);
2012   }
2013   if (GNUNET_MULTICAST_REC_OK == res->error_code)
2014   {
2015     struct GNUNET_CONTAINER_MultiHashMap *
2016       grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
2017                                                                  &grp->pub_key_hash);
2018     if (NULL != grp_replay_req_client)
2019     {
2020       GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash,
2021                                                   client_send_replay_response_cb,
2022                                                   (void *) msg);
2023     }
2024   }
2025   else
2026   {
2027     handle_client_replay_response_end (c, res);
2028     return;
2029   }
2030   GNUNET_SERVICE_client_continue (client);
2031 }
2032
2033
2034 /**
2035  * A new client connected.
2036  *
2037  * @param cls NULL
2038  * @param client client to add
2039  * @param mq message queue for @a client
2040  * @return @a client
2041  */
2042 static void *
2043 client_notify_connect (void *cls,
2044                        struct GNUNET_SERVICE_Client *client,
2045                        struct GNUNET_MQ_Handle *mq)
2046 {
2047   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
2048   /* FIXME: send connect ACK */
2049
2050   struct Client *c = GNUNET_new (struct Client);
2051   c->client = client;
2052
2053   return c;
2054 }
2055
2056
2057 /**
2058  * Called whenever a client is disconnected.
2059  * Frees our resources associated with that client.
2060  *
2061  * @param cls closure
2062  * @param client identification of the client
2063  * @param app_ctx must match @a client
2064  */
2065 static void
2066 client_notify_disconnect (void *cls,
2067                           struct GNUNET_SERVICE_Client *client,
2068                           void *app_ctx)
2069 {
2070   struct Client *c = app_ctx;
2071   struct Group *grp = c->group;
2072   GNUNET_free (c);
2073
2074   if (NULL == grp)
2075   {
2076     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2077                 "%p User context is NULL in client_disconnect()\n", grp);
2078     GNUNET_break (0);
2079     return;
2080   }
2081
2082   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2083               "%p Client (%s) disconnected from group %s\n",
2084               grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
2085               GNUNET_h2s (&grp->pub_key_hash));
2086
2087   // FIXME (due to protocol change): here we must not remove all clients,
2088   // only the one we were notified about!
2089   struct ClientList *cl = grp->clients_head;
2090   while (NULL != cl)
2091   {
2092     if (cl->client == client)
2093     {
2094       GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
2095       GNUNET_free (cl);
2096       break;
2097     }
2098     cl = cl->next;
2099   }
2100
2101   while (GNUNET_YES == replay_req_remove_client (grp, client));
2102
2103   if (NULL == grp->clients_head)
2104   { /* Last client disconnected. */
2105 #if FIXME
2106     if (NULL != grp->tmit_head)
2107     { /* Send pending messages via CADET before cleanup. */
2108       transmit_message (grp);
2109     }
2110     else
2111 #endif
2112     {
2113       cleanup_group (grp);
2114     }
2115   }
2116 }
2117
2118
2119 /**
2120  * Service started.
2121  *
2122  * @param cls closure
2123  * @param server the initialized server
2124  * @param cfg configuration to use
2125  */
2126 static void
2127 run (void *cls,
2128      const struct GNUNET_CONFIGURATION_Handle *c,
2129      struct GNUNET_SERVICE_Handle *svc)
2130 {
2131   cfg = c;
2132   service = svc;
2133   GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
2134
2135   stats = GNUNET_STATISTICS_create ("multicast", cfg);
2136   origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2137   members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2138   group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2139   channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2140   channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2141   replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2142   replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2143
2144   cadet = GNUNET_CADET_connect (cfg);
2145
2146   GNUNET_assert (NULL != cadet);
2147
2148   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2149                                  NULL);
2150 }
2151
2152
2153 /**
2154  * Define "main" method using service macro.
2155  */
2156 GNUNET_SERVICE_MAIN
2157 ("multicast",
2158  GNUNET_SERVICE_OPTION_NONE,
2159  run,
2160  client_notify_connect,
2161  client_notify_disconnect,
2162  NULL,
2163  GNUNET_MQ_hd_fixed_size (client_origin_start,
2164                           GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START,
2165                           struct MulticastOriginStartMessage,
2166                           NULL),
2167  GNUNET_MQ_hd_var_size (client_member_join,
2168                         GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN,
2169                         struct MulticastMemberJoinMessage,
2170                         NULL),
2171  GNUNET_MQ_hd_var_size (client_join_decision,
2172                         GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
2173                         struct MulticastJoinDecisionMessageHeader,
2174                         NULL),
2175  GNUNET_MQ_hd_fixed_size (client_part_request,
2176                           GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST,
2177                           struct GNUNET_MessageHeader,
2178                           NULL),
2179  GNUNET_MQ_hd_var_size (client_multicast_message,
2180                         GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
2181                         struct GNUNET_MULTICAST_MessageHeader,
2182                         NULL),
2183  GNUNET_MQ_hd_var_size (client_multicast_request,
2184                         GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
2185                         struct GNUNET_MULTICAST_RequestHeader,
2186                         NULL),
2187  GNUNET_MQ_hd_fixed_size (client_replay_request,
2188                           GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
2189                           struct MulticastReplayRequestMessage,
2190                           NULL),
2191  GNUNET_MQ_hd_var_size (client_replay_response,
2192                         GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
2193                         struct MulticastReplayResponseMessage,
2194                         NULL),
2195  GNUNET_MQ_hd_var_size (client_replay_response_end,
2196                         GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END,
2197                         struct MulticastReplayResponseMessage,
2198                         NULL));
2199
2200 /* end of gnunet-service-multicast.c */