multicast tests
[oweals/gnunet.git] / src / multicast / gnunet-service-multicast.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009 Christian Grothoff (and other contributing authors)
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_core_service.h"
32 #include "gnunet_cadet_service.h"
33 #include "gnunet_multicast_service.h"
34 #include "multicast.h"
35
36 /**
37  * Handle to our current configuration.
38  */
39 static const struct GNUNET_CONFIGURATION_Handle *cfg;
40
41 /**
42  * Server handle.
43  */
44 static struct GNUNET_SERVER_Handle *server;
45
46 /**
47  * Core handle.
48  * Only used during initialization.
49  */
50 static struct GNUNET_CORE_Handle *core;
51
52 /**
53  * CADET handle.
54  */
55 static struct GNUNET_CADET_Handle *cadet;
56
57 /**
58  * Identity of this peer.
59  */
60 static struct GNUNET_PeerIdentity this_peer;
61
62 /**
63  * Handle to the statistics service.
64  */
65 static struct GNUNET_STATISTICS_Handle *stats;
66
67 /**
68  * Notification context, simplifies client broadcasts.
69  */
70 static struct GNUNET_SERVER_NotificationContext *nc;
71
72 /**
73  * All connected origin clients.
74  * Group's pub_key_hash -> struct Origin * (uniq)
75  */
76 static struct GNUNET_CONTAINER_MultiHashMap *origins;
77
78 /**
79  * All connected member clients.
80  * Group's pub_key_hash -> struct Member * (multi)
81  */
82 static struct GNUNET_CONTAINER_MultiHashMap *members;
83
84 /**
85  * Connected member clients per group.
86  * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq)
87  */
88 static struct GNUNET_CONTAINER_MultiHashMap *group_members;
89
90 /**
91  * Incoming CADET channels.
92  * Group's pub_key_hash -> struct Channel * (multi)
93  */
94 static struct GNUNET_CONTAINER_MultiHashMap *channels_in;
95
96 /**
97  * Outgoing CADET channels.
98  * Group's pub_key_hash -> struct Channel * (multi)
99  */
100 static struct GNUNET_CONTAINER_MultiHashMap *channels_out;
101
102 /**
103  * Join status of a remote peer.
104  */
105 enum JoinStatus
106 {
107   JOIN_REFUSED  = -1,
108   JOIN_NOT_ASKED = 0,
109   JOIN_WAITING   = 1,
110   JOIN_ADMITTED  = 2,
111 };
112
113 enum ChannelDirection
114 {
115   DIR_INCOMING = 0,
116   DIR_OUTGOING = 1,
117 };
118
119
120 /**
121  * Context for a CADET channel.
122  */
123 struct Channel
124 {
125   /**
126    * Group the channel belongs to.
127    *
128    * Only set for outgoing channels.
129    */
130   struct Group *grp;
131
132   /**
133    * CADET channel.
134    */
135   struct GNUNET_CADET_Channel *channel;
136
137   /**
138    * CADET transmission handle.
139    */
140   struct GNUNET_CADET_TransmitHandle *tmit_handle;
141
142   /**
143    * Public key of the target group.
144    */
145   struct GNUNET_CRYPTO_EddsaPublicKey group_key;
146
147   /**
148    * Hash of @a group_key.
149    */
150   struct GNUNET_HashCode group_key_hash;
151
152   /**
153    * Public key of the joining member.
154    */
155   struct GNUNET_CRYPTO_EcdsaPublicKey member_key;
156
157   /**
158    * Remote peer identity.
159    */
160   struct GNUNET_PeerIdentity peer;
161
162   /**
163    * Is the remote peer admitted to the group?
164    * @see enum JoinStatus
165    */
166   int8_t join_status;
167
168   /**
169    * Channel direction.
170    * @see enum ChannelDirection
171    */
172   uint8_t direction;
173 };
174
175
176 /**
177  * List of connected clients.
178  */
179 struct ClientList
180 {
181   struct ClientList *prev;
182   struct ClientList *next;
183   struct GNUNET_SERVER_Client *client;
184 };
185
186 /**
187  * Common part of the client context for both an origin and member.
188  */
189 struct Group
190 {
191   struct ClientList *clients_head;
192   struct ClientList *clients_tail;
193
194   /**
195    * Public key of the group.
196    */
197   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
198
199   /**
200    * Hash of @a pub_key.
201    */
202   struct GNUNET_HashCode pub_key_hash;
203
204   /**
205    * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
206    */
207   uint8_t is_origin;
208
209   /**
210    * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
211    */
212   uint8_t disconnected;
213 };
214
215
216 /**
217  * Client context for a group's origin.
218  */
219 struct Origin
220 {
221   struct Group grp;
222
223   /**
224    * Private key of the group.
225    */
226   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
227
228   /**
229    * Last message fragment ID sent to the group.
230    */
231   uint64_t max_fragment_id;
232 };
233
234
235 /**
236  * Client context for a group member.
237  */
238 struct Member
239 {
240   struct Group grp;
241
242   /**
243    * Private key of the member.
244    */
245   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
246
247   /**
248    * Public key of the member.
249    */
250   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
251
252   /**
253    * Hash of @a pub_key.
254    */
255   struct GNUNET_HashCode pub_key_hash;
256
257   /**
258    * Join request sent to the origin / members.
259    */
260   struct MulticastJoinRequestMessage *join_req;
261
262   /**
263    * Join decision sent in reply to our request.
264    *
265    * Only a positive decision is stored here, in case of a negative decision the
266    * client is disconnected.
267    */
268   struct MulticastJoinDecisionMessageHeader *join_dcsn;
269
270   /**
271    * CADET channel to the origin.
272    */
273   struct Channel *origin_channel;
274
275   /**
276    * Peer identity of origin.
277    */
278   struct GNUNET_PeerIdentity origin;
279
280   /**
281    * Peer identity of relays (other members to connect).
282    */
283   struct GNUNET_PeerIdentity *relays;
284
285   /**
286    * Last request fragment ID sent to the origin.
287    */
288   uint64_t max_fragment_id;
289
290   /**
291    * Number of @a relays.
292    */
293   uint32_t relay_count;
294 };
295
296
297 /**
298  * Task run during shutdown.
299  *
300  * @param cls unused
301  * @param tc unused
302  */
303 static void
304 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
305 {
306   if (NULL != core)
307   {
308     GNUNET_CORE_disconnect (core);
309     core = NULL;
310   }
311   if (NULL != cadet)
312   {
313     GNUNET_CADET_disconnect (cadet);
314     cadet = NULL;
315   }
316   if (NULL != stats)
317   {
318     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
319     stats = NULL;
320   }
321   /* FIXME: do more clean up here */
322 }
323
324
325 /**
326  * Clean up origin data structures after a client disconnected.
327  */
328 static void
329 cleanup_origin (struct Origin *orig)
330 {
331   struct Group *grp = &orig->grp;
332   GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
333 }
334
335
336 /**
337  * Clean up member data structures after a client disconnected.
338  */
339 static void
340 cleanup_member (struct Member *mem)
341 {
342   struct Group *grp = &mem->grp;
343   struct GNUNET_CONTAINER_MultiHashMap *
344     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
345                                                  &grp->pub_key_hash);
346   GNUNET_assert (NULL != grp_mem);
347   GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
348
349   if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
350   {
351     GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
352                                           grp_mem);
353     GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
354   }
355   if (NULL != mem->join_dcsn)
356   {
357     GNUNET_free (mem->join_dcsn);
358     mem->join_dcsn = NULL;
359   }
360   GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
361 }
362
363
364 /**
365  * Clean up group data structures after a client disconnected.
366  */
367 static void
368 cleanup_group (struct Group *grp)
369 {
370   (GNUNET_YES == grp->is_origin)
371     ? cleanup_origin ((struct Origin *) grp)
372     : cleanup_member ((struct Member *) grp);
373
374   GNUNET_free (grp);
375 }
376
377
378 /**
379  * Called whenever a client is disconnected.
380  *
381  * Frees our resources associated with that client.
382  *
383  * @param cls  Closure.
384  * @param client  Client handle.
385  */
386 static void
387 client_notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
388 {
389   if (NULL == client)
390     return;
391
392   struct Group *grp
393     = GNUNET_SERVER_client_get_user_context (client, struct Group);
394
395   if (NULL == grp)
396   {
397     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398                 "%p User context is NULL in client_disconnect()\n", grp);
399     GNUNET_assert (0);
400     return;
401   }
402
403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404               "%p Client (%s) disconnected from group %s\n",
405               grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
406               GNUNET_h2s (&grp->pub_key_hash));
407
408   struct ClientList *cl = grp->clients_head;
409   while (NULL != cl)
410   {
411     if (cl->client == client)
412     {
413       GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
414       GNUNET_free (cl);
415       break;
416     }
417     cl = cl->next;
418   }
419
420   if (NULL == grp->clients_head)
421   { /* Last client disconnected. */
422 #if FIXME
423     if (NULL != grp->tmit_head)
424     { /* Send pending messages via CADET before cleanup. */
425       transmit_message (grp);
426     }
427     else
428 #endif
429     {
430       cleanup_group (grp);
431     }
432   }
433 }
434
435
436 /**
437  * Send message to all clients connected to the group.
438  */
439 static void
440 client_send_msg (const struct Group *grp,
441                  const struct GNUNET_MessageHeader *msg)
442 {
443   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
444               "%p Sending message to clients.\n", grp);
445
446   struct ClientList *cl = grp->clients_head;
447   while (NULL != cl)
448   {
449     GNUNET_SERVER_notification_context_add (nc, cl->client);
450     GNUNET_SERVER_notification_context_unicast (nc, cl->client, msg, GNUNET_NO);
451     cl = cl->next;
452   }
453 }
454
455
456 /**
457  * Iterator callback for sending a message to origin clients.
458  */
459 static int
460 client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
461                        void *origin)
462 {
463   const struct GNUNET_MessageHeader *msg = cls;
464   struct Member *orig = origin;
465
466   client_send_msg (&orig->grp, msg);
467   return GNUNET_YES;
468 }
469
470
471 /**
472  * Iterator callback for sending a message to member clients.
473  */
474 static int
475 client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
476                        void *member)
477 {
478   const struct GNUNET_MessageHeader *msg = cls;
479   struct Member *mem = member;
480
481   if (NULL != mem->join_dcsn)
482   { /* Only send message to admitted members */
483     client_send_msg (&mem->grp, msg);
484   }
485   return GNUNET_YES;
486 }
487
488
489 /**
490  * Send message to all origin and member clients connected to the group.
491  *
492  * @param grp  The group to send @a msg to.
493  * @param msg  Message to send.
494  */
495 static int
496 client_send_all (struct GNUNET_HashCode *pub_key_hash,
497                  const struct GNUNET_MessageHeader *msg)
498 {
499   int n = 0;
500   if (origins != NULL)
501     n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
502                                                      client_send_origin_cb,
503                                                      (void *) msg);
504   if (members != NULL)
505     n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash,
506                                                      client_send_member_cb,
507                                                      (void *) msg);
508   return n;
509 }
510
511
512 /**
513  * Send message to all origin clients connected to the group.
514  *
515  * @param grp  The group to send @a msg to.
516  * @param msg  Message to send.
517  */
518 static int
519 client_send_origin (struct GNUNET_HashCode *pub_key_hash,
520                     const struct GNUNET_MessageHeader *msg)
521 {
522   int n = 0;
523   if (origins != NULL)
524     n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
525                                                      client_send_origin_cb,
526                                                      (void *) msg);
527   return n;
528 }
529
530
531 /**
532  * CADET is ready to transmit a message.
533  */
534 size_t
535 cadet_notify_transmit_ready (void *cls, size_t buf_size, void *buf)
536 {
537   if (0 == buf_size)
538   {
539     /* FIXME: connection closed */
540     return 0;
541   }
542   const struct GNUNET_MessageHeader *msg = cls;
543   uint16_t msg_size = ntohs (msg->size);
544   GNUNET_assert (msg_size <= buf_size);
545   memcpy (buf, msg, msg_size);
546   return msg_size;
547 }
548
549
550 /**
551  * Send a message to a CADET channel.
552  *
553  * @param chn  Channel.
554  * @param msg  Message.
555  */
556 static void
557 cadet_send_msg (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
558 {
559   chn->tmit_handle
560     = GNUNET_CADET_notify_transmit_ready (chn->channel, GNUNET_NO,
561                                           GNUNET_TIME_UNIT_FOREVER_REL,
562                                           ntohs (msg->size),
563                                           &cadet_notify_transmit_ready,
564                                           (void *) msg);
565   GNUNET_assert (NULL != chn->tmit_handle);
566 }
567
568
569 /**
570  * Create new outgoing CADET channel.
571  *
572  * @param peer
573  *        Peer to connect to.
574  * @param group_key
575  *        Public key of group the channel belongs to.
576  * @param group_key_hash
577  *        Hash of @a group_key.
578  *
579  * @return Channel.
580  */
581 static struct Channel *
582 cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
583 {
584   struct Channel *chn = GNUNET_malloc (sizeof (*chn));
585   chn->grp = grp;
586   chn->group_key = grp->pub_key;
587   chn->group_key_hash = grp->pub_key_hash;
588   chn->peer = *peer;
589   chn->direction = DIR_OUTGOING;
590   chn->join_status = JOIN_WAITING;
591   chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
592                                               GNUNET_APPLICATION_TYPE_MULTICAST,
593                                               GNUNET_CADET_OPTION_RELIABLE);
594   GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_key_hash, chn,
595                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
596   return chn;
597 }
598
599
600 /**
601  * Create CADET channel and send a join request.
602  */
603 static void
604 cadet_send_join_request (struct Member *mem)
605 {
606   mem->origin_channel = cadet_channel_create (&mem->grp, &mem->origin);
607   cadet_send_msg (mem->origin_channel, &mem->join_req->header);
608
609   uint32_t i;
610   for (i = 0; i < mem->relay_count; i++)
611   {
612     struct Channel *
613       chn = cadet_channel_create (&mem->grp, &mem->relays[i]);
614     cadet_send_msg (chn, &mem->join_req->header);
615   }
616 }
617
618
619 static int
620 cadet_send_join_decision_cb (void *cls,
621                              const struct GNUNET_HashCode *group_key_hash,
622                              void *channel)
623 {
624   const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
625   struct Channel *chn = channel;
626
627   if (0 == memcmp (&hdcsn->member_key, &chn->member_key, sizeof (chn->member_key))
628       && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer)))
629   {
630     cadet_send_msg (chn, &hdcsn->header);
631     return GNUNET_NO;
632   }
633   return GNUNET_YES;
634 }
635
636
637 /**
638  * Send join decision to a remote peer.
639  */
640 static void
641 cadet_send_join_decision (struct Group *grp,
642                           const struct MulticastJoinDecisionMessageHeader *hdcsn)
643 {
644   GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash,
645                                               &cadet_send_join_decision_cb,
646                                               (void *) hdcsn);
647 }
648
649
650 /**
651  * Iterator callback for sending a message to origin clients.
652  */
653 static int
654 cadet_send_members_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
655                        void *channel)
656 {
657   const struct GNUNET_MessageHeader *msg = cls;
658   struct Channel *chn = channel;
659   if (JOIN_ADMITTED == chn->join_status)
660     cadet_send_msg (chn, msg);
661   return GNUNET_YES;
662 }
663
664
665 static int
666 cadet_send_members (struct GNUNET_HashCode *pub_key_hash,
667                     const struct GNUNET_MessageHeader *msg)
668 {
669   int n = 0;
670   if (channels_in != NULL)
671     n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash,
672                                                      cadet_send_members_cb,
673                                                      (void *) msg);
674   return n;
675 }
676
677 /**
678  * Handle a connecting client starting an origin.
679  */
680 static void
681 client_recv_origin_start (void *cls, struct GNUNET_SERVER_Client *client,
682                           const struct GNUNET_MessageHeader *m)
683 {
684   const struct MulticastOriginStartMessage *
685     msg = (const struct MulticastOriginStartMessage *) m;
686
687   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
688   struct GNUNET_HashCode pub_key_hash;
689
690   GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
691   GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
692
693   struct Origin *
694     orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
695   struct Group *grp;
696
697   if (NULL == orig)
698   {
699     orig = GNUNET_new (struct Origin);
700     orig->priv_key = msg->group_key;
701     orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
702     grp = &orig->grp;
703     grp->is_origin = GNUNET_YES;
704     grp->pub_key = pub_key;
705     grp->pub_key_hash = pub_key_hash;
706
707     GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
708                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
709   }
710   else
711   {
712     grp = &orig->grp;
713   }
714
715   struct ClientList *cl = GNUNET_new (struct ClientList);
716   cl->client = client;
717   GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
718
719   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720               "%p Client connected as origin to group %s.\n",
721               orig, GNUNET_h2s (&grp->pub_key_hash));
722
723   GNUNET_SERVER_client_set_user_context (client, grp);
724   GNUNET_SERVER_receive_done (client, GNUNET_OK);
725 }
726
727
728 /**
729  * Handle a connecting client joining a group.
730  */
731 static void
732 client_recv_member_join (void *cls, struct GNUNET_SERVER_Client *client,
733                          const struct GNUNET_MessageHeader *m)
734 {
735   const struct MulticastMemberJoinMessage *
736     msg = (const struct MulticastMemberJoinMessage *) m;
737   uint16_t msg_size = ntohs (msg->header.size);
738
739   struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
740   struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
741
742   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
743   GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
744   GNUNET_CRYPTO_hash (&msg->group_key, sizeof (msg->group_key), &pub_key_hash);
745
746   struct GNUNET_CONTAINER_MultiHashMap *
747     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
748   struct Member *mem = NULL;
749   struct Group *grp;
750
751   if (NULL != grp_mem)
752   {
753     mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
754   }
755   if (NULL == mem)
756   {
757     mem = GNUNET_new (struct Member);
758     mem->priv_key = msg->member_key;
759     mem->pub_key = mem_pub_key;
760     mem->pub_key_hash = mem_pub_key_hash;
761     mem->max_fragment_id = 0; // FIXME
762
763     grp = &mem->grp;
764     grp->is_origin = GNUNET_NO;
765     grp->pub_key = msg->group_key;
766     grp->pub_key_hash = pub_key_hash;
767
768     if (NULL == grp_mem)
769     {
770       grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
771       GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
772                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
773     }
774     GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
775                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
776     GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
777                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
778   }
779   else
780   {
781     grp = &mem->grp;
782   }
783
784   struct ClientList *cl = GNUNET_new (struct ClientList);
785   cl->client = client;
786   GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
787
788   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789               "%p Client connected to group %s..\n",
790               mem, GNUNET_h2s (&grp->pub_key_hash));
791   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
792   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793               "%p ..as member %s (%s).\n",
794               mem, GNUNET_h2s (&mem->pub_key_hash), str);
795   GNUNET_free (str);
796
797   GNUNET_SERVER_client_set_user_context (client, grp);
798
799   if (NULL != mem->join_dcsn)
800   { /* Already got a join decision, send it to client. */
801     GNUNET_SERVER_notification_context_add (nc, client);
802     GNUNET_SERVER_notification_context_unicast (nc, client,
803                                                 (struct GNUNET_MessageHeader *)
804                                                 mem->join_dcsn,
805                                                 GNUNET_NO);
806   }
807   else if (grp->clients_head == grp->clients_tail)
808   { /* First client of the group, send join request. */
809     struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
810     uint32_t relay_count = ntohl (msg->relay_count);
811     uint16_t relay_size = relay_count * sizeof (*relays);
812     struct GNUNET_MessageHeader *join_msg = NULL;
813     uint16_t join_msg_size = 0;
814     if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
815         <= msg_size)
816     {
817       join_msg = (struct GNUNET_MessageHeader *)
818         (((char *) &msg[1]) + relay_size);
819       join_msg_size = ntohs (join_msg->size);
820     }
821     if (sizeof (*msg) + relay_size + join_msg_size != msg_size)
822     {
823       GNUNET_break (0);
824       GNUNET_SERVER_client_disconnect (client);
825       return;
826     }
827
828     struct MulticastJoinRequestMessage *
829       req = GNUNET_malloc (sizeof (*req) + join_msg_size);
830     req->header.size = htons (sizeof (*req) + join_msg_size);
831     req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
832     req->group_key = grp->pub_key;
833     req->peer = this_peer;
834     GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_key);
835     if (0 < join_msg_size)
836       memcpy (&req[1], join_msg, join_msg_size);
837
838     req->member_key = mem->pub_key;
839     req->purpose.size = htonl (msg_size
840                                - sizeof (req->header)
841                                - sizeof (req->reserved)
842                                - sizeof (req->signature));
843     req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
844
845     if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
846                                                &req->signature))
847     {
848       /* FIXME: handle error */
849       GNUNET_assert (0);
850     }
851
852     if (NULL != mem->join_req)
853       GNUNET_free (mem->join_req);
854     mem->join_req = req;
855
856     if (0 == client_send_origin (&grp->pub_key_hash, &mem->join_req->header))
857     { /* No local origins, send to remote origin */
858       cadet_send_join_request (mem);
859     }
860   }
861   GNUNET_SERVER_receive_done (client, GNUNET_OK);
862 }
863
864
865 static void
866 client_send_join_decision (struct Member *mem,
867                            const struct MulticastJoinDecisionMessageHeader *hdcsn)
868 {
869   client_send_msg (&mem->grp, &hdcsn->header);
870
871   const struct MulticastJoinDecisionMessage *
872     dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
873   if (GNUNET_YES == ntohl (dcsn->is_admitted))
874   { /* Member admitted, store join_decision. */
875     uint16_t dcsn_size = ntohs (dcsn->header.size);
876     mem->join_dcsn = GNUNET_malloc (dcsn_size);
877     memcpy (mem->join_dcsn, dcsn, dcsn_size);
878   }
879   else
880   { /* Refused entry, disconnect clients. */
881 #if FIXME
882     struct ClientList *cl = mem->grp.clients_head;
883     while (NULL != cl)
884     {
885       struct GNUNET_SERVER_Client *client = cl->client;
886       cl = cl->next;
887       GNUNET_SERVER_client_disconnect (client);
888     }
889 #endif
890   }
891 }
892
893
894 /**
895  * Join decision from client.
896  */
897 static void
898 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
899                            const struct GNUNET_MessageHeader *m)
900 {
901   struct Group *
902     grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
903   const struct MulticastJoinDecisionMessageHeader *
904     hdcsn = (const struct MulticastJoinDecisionMessageHeader *) m;
905
906   if (NULL == grp)
907   {
908     GNUNET_break (0);
909     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
910     return;
911   }
912   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913               "%p Got join decision from client for group %s..\n",
914               grp, GNUNET_h2s (&grp->pub_key_hash));
915
916   struct GNUNET_CONTAINER_MultiHashMap *
917     grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
918                                                  &grp->pub_key_hash);
919   struct Member *mem = NULL;
920   if (NULL != grp_mem)
921   {
922     struct GNUNET_HashCode member_key_hash;
923     GNUNET_CRYPTO_hash (&hdcsn->member_key, sizeof (hdcsn->member_key),
924                         &member_key_hash);
925     mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
926     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927                 "%p ..and member %s: %p\n",
928                 grp, GNUNET_h2s (&member_key_hash), mem);
929   }
930   if (NULL != mem)
931   { /* Found local member */
932     client_send_join_decision (mem, hdcsn);
933   }
934   else
935   { /* Look for remote member */
936     cadet_send_join_decision (grp, hdcsn);
937   }
938   GNUNET_SERVER_receive_done (client, GNUNET_OK);
939 }
940
941
942 /**
943  * Incoming message from a client.
944  */
945 static void
946 client_recv_multicast_message (void *cls, struct GNUNET_SERVER_Client *client,
947                                const struct GNUNET_MessageHeader *m)
948 {
949   struct Group *
950     grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
951   struct GNUNET_MULTICAST_MessageHeader *out;
952   struct Origin *orig;
953
954   if (NULL == grp)
955   {
956     GNUNET_break (0);
957     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
958     return;
959   }
960   GNUNET_assert (GNUNET_YES == grp->is_origin);
961   orig = (struct Origin *) grp;
962   /* FIXME: yucky, should use separate message structs for P2P and CS! */
963   out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (m);
964
965   out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
966   out->purpose.size = htonl (ntohs (out->header.size)
967                              - sizeof (out->header)
968                              - sizeof (out->hop_counter)
969                              - sizeof (out->signature));
970   out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
971
972   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
973                                              &out->signature))
974   {
975     GNUNET_assert (0);
976   }
977
978   client_send_all (&grp->pub_key_hash, &out->header);
979   cadet_send_members (&grp->pub_key_hash, &out->header);
980   GNUNET_free (out);
981
982   GNUNET_SERVER_receive_done (client, GNUNET_OK);
983 }
984
985
986 /**
987  * Incoming request from a client.
988  */
989 static void
990 client_recv_multicast_request (void *cls, struct GNUNET_SERVER_Client *client,
991                                const struct GNUNET_MessageHeader *m)
992 {
993   struct Group *grp = GNUNET_SERVER_client_get_user_context (client, struct Group);
994   struct Member *mem;
995   struct GNUNET_MULTICAST_RequestHeader *out;
996
997   if (NULL == grp)
998   {
999     GNUNET_break (0);
1000     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1001     return;
1002   }
1003   GNUNET_assert (GNUNET_NO == grp->is_origin);
1004   mem = (struct Member *) grp;
1005   /* FIXME: yucky, should use separate message structs for P2P and CS! */
1006   out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (m);
1007
1008   out->member_key = mem->pub_key;
1009   out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1010   out->purpose.size = htonl (ntohs (out->header.size)
1011                              - sizeof (out->header)
1012                              - sizeof (out->member_key)
1013                              - sizeof (out->signature));
1014   out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1015
1016   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1017                                              &out->signature))
1018   {
1019     GNUNET_assert (0);
1020   }
1021
1022   if (0 == client_send_origin (&grp->pub_key_hash, &out->header))
1023   { /* No local origins, send to remote origin */
1024     if (NULL != mem->origin_channel)
1025     {
1026       cadet_send_msg (mem->origin_channel, &out->header);
1027     }
1028     else
1029     {
1030       /* FIXME: not yet connected to origin */
1031       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1032       GNUNET_free (out);
1033       return;
1034     }
1035   }
1036   GNUNET_free (out);
1037   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1038 }
1039
1040
1041 /**
1042  * A new client connected.
1043  */
1044 static void
1045 client_notify_connect (void *cls, struct GNUNET_SERVER_Client *client)
1046 {
1047   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
1048   /* FIXME: send connect ACK */
1049 }
1050
1051
1052 /**
1053  * Message handlers for the server.
1054  */
1055 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1056   { &client_recv_origin_start, NULL,
1057     GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, 0 },
1058
1059   { &client_recv_member_join, NULL,
1060     GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, 0 },
1061
1062   { &client_recv_join_decision, NULL,
1063     GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, 0 },
1064
1065   { &client_recv_multicast_message, NULL,
1066     GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
1067
1068   { &client_recv_multicast_request, NULL,
1069     GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
1070
1071   {NULL, NULL, 0, 0}
1072 };
1073
1074
1075 /**
1076  * New incoming CADET channel.
1077  */
1078 static void *
1079 cadet_notify_channel_new (void *cls,
1080                           struct GNUNET_CADET_Channel *channel,
1081                           const struct GNUNET_PeerIdentity *initiator,
1082                           uint32_t port,
1083                           enum GNUNET_CADET_ChannelOption options)
1084 {
1085   return NULL;
1086 }
1087
1088
1089 /**
1090  * CADET channel is being destroyed.
1091  */
1092 static void
1093 cadet_notify_channel_end (void *cls,
1094                           const struct GNUNET_CADET_Channel *channel,
1095                           void *ctx)
1096 {
1097   if (NULL == ctx)
1098     return;
1099
1100   struct Channel *chn = ctx;
1101   if (NULL != chn->grp)
1102   {
1103     if (GNUNET_NO == chn->grp->is_origin)
1104     {
1105       struct Member *mem = (struct Member *) chn->grp;
1106       if (chn == mem->origin_channel)
1107         mem->origin_channel = NULL;
1108     }
1109   }
1110   GNUNET_free (chn);
1111 }
1112
1113
1114 /**
1115  * Incoming join request message from CADET.
1116  */
1117 int
1118 cadet_recv_join_request (void *cls,
1119                          struct GNUNET_CADET_Channel *channel,
1120                          void **ctx,
1121                          const struct GNUNET_MessageHeader *m)
1122 {
1123   const struct MulticastJoinRequestMessage *
1124     req = (const struct MulticastJoinRequestMessage *) m;
1125   uint16_t size = ntohs (m->size);
1126   if (size < sizeof (*req))
1127   {
1128     GNUNET_break_op (0);
1129     return GNUNET_SYSERR;
1130   }
1131   if (NULL != *ctx)
1132   {
1133     GNUNET_break_op (0);
1134     return GNUNET_SYSERR;
1135   }
1136   if (ntohl (req->purpose.size) != (size
1137                                     - sizeof (req->header)
1138                                     - sizeof (req->reserved)
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_key))
1148   {
1149     GNUNET_break_op (0);
1150     return GNUNET_SYSERR;
1151   }
1152
1153   struct GNUNET_HashCode group_key_hash;
1154   GNUNET_CRYPTO_hash (&req->group_key, sizeof (req->group_key), &group_key_hash);
1155
1156   struct Channel *chn = GNUNET_malloc (sizeof *chn);
1157   chn->channel = channel;
1158   chn->group_key = req->group_key;
1159   chn->group_key_hash = group_key_hash;
1160   chn->member_key = req->member_key;
1161   chn->peer = req->peer;
1162   chn->join_status = JOIN_WAITING;
1163   GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group_key_hash, chn,
1164                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1165
1166   client_send_all (&group_key_hash, m);
1167   return GNUNET_OK;
1168 }
1169
1170
1171 /**
1172  * Incoming join decision message from CADET.
1173  */
1174 int
1175 cadet_recv_join_decision (void *cls,
1176                           struct GNUNET_CADET_Channel *channel,
1177                           void **ctx,
1178                           const struct GNUNET_MessageHeader *m)
1179 {
1180   const struct MulticastJoinDecisionMessage *
1181     dcsn = (const struct MulticastJoinDecisionMessage *) m;
1182   uint16_t size = ntohs (m->size);
1183   if (size < sizeof (*dcsn))
1184   {
1185     GNUNET_break_op (0);
1186     return GNUNET_SYSERR;
1187   }
1188   struct Channel *chn = *ctx;
1189   if (NULL == chn)
1190   {
1191     GNUNET_break_op (0);
1192     return GNUNET_SYSERR;
1193   }
1194   if (NULL == chn->grp || GNUNET_NO != chn->grp->is_origin)
1195   {
1196     GNUNET_break_op (0);
1197     return GNUNET_SYSERR;
1198   }
1199   switch (chn->join_status)
1200   {
1201   case JOIN_REFUSED:
1202     return GNUNET_SYSERR;
1203
1204   case JOIN_ADMITTED:
1205     return GNUNET_OK;
1206
1207   case JOIN_NOT_ASKED:
1208   case JOIN_WAITING:
1209     break;
1210   }
1211
1212   struct MulticastJoinDecisionMessageHeader *
1213     hdcsn = GNUNET_malloc (sizeof (*hdcsn) + size);
1214   hdcsn->peer = chn->peer;
1215   memcpy (&hdcsn[1], dcsn, sizeof (*hdcsn) + size);
1216
1217   struct Member *mem = (struct Member *) chn->grp;
1218   client_send_join_decision (mem, hdcsn);
1219   GNUNET_free (hdcsn);
1220   if (GNUNET_YES == ntohs (dcsn->is_admitted))
1221   {
1222     chn->join_status = JOIN_ADMITTED;
1223     return GNUNET_OK;
1224   }
1225   else
1226   {
1227     chn->join_status = JOIN_REFUSED;
1228     return GNUNET_SYSERR;
1229   }
1230 }
1231
1232 /**
1233  * Incoming multicast message from CADET.
1234  */
1235 int
1236 cadet_recv_message (void *cls,
1237                     struct GNUNET_CADET_Channel *channel,
1238                     void **ctx,
1239                     const struct GNUNET_MessageHeader *m)
1240 {
1241   const struct GNUNET_MULTICAST_MessageHeader *
1242     msg = (const struct GNUNET_MULTICAST_MessageHeader *) m;
1243   uint16_t size = ntohs (m->size);
1244   if (size < sizeof (*msg))
1245   {
1246     GNUNET_break_op (0);
1247     return GNUNET_SYSERR;
1248   }
1249   struct Channel *chn = *ctx;
1250   if (NULL == chn)
1251   {
1252     GNUNET_break_op (0);
1253     return GNUNET_SYSERR;
1254   }
1255   if (ntohl (msg->purpose.size) != (size
1256                                     - sizeof (msg->header)
1257                                     - sizeof (msg->hop_counter)
1258                                     - sizeof (msg->signature)))
1259   {
1260     GNUNET_break_op (0);
1261     return GNUNET_SYSERR;
1262   }
1263   if (GNUNET_OK !=
1264       GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1265                                   &msg->purpose, &msg->signature,
1266                                   &chn->group_key))
1267   {
1268     GNUNET_break_op (0);
1269     return GNUNET_SYSERR;
1270   }
1271
1272   client_send_all (&chn->group_key_hash, m);
1273   return GNUNET_OK;
1274 }
1275
1276
1277 /**
1278  * Incoming multicast request message from CADET.
1279  */
1280 int
1281 cadet_recv_request (void *cls,
1282                     struct GNUNET_CADET_Channel *channel,
1283                     void **ctx,
1284                     const struct GNUNET_MessageHeader *m)
1285 {
1286   const struct GNUNET_MULTICAST_RequestHeader *
1287     req = (const struct GNUNET_MULTICAST_RequestHeader *) m;
1288   uint16_t size = ntohs (m->size);
1289   if (size < sizeof (*req))
1290   {
1291     GNUNET_break_op (0);
1292     return GNUNET_SYSERR;
1293   }
1294   struct Channel *chn = *ctx;
1295   if (NULL == chn)
1296   {
1297     GNUNET_break_op (0);
1298     return GNUNET_SYSERR;
1299   }
1300   if (ntohl (req->purpose.size) != (size
1301                                     - sizeof (req->header)
1302                                     - sizeof (req->member_key)
1303                                     - sizeof (req->signature)))
1304   {
1305     GNUNET_break_op (0);
1306     return GNUNET_SYSERR;
1307   }
1308   if (GNUNET_OK !=
1309       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1310                                   &req->purpose, &req->signature,
1311                                   &req->member_key))
1312   {
1313     GNUNET_break_op (0);
1314     return GNUNET_SYSERR;
1315   }
1316
1317   client_send_origin (&chn->group_key_hash, m);
1318   return GNUNET_OK;
1319 }
1320
1321
1322 /**
1323  * Message handlers for CADET.
1324  */
1325 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1326   { &cadet_recv_join_request, GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, 0 },
1327   { &cadet_recv_message, GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
1328   { &cadet_recv_request, GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
1329   { NULL, 0, 0 }
1330 };
1331
1332
1333 /**
1334  * Listening ports for CADET.
1335  */
1336 static const uint32_t cadet_ports[] = { GNUNET_APPLICATION_TYPE_MULTICAST, 0 };
1337
1338
1339 /**
1340  * Connected to core service.
1341  */
1342 static void
1343 core_connected_cb  (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1344 {
1345   this_peer = *my_identity;
1346
1347   stats = GNUNET_STATISTICS_create ("multicast", cfg);
1348   origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1349   members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1350   group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1351   channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1352   channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1353
1354   cadet = GNUNET_CADET_connect (cfg, NULL,
1355                                 &cadet_notify_channel_new,
1356                                 &cadet_notify_channel_end,
1357                                 cadet_handlers, cadet_ports);
1358
1359   nc = GNUNET_SERVER_notification_context_create (server, 1);
1360   GNUNET_SERVER_add_handlers (server, server_handlers);
1361   GNUNET_SERVER_disconnect_notify (server, &client_notify_disconnect, NULL);
1362
1363   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1364                                 NULL);
1365 }
1366
1367
1368 /**
1369  * Service started.
1370  *
1371  * @param cls closure
1372  * @param server the initialized server
1373  * @param cfg configuration to use
1374  */
1375 static void
1376 run (void *cls, struct GNUNET_SERVER_Handle *srv,
1377      const struct GNUNET_CONFIGURATION_Handle *c)
1378 {
1379   cfg = c;
1380   server = srv;
1381   GNUNET_SERVER_connect_notify (server, &client_notify_connect, NULL);
1382   core = GNUNET_CORE_connect (cfg, NULL, &core_connected_cb, NULL, NULL,
1383                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1384 }
1385
1386
1387 /**
1388  * The main function for the multicast service.
1389  *
1390  * @param argc number of arguments from the command line
1391  * @param argv command line arguments
1392  * @return 0 ok, 1 on error
1393  */
1394 int
1395 main (int argc, char *const *argv)
1396 {
1397   return (GNUNET_OK ==
1398           GNUNET_SERVICE_run (argc, argv, "multicast",
1399                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1400 }
1401
1402 /* end of gnunet-service-multicast.c */