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