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