aboutsummaryrefslogtreecommitdiff
path: root/src/multicast
diff options
context:
space:
mode:
Diffstat (limited to 'src/multicast')
-rw-r--r--src/multicast/.gitignore7
-rw-r--r--src/multicast/Makefile.am79
-rw-r--r--src/multicast/gnunet-multicast.c79
-rw-r--r--src/multicast/gnunet-service-multicast.c2234
-rw-r--r--src/multicast/multicast.conf.in22
-rw-r--r--src/multicast/multicast.h303
-rw-r--r--src/multicast/multicast_api.c1399
-rw-r--r--src/multicast/test_multicast.c758
-rw-r--r--src/multicast/test_multicast.conf56
-rw-r--r--src/multicast/test_multicast_2peers.c520
-rw-r--r--src/multicast/test_multicast_line.conf63
-rw-r--r--src/multicast/test_multicast_multipeer.c643
-rw-r--r--src/multicast/test_multicast_star.conf64
13 files changed, 0 insertions, 6227 deletions
diff --git a/src/multicast/.gitignore b/src/multicast/.gitignore
deleted file mode 100644
index a97844e81..000000000
--- a/src/multicast/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
1gnunet-service-multicast
2gnunet-multicast
3test_multicast
4test_multicast_multipeer
5test_multicast_2peers
6test_multicast_multipeer_line
7test_multicast_multipeer_star
diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am
deleted file mode 100644
index 61a9f8bf6..000000000
--- a/src/multicast/Makefile.am
+++ /dev/null
@@ -1,79 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfg_DATA = \
9 multicast.conf
10
11if MINGW
12 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
13endif
14
15if USE_COVERAGE
16 AM_CFLAGS = -fprofile-arcs -ftest-coverage
17endif
18
19lib_LTLIBRARIES = libgnunetmulticast.la
20
21libgnunetmulticast_la_SOURCES = \
22 multicast_api.c multicast.h
23libgnunetmulticast_la_LIBADD = \
24 $(top_builddir)/src/util/libgnunetutil.la \
25 $(GN_LIBINTL) $(XLIB)
26libgnunetmulticast_la_LDFLAGS = \
27 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
28 -version-info 0:0:0
29
30
31bin_PROGRAMS = \
32 gnunet-multicast
33
34libexec_PROGRAMS = \
35 gnunet-service-multicast \
36 $(EXP_LIBEXEC)
37
38gnunet_multicast_SOURCES = \
39 gnunet-multicast.c
40gnunet_multicast_LDADD = \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(GN_LIBINTL)
43
44gnunet_service_multicast_SOURCES = \
45 gnunet-service-multicast.c
46gnunet_service_multicast_LDADD = \
47 $(top_builddir)/src/util/libgnunetutil.la \
48 $(top_builddir)/src/cadet/libgnunetcadet.la \
49 $(top_builddir)/src/statistics/libgnunetstatistics.la \
50 $(GN_LIBINTL)
51
52check_PROGRAMS = \
53 test_multicast \
54 test_multicast_multipeer_star \
55 test_multicast_multipeer_line
56
57if ENABLE_TEST_RUN
58AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME;
59TESTS = $(check_PROGRAMS)
60endif
61
62test_multicast_SOURCES = \
63 test_multicast.c
64test_multicast_LDADD = \
65 libgnunetmulticast.la \
66 $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68test_multicast_multipeer_star_SOURCES = \
69 test_multicast_multipeer.c
70test_multicast_multipeer_star_LDADD = \
71 libgnunetmulticast.la \
72 $(top_builddir)/src/testbed/libgnunettestbed.la \
73 $(top_builddir)/src/util/libgnunetutil.la
74test_multicast_multipeer_line_SOURCES = \
75 test_multicast_multipeer.c
76test_multicast_multipeer_line_LDADD = \
77 libgnunetmulticast.la \
78 $(top_builddir)/src/testbed/libgnunettestbed.la \
79 $(top_builddir)/src/util/libgnunetutil.la
diff --git a/src/multicast/gnunet-multicast.c b/src/multicast/gnunet-multicast.c
deleted file mode 100644
index 63e1d52aa..000000000
--- a/src/multicast/gnunet-multicast.c
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 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-multicast.c
23 * @brief multicast for writing a tool
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28/* #include "gnunet_multicast_service.h" */
29
30/**
31 * Final status code.
32 */
33static int ret;
34
35/**
36 * Main function that will be run by the scheduler.
37 *
38 * @param cls closure
39 * @param args remaining command-line arguments
40 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
41 * @param cfg configuration
42 */
43static void
44run (void *cls, char *const *args, const char *cfgfile,
45 const struct GNUNET_CONFIGURATION_Handle *cfg)
46{
47 /* main code here */
48 puts( gettext_noop ("This command doesn't do anything yet.") );
49 ret = -1;
50}
51
52
53/**
54 * The main function.
55 *
56 * @param argc number of arguments from the command line
57 * @param argv command line arguments
58 * @return 0 ok, 1 on error
59 */
60int
61main (int argc, char *const *argv)
62{
63 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
64 /* FIMXE: add options here */
65 GNUNET_GETOPT_OPTION_END
66 };
67 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
68 return 2;
69
70 ret = (GNUNET_OK ==
71 GNUNET_PROGRAM_run (argc, argv, "gnunet-multicast",
72 gettext_noop ("This command doesn't do anything yet."),
73 options, &run,
74 NULL)) ? ret : 1;
75 GNUNET_free ((void*) argv);
76 return ret;
77}
78
79/* end of gnunet-multicast.c */
diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c
deleted file mode 100644
index 18c366118..000000000
--- a/src/multicast/gnunet-service-multicast.c
+++ /dev/null
@@ -1,2234 +0,0 @@
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 */
diff --git a/src/multicast/multicast.conf.in b/src/multicast/multicast.conf.in
deleted file mode 100644
index 97a541336..000000000
--- a/src/multicast/multicast.conf.in
+++ /dev/null
@@ -1,22 +0,0 @@
1[multicast]
2START_ON_DEMAND = @START_ON_DEMAND@
3BINARY = gnunet-service-multicast
4
5UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
6UNIX_MATCH_UID = YES
7UNIX_MATCH_GID = YES
8
9@UNIXONLY@PORT = 2109
10HOSTNAME = localhost
11ACCEPT_FROM = 127.0.0.1;
12ACCEPT_FROM6 = ::1;
13
14# DISABLE_SOCKET_FORWARDING = NO
15# USERNAME =
16# MAXBUF =
17# TIMEOUT =
18# DISABLEV6 =
19# BINDTO =
20# REJECT_FROM =
21# REJECT_FROM6 =
22# PREFIX =
diff --git a/src/multicast/multicast.h b/src/multicast/multicast.h
deleted file mode 100644
index 8a3ca14c8..000000000
--- a/src/multicast/multicast.h
+++ /dev/null
@@ -1,303 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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/multicast.h
23 * @brief multicast IPC messages
24 * @author Christian Grothoff
25 * @author Gabor X Toth
26 */
27#ifndef MULTICAST_H
28#define MULTICAST_H
29
30#include "platform.h"
31#include "gnunet_multicast_service.h"
32
33GNUNET_NETWORK_STRUCT_BEGIN
34
35
36/**
37 * Header of a join request sent to the origin or another member.
38 */
39struct MulticastJoinRequestMessage
40{
41 /**
42 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST
43 */
44 struct GNUNET_MessageHeader header;
45
46 /**
47 * Always zero.
48 */
49 uint32_t reserved;
50
51 /**
52 * ECC signature of the rest of the fields of the join request.
53 *
54 * Signature must match the public key of the joining member.
55 */
56 struct GNUNET_CRYPTO_EcdsaSignature signature;
57
58 /**
59 * Purpose for the signature and size of the signed data.
60 */
61 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
62
63 /**
64 * Public key of the target group.
65 */
66 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
67
68 /**
69 * Public key of the joining member.
70 */
71 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
72
73 /**
74 * Peer identity of the joining member.
75 */
76 struct GNUNET_PeerIdentity peer;
77
78 /* Followed by struct GNUNET_MessageHeader join_message */
79};
80
81
82/**
83 * Header of a join decision message sent to a peer requesting join.
84 */
85struct MulticastJoinDecisionMessage
86{
87 /**
88 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION
89 */
90 struct GNUNET_MessageHeader header;
91
92 /**
93 * #GNUNET_YES if the peer was admitted
94 * #GNUNET_NO if entry was refused,
95 * #GNUNET_SYSERR if the request could not be answered.
96 */
97 int32_t is_admitted;
98
99 /**
100 * Number of relays given.
101 */
102 uint32_t relay_count;
103
104 /* Followed by relay_count peer identities */
105
106 /* Followed by the join response message */
107};
108
109
110/**
111 * Header added to a struct MulticastJoinDecisionMessage
112 * when sent between the client and service.
113 */
114struct MulticastJoinDecisionMessageHeader
115{
116 /**
117 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION
118 */
119 struct GNUNET_MessageHeader header;
120
121 /**
122 * C->S: Peer to send the join decision to.
123 * S->C: Peer we received the join decision from.
124 */
125 struct GNUNET_PeerIdentity peer;
126
127 /**
128 * C->S: Public key of the member requesting join.
129 * S->C: Unused.
130 */
131 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
132
133 /* Followed by struct MulticastJoinDecisionMessage */
134};
135
136
137/**
138 * Message sent from the client to the service to notify the service
139 * about the result of a membership test.
140 */
141struct MulticastMembershipTestResultMessage
142{
143 /**
144 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBERSHIP_TEST_RESULT
145 */
146 struct GNUNET_MessageHeader header;
147
148 /**
149 * Unique ID that identifies the associated membership test.
150 */
151 uint32_t uid;
152
153 /**
154 * #GNUNET_YES if the peer is a member
155 * #GNUNET_NO if peer is not a member,
156 * #GNUNET_SYSERR if the test could not be answered.
157 */
158 int32_t is_admitted;
159};
160
161
162/**
163 * Message sent from the client to the service OR the service to the
164 * client asking for a message fragment to be replayed.
165 */
166struct MulticastReplayRequestMessage
167{
168
169 /**
170 * The message type should be
171 * #GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST.
172 */
173 struct GNUNET_MessageHeader header;
174
175 /**
176 * S->C: Public key of the member requesting replay.
177 * C->S: Unused.
178 */
179 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
180
181 /**
182 * ID of the message that is being requested.
183 */
184 uint64_t fragment_id;
185
186 /**
187 * ID of the message that is being requested.
188 */
189 uint64_t message_id;
190
191 /**
192 * Offset of the fragment that is being requested.
193 */
194 uint64_t fragment_offset;
195
196 /**
197 * Additional flags for the request.
198 */
199 uint64_t flags;
200
201 /**
202 * Replay request ID.
203 */
204 uint32_t uid;
205};
206
207
208/**
209 * Message sent from the client to the service to give the service
210 * a replayed message.
211 */
212struct MulticastReplayResponseMessage
213{
214
215 /**
216 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE
217 * or GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END
218 */
219 struct GNUNET_MessageHeader header;
220
221 /**
222 * ID of the message that is being requested.
223 */
224 uint64_t fragment_id;
225
226 /**
227 * ID of the message that is being requested.
228 */
229 uint64_t message_id;
230
231 /**
232 * Offset of the fragment that is being requested.
233 */
234 uint64_t fragment_offset;
235
236 /**
237 * Additional flags for the request.
238 */
239 uint64_t flags;
240
241 /**
242 * An `enum GNUNET_MULTICAST_ReplayErrorCode` identifying issues (in NBO).
243 */
244 int32_t error_code;
245
246 /* followed by replayed message */
247};
248
249
250/**
251 * Message sent from the client to the service to notify the service
252 * about the starting of a multicast group with this peers as its origin.
253 */
254struct MulticastOriginStartMessage
255{
256 /**
257 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START
258 */
259 struct GNUNET_MessageHeader header;
260
261 /**
262 * Always zero.
263 */
264 uint32_t reserved;
265
266 /**
267 * Private, non-ephemeral key for the multicast group.
268 */
269 struct GNUNET_CRYPTO_EddsaPrivateKey group_key;
270
271 /**
272 * Last fragment ID sent to the group, used to continue counting fragments if
273 * we resume operating * a group.
274 */
275 uint64_t max_fragment_id;
276};
277
278
279struct MulticastMemberJoinMessage
280{
281 /**
282 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN
283 */
284 struct GNUNET_MessageHeader header;
285
286 uint32_t relay_count GNUNET_PACKED;
287
288 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
289
290 struct GNUNET_CRYPTO_EcdsaPrivateKey member_key;
291
292 struct GNUNET_PeerIdentity origin;
293
294 /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
295
296 /* Followed by struct GNUNET_MessageHeader join_msg */
297};
298
299
300GNUNET_NETWORK_STRUCT_END
301
302#endif
303/* end of multicast.h */
diff --git a/src/multicast/multicast_api.c b/src/multicast/multicast_api.c
deleted file mode 100644
index e5e830225..000000000
--- a/src/multicast/multicast_api.c
+++ /dev/null
@@ -1,1399 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 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/multicast_api.c
23 * @brief Multicast service; implements multicast groups using CADET connections.
24 * @author Christian Grothoff
25 * @author Gabor X Toth
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_multicast_service.h"
31#include "multicast.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__)
34
35
36/**
37 * Handle for a request to send a message to all multicast group members
38 * (from the origin).
39 */
40struct GNUNET_MULTICAST_OriginTransmitHandle
41{
42 GNUNET_MULTICAST_OriginTransmitNotify notify;
43 void *notify_cls;
44 struct GNUNET_MULTICAST_Origin *origin;
45
46 uint64_t message_id;
47 uint64_t group_generation;
48 uint64_t fragment_offset;
49};
50
51
52/**
53 * Handle for a message to be delivered from a member to the origin.
54 */
55struct GNUNET_MULTICAST_MemberTransmitHandle
56{
57 GNUNET_MULTICAST_MemberTransmitNotify notify;
58 void *notify_cls;
59 struct GNUNET_MULTICAST_Member *member;
60
61 uint64_t request_id;
62 uint64_t fragment_offset;
63};
64
65
66struct GNUNET_MULTICAST_Group
67{
68 /**
69 * Configuration to use.
70 */
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
74 * Client connection to the service.
75 */
76 struct GNUNET_MQ_Handle *mq;
77
78 /**
79 * Message to send on connect.
80 */
81 struct GNUNET_MQ_Envelope *connect_env;
82
83 /**
84 * Time to wait until we try to reconnect on failure.
85 */
86 struct GNUNET_TIME_Relative reconnect_delay;
87
88 /**
89 * Task for reconnecting when the listener fails.
90 */
91 struct GNUNET_SCHEDULER_Task *reconnect_task;
92
93 GNUNET_MULTICAST_JoinRequestCallback join_req_cb;
94 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
95 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
96 GNUNET_MULTICAST_MessageCallback message_cb;
97 void *cb_cls;
98
99 /**
100 * Function called after disconnected from the service.
101 */
102 GNUNET_ContinuationCallback disconnect_cb;
103
104 /**
105 * Closure for @a disconnect_cb.
106 */
107 void *disconnect_cls;
108
109 /**
110 * Are we currently transmitting a message?
111 */
112 uint8_t in_transmit;
113
114 /**
115 * Number of MULTICAST_FRAGMENT_ACK messages we are still waiting for.
116 */
117 uint8_t acks_pending;
118
119 /**
120 * Is this the origin or a member?
121 */
122 uint8_t is_origin;
123
124 /**
125 * Is this channel in the process of disconnecting from the service?
126 * #GNUNET_YES or #GNUNET_NO
127 */
128 uint8_t is_disconnecting;
129};
130
131
132/**
133 * Handle for the origin of a multicast group.
134 */
135struct GNUNET_MULTICAST_Origin
136{
137 struct GNUNET_MULTICAST_Group grp;
138 struct GNUNET_MULTICAST_OriginTransmitHandle tmit;
139
140 GNUNET_MULTICAST_RequestCallback request_cb;
141};
142
143
144/**
145 * Handle for a multicast group member.
146 */
147struct GNUNET_MULTICAST_Member
148{
149 struct GNUNET_MULTICAST_Group grp;
150 struct GNUNET_MULTICAST_MemberTransmitHandle tmit;
151
152 GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb;
153
154 /**
155 * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle *
156 */
157 struct GNUNET_CONTAINER_MultiHashMap *replay_reqs;
158
159 uint64_t next_fragment_id;
160};
161
162
163/**
164 * Handle that identifies a join request.
165 *
166 * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the
167 * corresponding calls to #GNUNET_MULTICAST_join_decision().
168 */
169struct GNUNET_MULTICAST_JoinHandle
170{
171 struct GNUNET_MULTICAST_Group *group;
172
173 /**
174 * Public key of the member requesting join.
175 */
176 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
177
178 /**
179 * Peer identity of the member requesting join.
180 */
181 struct GNUNET_PeerIdentity peer;
182};
183
184
185/**
186 * Opaque handle to a replay request from the multicast service.
187 */
188struct GNUNET_MULTICAST_ReplayHandle
189{
190 struct GNUNET_MULTICAST_Group *grp;
191 struct MulticastReplayRequestMessage req;
192};
193
194
195/**
196 * Handle for a replay request.
197 */
198struct GNUNET_MULTICAST_MemberReplayHandle
199{
200};
201
202
203static void
204origin_to_all (struct GNUNET_MULTICAST_Origin *orig);
205
206static void
207member_to_origin (struct GNUNET_MULTICAST_Member *mem);
208
209
210/**
211 * Check join request message.
212 */
213static int
214check_group_join_request (void *cls,
215 const struct MulticastJoinRequestMessage *jreq)
216{
217 uint16_t size = ntohs (jreq->header.size);
218
219 if (sizeof (*jreq) == size)
220 return GNUNET_OK;
221
222 if (sizeof (*jreq) + sizeof (struct GNUNET_MessageHeader) <= size)
223 return GNUNET_OK;
224
225 return GNUNET_SYSERR;
226}
227
228
229/**
230 * Receive join request from service.
231 */
232static void
233handle_group_join_request (void *cls,
234 const struct MulticastJoinRequestMessage *jreq)
235{
236 struct GNUNET_MULTICAST_Group *grp = cls;
237 struct GNUNET_MULTICAST_JoinHandle *jh;
238 const struct GNUNET_MessageHeader *jmsg = NULL;
239
240 if (NULL == grp)
241 {
242 GNUNET_break (0);
243 return;
244 }
245 if (NULL == grp->join_req_cb)
246 return;
247
248 if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size))
249 jmsg = (const struct GNUNET_MessageHeader *) &jreq[1];
250
251 jh = GNUNET_malloc (sizeof (*jh));
252 jh->group = grp;
253 jh->member_pub_key = jreq->member_pub_key;
254 jh->peer = jreq->peer;
255 grp->join_req_cb (grp->cb_cls, &jreq->member_pub_key, jmsg, jh);
256
257 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
258}
259
260
261/**
262 * Check multicast message.
263 */
264static int
265check_group_message (void *cls,
266 const struct GNUNET_MULTICAST_MessageHeader *mmsg)
267{
268 return GNUNET_OK;
269}
270
271
272/**
273 * Receive multicast message from service.
274 */
275static void
276handle_group_message (void *cls,
277 const struct GNUNET_MULTICAST_MessageHeader *mmsg)
278{
279 struct GNUNET_MULTICAST_Group *grp = cls;
280
281 if (GNUNET_YES == grp->is_disconnecting)
282 return;
283
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285 "Calling message callback with a message of size %u.\n",
286 ntohs (mmsg->header.size));
287
288 if (NULL != grp->message_cb)
289 grp->message_cb (grp->cb_cls, mmsg);
290
291 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
292}
293
294
295/**
296 * Receive message/request fragment acknowledgement from service.
297 */
298static void
299handle_group_fragment_ack (void *cls,
300 const struct GNUNET_MessageHeader *msg)
301{
302 struct GNUNET_MULTICAST_Group *grp = cls;
303
304 LOG (GNUNET_ERROR_TYPE_DEBUG,
305 "%p Got fragment ACK. in_transmit=%u, acks_pending=%u\n",
306 grp, grp->in_transmit, grp->acks_pending);
307
308 if (0 == grp->acks_pending)
309 {
310 LOG (GNUNET_ERROR_TYPE_DEBUG,
311 "%p Ignoring extraneous fragment ACK.\n", grp);
312 return;
313 }
314 grp->acks_pending--;
315
316 if (GNUNET_YES != grp->in_transmit)
317 return;
318
319 if (GNUNET_YES == grp->is_origin)
320 origin_to_all ((struct GNUNET_MULTICAST_Origin *) grp);
321 else
322 member_to_origin ((struct GNUNET_MULTICAST_Member *) grp);
323
324 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
325}
326
327
328/**
329 * Check unicast request.
330 */
331static int
332check_origin_request (void *cls,
333 const struct GNUNET_MULTICAST_RequestHeader *req)
334{
335 return GNUNET_OK;
336}
337
338
339/**
340 * Origin receives unicast request from a member.
341 */
342static void
343handle_origin_request (void *cls,
344 const struct GNUNET_MULTICAST_RequestHeader *req)
345{
346 struct GNUNET_MULTICAST_Group *grp;
347 struct GNUNET_MULTICAST_Origin *orig = cls;
348 grp = &orig->grp;
349
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "Calling request callback with a request of size %u.\n",
352 ntohs (req->header.size));
353
354 if (NULL != orig->request_cb)
355 orig->request_cb (grp->cb_cls, req);
356
357 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
358}
359
360
361/**
362 * Receive multicast replay request from service.
363 */
364static void
365handle_group_replay_request (void *cls,
366 const struct MulticastReplayRequestMessage *rep)
367
368{
369 struct GNUNET_MULTICAST_Group *grp = cls;
370
371 if (GNUNET_YES == grp->is_disconnecting)
372 return;
373
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n");
375
376 if (0 != rep->fragment_id)
377 {
378 if (NULL != grp->replay_frag_cb)
379 {
380 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
381 rh->grp = grp;
382 rh->req = *rep;
383 grp->replay_frag_cb (grp->cb_cls, &rep->member_pub_key,
384 GNUNET_ntohll (rep->fragment_id),
385 GNUNET_ntohll (rep->flags), rh);
386 }
387 }
388 else if (0 != rep->message_id)
389 {
390 if (NULL != grp->replay_msg_cb)
391 {
392 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
393 rh->grp = grp;
394 rh->req = *rep;
395 grp->replay_msg_cb (grp->cb_cls, &rep->member_pub_key,
396 GNUNET_ntohll (rep->message_id),
397 GNUNET_ntohll (rep->fragment_offset),
398 GNUNET_ntohll (rep->flags), rh);
399 }
400 }
401
402 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
403}
404
405
406/**
407 * Check replay response.
408 */
409static int
410check_member_replay_response (void *cls,
411 const struct MulticastReplayResponseMessage *res)
412{
413 uint16_t size = ntohs (res->header.size);
414
415 if (sizeof (*res) == size)
416 return GNUNET_OK;
417
418 if (sizeof (*res) + sizeof (struct GNUNET_MULTICAST_MessageHeader) <= size)
419 return GNUNET_OK;
420
421 return GNUNET_SYSERR;
422}
423
424
425/**
426 * Receive replay response from service.
427 */
428static void
429handle_member_replay_response (void *cls,
430 const struct MulticastReplayResponseMessage *res)
431{
432 struct GNUNET_MULTICAST_Group *grp;
433 struct GNUNET_MULTICAST_Member *mem = cls;
434 grp = &mem->grp;
435
436 if (GNUNET_YES == grp->is_disconnecting)
437 return;
438
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n");
440
441 // FIXME: return result
442}
443
444
445/**
446 * Check join decision.
447 */
448static int
449check_member_join_decision (void *cls,
450 const struct MulticastJoinDecisionMessageHeader *hdcsn)
451{
452 return GNUNET_OK; // checked in handle below
453}
454
455
456/**
457 * Member receives join decision.
458 */
459static void
460handle_member_join_decision (void *cls,
461 const struct MulticastJoinDecisionMessageHeader *hdcsn)
462{
463 struct GNUNET_MULTICAST_Group *grp;
464 struct GNUNET_MULTICAST_Member *mem = cls;
465 grp = &mem->grp;
466
467 const struct MulticastJoinDecisionMessage *
468 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
469
470 uint16_t dcsn_size = ntohs (dcsn->header.size);
471 int is_admitted = ntohl (dcsn->is_admitted);
472
473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "%p Member got join decision from multicast: %d\n",
475 mem, is_admitted);
476
477 const struct GNUNET_MessageHeader *join_resp = NULL;
478 uint16_t join_resp_size = 0;
479
480 uint16_t relay_count = ntohl (dcsn->relay_count);
481 const struct GNUNET_PeerIdentity *relays = NULL;
482 uint16_t relay_size = relay_count * sizeof (*relays);
483 if (0 < relay_count)
484 {
485 if (dcsn_size < sizeof (*dcsn) + relay_size)
486 {
487 GNUNET_break_op (0);
488 is_admitted = GNUNET_SYSERR;
489 }
490 else
491 {
492 relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
493 }
494 }
495
496 if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
497 {
498 join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size);
499 join_resp_size = ntohs (join_resp->size);
500 }
501 if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
502 {
503 LOG (GNUNET_ERROR_TYPE_DEBUG,
504 "Received invalid join decision message from multicast: %u < %u + %u + %u\n",
505 dcsn_size , sizeof (*dcsn), relay_size, join_resp_size);
506 GNUNET_break_op (0);
507 is_admitted = GNUNET_SYSERR;
508 }
509
510 if (NULL != mem->join_dcsn_cb)
511 mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
512 relay_count, relays, join_resp);
513
514 // FIXME:
515 //if (GNUNET_YES != is_admitted)
516 // GNUNET_MULTICAST_member_part (mem);
517
518 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
519}
520
521
522static void
523group_cleanup (struct GNUNET_MULTICAST_Group *grp)
524{
525 if (NULL != grp->connect_env)
526 {
527 GNUNET_MQ_discard (grp->connect_env);
528 grp->connect_env = NULL;
529 }
530 if (NULL != grp->mq)
531 {
532 GNUNET_MQ_destroy (grp->mq);
533 grp->mq = NULL;
534 }
535 if (NULL != grp->disconnect_cb)
536 {
537 grp->disconnect_cb (grp->disconnect_cls);
538 grp->disconnect_cb = NULL;
539 }
540 GNUNET_free (grp);
541}
542
543
544static void
545handle_group_part_ack (void *cls,
546 const struct GNUNET_MessageHeader *msg)
547{
548 struct GNUNET_MULTICAST_Group *grp = cls;
549
550 group_cleanup (grp);
551}
552
553
554/**
555 * Function to call with the decision made for a join request.
556 *
557 * Must be called once and only once in response to an invocation of the
558 * #GNUNET_MULTICAST_JoinRequestCallback.
559 *
560 * @param join
561 * Join request handle.
562 * @param is_admitted
563 * #GNUNET_YES if the join is approved,
564 * #GNUNET_NO if it is disapproved,
565 * #GNUNET_SYSERR if we cannot answer the request.
566 * @param relay_count
567 * Number of relays given.
568 * @param relays
569 * Array of suggested peers that might be useful relays to use
570 * when joining the multicast group (essentially a list of peers that
571 * are already part of the multicast group and might thus be willing
572 * to help with routing). If empty, only this local peer (which must
573 * be the multicast origin) is a good candidate for building the
574 * multicast tree. Note that it is unnecessary to specify our own
575 * peer identity in this array.
576 * @param join_resp
577 * Message to send in response to the joining peer;
578 * can also be used to redirect the peer to a different group at the
579 * application layer; this response is to be transmitted to the
580 * peer that issued the request even if admission is denied.
581 */
582struct GNUNET_MULTICAST_ReplayHandle *
583GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join,
584 int is_admitted,
585 uint16_t relay_count,
586 const struct GNUNET_PeerIdentity *relays,
587 const struct GNUNET_MessageHeader *join_resp)
588{
589 struct GNUNET_MULTICAST_Group *grp = join->group;
590 uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
591 uint16_t relay_size = relay_count * sizeof (*relays);
592
593 struct MulticastJoinDecisionMessageHeader *hdcsn;
594 struct MulticastJoinDecisionMessage *dcsn;
595 struct GNUNET_MQ_Envelope *
596 env = GNUNET_MQ_msg_extra (hdcsn, sizeof (*dcsn) + relay_size + join_resp_size,
597 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
598 hdcsn->member_pub_key = join->member_pub_key;
599 hdcsn->peer = join->peer;
600
601 dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
602 dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
603 dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
604 dcsn->is_admitted = htonl (is_admitted);
605 dcsn->relay_count = htonl (relay_count);
606 if (0 < relay_size)
607 GNUNET_memcpy (&dcsn[1], relays, relay_size);
608 if (0 < join_resp_size)
609 GNUNET_memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
610
611 GNUNET_MQ_send (grp->mq, env);
612 GNUNET_free (join);
613 return NULL;
614}
615
616
617/**
618 * Replay a message fragment for the multicast group.
619 *
620 * @param rh
621 * Replay handle identifying which replay operation was requested.
622 * @param msg
623 * Replayed message fragment, NULL if not found / an error occurred.
624 * @param ec
625 * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode
626 * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated.
627 */
628void
629GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
630 const struct GNUNET_MessageHeader *msg,
631 enum GNUNET_MULTICAST_ReplayErrorCode ec)
632{
633 uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0;
634 struct MulticastReplayResponseMessage *res;
635 struct GNUNET_MQ_Envelope *
636 env = GNUNET_MQ_msg_extra (res, msg_size,
637 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE);
638 res->fragment_id = rh->req.fragment_id;
639 res->message_id = rh->req.message_id;
640 res->fragment_offset = rh->req.fragment_offset;
641 res->flags = rh->req.flags;
642 res->error_code = htonl (ec);
643
644 if (GNUNET_MULTICAST_REC_OK == ec)
645 {
646 GNUNET_assert (NULL != msg);
647 GNUNET_memcpy (&res[1], msg, msg_size);
648 }
649
650 GNUNET_MQ_send (rh->grp->mq, env);
651
652 if (GNUNET_MULTICAST_REC_OK != ec)
653 GNUNET_free (rh);
654}
655
656
657/**
658 * Indicate the end of the replay session.
659 *
660 * Invalidates the replay handle.
661 *
662 * @param rh
663 * Replay session to end.
664 */
665void
666GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
667{
668 struct MulticastReplayResponseMessage *end;
669 struct GNUNET_MQ_Envelope *
670 env = GNUNET_MQ_msg (end, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END);
671
672 end->fragment_id = rh->req.fragment_id;
673 end->message_id = rh->req.message_id;
674 end->fragment_offset = rh->req.fragment_offset;
675 end->flags = rh->req.flags;
676
677 GNUNET_MQ_send (rh->grp->mq, env);
678 GNUNET_free (rh);
679}
680
681
682/**
683 * Replay a message for the multicast group.
684 *
685 * @param rh
686 * Replay handle identifying which replay operation was requested.
687 * @param notify
688 * Function to call to get the message.
689 * @param notify_cls
690 * Closure for @a notify.
691 */
692void
693GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
694 GNUNET_MULTICAST_ReplayTransmitNotify notify,
695 void *notify_cls)
696{
697}
698
699
700static void
701origin_connect (struct GNUNET_MULTICAST_Origin *orig);
702
703
704static void
705origin_reconnect (void *cls)
706{
707 origin_connect (cls);
708}
709
710
711/**
712 * Origin client disconnected from service.
713 *
714 * Reconnect after backoff period.
715 */
716static void
717origin_disconnected (void *cls, enum GNUNET_MQ_Error error)
718{
719 struct GNUNET_MULTICAST_Origin *orig = cls;
720 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
721
722 LOG (GNUNET_ERROR_TYPE_DEBUG,
723 "Origin client disconnected (%d), re-connecting\n",
724 (int) error);
725 if (NULL != grp->mq)
726 {
727 GNUNET_MQ_destroy (grp->mq);
728 grp->mq = NULL;
729 }
730
731 grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
732 origin_reconnect,
733 orig);
734 grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
735}
736
737
738/**
739 * Connect to service as origin.
740 */
741static void
742origin_connect (struct GNUNET_MULTICAST_Origin *orig)
743{
744 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
745
746 struct GNUNET_MQ_MessageHandler handlers[] = {
747 GNUNET_MQ_hd_var_size (group_message,
748 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
749 struct GNUNET_MULTICAST_MessageHeader,
750 grp),
751 GNUNET_MQ_hd_var_size (origin_request,
752 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
753 struct GNUNET_MULTICAST_RequestHeader,
754 orig),
755 GNUNET_MQ_hd_fixed_size (group_fragment_ack,
756 GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
757 struct GNUNET_MessageHeader,
758 grp),
759 GNUNET_MQ_hd_var_size (group_join_request,
760 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
761 struct MulticastJoinRequestMessage,
762 grp),
763 GNUNET_MQ_hd_fixed_size (group_part_ack,
764 GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
765 struct GNUNET_MessageHeader,
766 grp),
767 GNUNET_MQ_hd_fixed_size (group_replay_request,
768 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
769 struct MulticastReplayRequestMessage,
770 grp),
771 GNUNET_MQ_handler_end ()
772 };
773
774 grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
775 handlers, origin_disconnected, orig);
776 GNUNET_assert (NULL != grp->mq);
777 GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
778}
779
780
781/**
782 * Start a multicast group.
783 *
784 * Will advertise the origin in the P2P overlay network under the respective
785 * public key so that other peer can find this peer to join it. Peers that
786 * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
787 * either an existing group member or to the origin. If the joining is
788 * approved, the member is cleared for @e replay and will begin to receive
789 * messages transmitted to the group. If joining is disapproved, the failed
790 * candidate will be given a response. Members in the group can send messages
791 * to the origin (one at a time).
792 *
793 * @param cfg
794 * Configuration to use.
795 * @param priv_key
796 * ECC key that will be used to sign messages for this
797 * multicast session; public key is used to identify the multicast group;
798 * @param max_fragment_id
799 * Maximum fragment ID already sent to the group.
800 * 0 for a new group.
801 * @param join_request_cb
802 * Function called to approve / disapprove joining of a peer.
803 * @param replay_frag_cb
804 * Function that can be called to replay a message fragment.
805 * @param replay_msg_cb
806 * Function that can be called to replay a message.
807 * @param request_cb
808 * Function called with message fragments from group members.
809 * @param message_cb
810 * Function called with the message fragments sent to the
811 * network by GNUNET_MULTICAST_origin_to_all(). These message fragments
812 * should be stored for answering replay requests later.
813 * @param cls
814 * Closure for the various callbacks that follow.
815 *
816 * @return Handle for the origin, NULL on error.
817 */
818struct GNUNET_MULTICAST_Origin *
819GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
820 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
821 uint64_t max_fragment_id,
822 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
823 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
824 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
825 GNUNET_MULTICAST_RequestCallback request_cb,
826 GNUNET_MULTICAST_MessageCallback message_cb,
827 void *cls)
828{
829 struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
830 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
831
832 struct MulticastOriginStartMessage *start;
833 grp->connect_env = GNUNET_MQ_msg (start,
834 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
835 start->max_fragment_id = max_fragment_id;
836 start->group_key = *priv_key;
837
838 grp->cfg = cfg;
839 grp->is_origin = GNUNET_YES;
840 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
841
842 grp->cb_cls = cls;
843 grp->join_req_cb = join_request_cb;
844 grp->replay_frag_cb = replay_frag_cb;
845 grp->replay_msg_cb = replay_msg_cb;
846 grp->message_cb = message_cb;
847
848 orig->request_cb = request_cb;
849
850 origin_connect (orig);
851 return orig;
852}
853
854
855/**
856 * Stop a multicast group.
857 *
858 * @param origin
859 * Multicast group to stop.
860 */
861void
862GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
863 GNUNET_ContinuationCallback stop_cb,
864 void *stop_cls)
865{
866 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
867 struct GNUNET_MQ_Envelope *env;
868
869 grp->is_disconnecting = GNUNET_YES;
870 grp->disconnect_cb = stop_cb;
871 grp->disconnect_cls = stop_cls;
872 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
873 GNUNET_MQ_send (grp->mq, env);
874}
875
876
877static void
878origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
879{
880 LOG (GNUNET_ERROR_TYPE_DEBUG, "%p origin_to_all()\n", orig);
881 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
882 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
883 GNUNET_assert (GNUNET_YES == grp->in_transmit);
884
885 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
886 struct GNUNET_MULTICAST_MessageHeader *msg;
887 struct GNUNET_MQ_Envelope *
888 env = GNUNET_MQ_msg_extra (msg, buf_size - sizeof(*msg),
889 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
890
891 int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
892
893 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
894 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
895 {
896 LOG (GNUNET_ERROR_TYPE_ERROR,
897 "%p OriginTransmitNotify() returned error or invalid message size.\n",
898 orig);
899 /* FIXME: handle error */
900 GNUNET_MQ_discard (env);
901 return;
902 }
903
904 if (GNUNET_NO == ret && 0 == buf_size)
905 {
906 LOG (GNUNET_ERROR_TYPE_DEBUG,
907 "%p OriginTransmitNotify() - transmission paused.\n", orig);
908 GNUNET_MQ_discard (env);
909 return; /* Transmission paused. */
910 }
911
912 msg->header.size = htons (sizeof (*msg) + buf_size);
913 msg->message_id = GNUNET_htonll (tmit->message_id);
914 msg->group_generation = tmit->group_generation;
915 msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
916 tmit->fragment_offset += sizeof (*msg) + buf_size;
917
918 grp->acks_pending++;
919 GNUNET_MQ_send (grp->mq, env);
920
921 if (GNUNET_YES == ret)
922 grp->in_transmit = GNUNET_NO;
923}
924
925
926/**
927 * Send a message to the multicast group.
928 *
929 * @param orig
930 * Handle to the multicast group.
931 * @param message_id
932 * Application layer ID for the message. Opaque to multicast.
933 * @param group_generation
934 * Group generation of the message.
935 * Documented in struct GNUNET_MULTICAST_MessageHeader.
936 * @param notify
937 * Function to call to get the message.
938 * @param notify_cls
939 * Closure for @a notify.
940 *
941 * @return Message handle on success,
942 * NULL on error (i.e. another request is already pending).
943 */
944struct GNUNET_MULTICAST_OriginTransmitHandle *
945GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
946 uint64_t message_id,
947 uint64_t group_generation,
948 GNUNET_MULTICAST_OriginTransmitNotify notify,
949 void *notify_cls)
950{
951 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
952 if (GNUNET_YES == grp->in_transmit)
953 return NULL;
954 grp->in_transmit = GNUNET_YES;
955
956 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
957 tmit->origin = orig;
958 tmit->message_id = message_id;
959 tmit->fragment_offset = 0;
960 tmit->group_generation = group_generation;
961 tmit->notify = notify;
962 tmit->notify_cls = notify_cls;
963
964 origin_to_all (orig);
965 return tmit;
966}
967
968
969/**
970 * Resume message transmission to multicast group.
971 *
972 * @param th
973 * Transmission to cancel.
974 */
975void
976GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
977{
978 struct GNUNET_MULTICAST_Group *grp = &th->origin->grp;
979 if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
980 return;
981 origin_to_all (th->origin);
982}
983
984
985/**
986 * Cancel request for message transmission to multicast group.
987 *
988 * @param th
989 * Transmission to cancel.
990 */
991void
992GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
993{
994 th->origin->grp.in_transmit = GNUNET_NO;
995}
996
997
998static void
999member_connect (struct GNUNET_MULTICAST_Member *mem);
1000
1001
1002static void
1003member_reconnect (void *cls)
1004{
1005 member_connect (cls);
1006}
1007
1008
1009/**
1010 * Member client disconnected from service.
1011 *
1012 * Reconnect after backoff period.
1013 */
1014static void
1015member_disconnected (void *cls, enum GNUNET_MQ_Error error)
1016{
1017 struct GNUNET_MULTICAST_Member *mem = cls;
1018 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1019
1020 LOG (GNUNET_ERROR_TYPE_DEBUG,
1021 "Member client disconnected (%d), re-connecting\n",
1022 (int) error);
1023 GNUNET_MQ_destroy (grp->mq);
1024 grp->mq = NULL;
1025
1026 grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
1027 member_reconnect,
1028 mem);
1029 grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
1030}
1031
1032
1033/**
1034 * Connect to service as member.
1035 */
1036static void
1037member_connect (struct GNUNET_MULTICAST_Member *mem)
1038{
1039 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1040
1041 struct GNUNET_MQ_MessageHandler handlers[] = {
1042 GNUNET_MQ_hd_var_size (group_message,
1043 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1044 struct GNUNET_MULTICAST_MessageHeader,
1045 grp),
1046 GNUNET_MQ_hd_fixed_size (group_fragment_ack,
1047 GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
1048 struct GNUNET_MessageHeader,
1049 grp),
1050 GNUNET_MQ_hd_var_size (group_join_request,
1051 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1052 struct MulticastJoinRequestMessage,
1053 grp),
1054 GNUNET_MQ_hd_var_size (member_join_decision,
1055 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1056 struct MulticastJoinDecisionMessageHeader,
1057 mem),
1058 GNUNET_MQ_hd_fixed_size (group_part_ack,
1059 GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
1060 struct GNUNET_MessageHeader,
1061 grp),
1062 GNUNET_MQ_hd_fixed_size (group_replay_request,
1063 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1064 struct MulticastReplayRequestMessage,
1065 grp),
1066 GNUNET_MQ_hd_var_size (member_replay_response,
1067 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1068 struct MulticastReplayResponseMessage,
1069 mem),
1070 GNUNET_MQ_handler_end ()
1071 };
1072
1073 grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
1074 handlers, member_disconnected, mem);
1075 GNUNET_assert (NULL != grp->mq);
1076 GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
1077}
1078
1079
1080/**
1081 * Join a multicast group.
1082 *
1083 * The entity joining is always the local peer. Further information about the
1084 * candidate can be provided in the @a join_request message. If the join fails, the
1085 * @a message_cb is invoked with a (failure) response and then with NULL. If
1086 * the join succeeds, outstanding (state) messages and ongoing multicast
1087 * messages will be given to the @a message_cb until the member decides to part
1088 * the group. The @a replay_cb function may be called at any time by the
1089 * multicast service to support relaying messages to other members of the group.
1090 *
1091 * @param cfg
1092 * Configuration to use.
1093 * @param group_key
1094 * ECC public key that identifies the group to join.
1095 * @param member_key
1096 * ECC key that identifies the member
1097 * and used to sign requests sent to the origin.
1098 * @param origin
1099 * Peer ID of the origin to send unicast requsets to. If NULL,
1100 * unicast requests are sent back via multiple hops on the reverse path
1101 * of multicast messages.
1102 * @param relay_count
1103 * Number of peers in the @a relays array.
1104 * @param relays
1105 * Peer identities of members of the group, which serve as relays
1106 * and can be used to join the group at. and send the @a join_request to.
1107 * If empty, the @a join_request is sent directly to the @a origin.
1108 * @param join_msg
1109 * Application-dependent join message to be passed to the peer @a origin.
1110 * @param join_request_cb
1111 * Function called to approve / disapprove joining of a peer.
1112 * @param join_decision_cb
1113 * Function called to inform about the join decision.
1114 * @param replay_frag_cb
1115 * Function that can be called to replay message fragments
1116 * this peer already knows from this group. NULL if this
1117 * client is unable to support replay.
1118 * @param replay_msg_cb
1119 * Function that can be called to replay message fragments
1120 * this peer already knows from this group. NULL if this
1121 * client is unable to support replay.
1122 * @param message_cb
1123 * Function to be called for all message fragments we
1124 * receive from the group, excluding those our @a replay_cb
1125 * already has.
1126 * @param cls
1127 * Closure for callbacks.
1128 *
1129 * @return Handle for the member, NULL on error.
1130 */
1131struct GNUNET_MULTICAST_Member *
1132GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
1133 const struct GNUNET_CRYPTO_EddsaPublicKey *group_pub_key,
1134 const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key,
1135 const struct GNUNET_PeerIdentity *origin,
1136 uint16_t relay_count,
1137 const struct GNUNET_PeerIdentity *relays,
1138 const struct GNUNET_MessageHeader *join_msg,
1139 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
1140 GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
1141 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
1142 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
1143 GNUNET_MULTICAST_MessageCallback message_cb,
1144 void *cls)
1145{
1146 struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
1147 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1148
1149 uint16_t relay_size = relay_count * sizeof (*relays);
1150 uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
1151 struct MulticastMemberJoinMessage *join;
1152 grp->connect_env = GNUNET_MQ_msg_extra (join, relay_size + join_msg_size,
1153 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
1154 join->group_pub_key = *group_pub_key;
1155 join->member_key = *member_key;
1156 join->origin = *origin;
1157 join->relay_count = ntohl (relay_count);
1158 if (0 < relay_size)
1159 GNUNET_memcpy (&join[1], relays, relay_size);
1160 if (0 < join_msg_size)
1161 GNUNET_memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
1162
1163 grp->cfg = cfg;
1164 grp->is_origin = GNUNET_NO;
1165 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1166
1167 mem->join_dcsn_cb = join_decision_cb;
1168 grp->join_req_cb = join_request_cb;
1169 grp->replay_frag_cb = replay_frag_cb;
1170 grp->replay_msg_cb = replay_msg_cb;
1171 grp->message_cb = message_cb;
1172 grp->cb_cls = cls;
1173
1174 member_connect (mem);
1175 return mem;
1176}
1177
1178
1179/**
1180 * Part a multicast group.
1181 *
1182 * Disconnects from all group members and invalidates the @a member handle.
1183 *
1184 * An application-dependent part message can be transmitted beforehand using
1185 * #GNUNET_MULTICAST_member_to_origin())
1186 *
1187 * @param member
1188 * Membership handle.
1189 */
1190void
1191GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
1192 GNUNET_ContinuationCallback part_cb,
1193 void *part_cls)
1194{
1195 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1196 struct GNUNET_MQ_Envelope *env;
1197
1198 mem->join_dcsn_cb = NULL;
1199 grp->join_req_cb = NULL;
1200 grp->message_cb = NULL;
1201 grp->replay_msg_cb = NULL;
1202 grp->replay_frag_cb = NULL;
1203 grp->is_disconnecting = GNUNET_YES;
1204 grp->disconnect_cb = part_cb;
1205 grp->disconnect_cls = part_cls;
1206 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
1207 GNUNET_MQ_send (grp->mq, env);
1208}
1209
1210
1211void
1212member_replay_request (struct GNUNET_MULTICAST_Member *mem,
1213 uint64_t fragment_id,
1214 uint64_t message_id,
1215 uint64_t fragment_offset,
1216 uint64_t flags)
1217{
1218 struct MulticastReplayRequestMessage *rep;
1219 struct GNUNET_MQ_Envelope *
1220 env = GNUNET_MQ_msg (rep, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST);
1221
1222 rep->fragment_id = GNUNET_htonll (fragment_id);
1223 rep->message_id = GNUNET_htonll (message_id);
1224 rep->fragment_offset = GNUNET_htonll (fragment_offset);
1225 rep->flags = GNUNET_htonll (flags);
1226
1227 GNUNET_MQ_send (mem->grp.mq, env);
1228}
1229
1230
1231/**
1232 * Request a fragment to be replayed by fragment ID.
1233 *
1234 * Useful if messages below the @e max_known_fragment_id given when joining are
1235 * needed and not known to the client.
1236 *
1237 * @param member
1238 * Membership handle.
1239 * @param fragment_id
1240 * ID of a message fragment that this client would like to see replayed.
1241 * @param flags
1242 * Additional flags for the replay request.
1243 * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback
1244 *
1245 * @return Replay request handle.
1246 */
1247struct GNUNET_MULTICAST_MemberReplayHandle *
1248GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem,
1249 uint64_t fragment_id,
1250 uint64_t flags)
1251{
1252 member_replay_request (mem, fragment_id, 0, 0, flags);
1253 // FIXME: return something useful
1254 return NULL;
1255}
1256
1257
1258/**
1259 * Request a message fragment to be replayed.
1260 *
1261 * Useful if messages below the @e max_known_fragment_id given when joining are
1262 * needed and not known to the client.
1263 *
1264 * @param member
1265 * Membership handle.
1266 * @param message_id
1267 * ID of the message this client would like to see replayed.
1268 * @param fragment_offset
1269 * Offset of the fragment within the message to replay.
1270 * @param flags
1271 * Additional flags for the replay request.
1272 * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback
1273 *
1274 * @return Replay request handle, NULL on error.
1275 */
1276struct GNUNET_MULTICAST_MemberReplayHandle *
1277GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem,
1278 uint64_t message_id,
1279 uint64_t fragment_offset,
1280 uint64_t flags)
1281{
1282 member_replay_request (mem, 0, message_id, fragment_offset, flags);
1283 // FIXME: return something useful
1284 return NULL;
1285}
1286
1287
1288static void
1289member_to_origin (struct GNUNET_MULTICAST_Member *mem)
1290{
1291 LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
1292 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1293 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1294 GNUNET_assert (GNUNET_YES == grp->in_transmit);
1295
1296 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
1297 struct GNUNET_MULTICAST_RequestHeader *req;
1298 struct GNUNET_MQ_Envelope *
1299 env = GNUNET_MQ_msg_extra (req, buf_size - sizeof(*req),
1300 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
1301
1302 int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
1303
1304 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
1305 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
1306 {
1307 LOG (GNUNET_ERROR_TYPE_ERROR,
1308 "MemberTransmitNotify() returned error or invalid message size. "
1309 "ret=%d, buf_size=%u\n", ret, buf_size);
1310 /* FIXME: handle error */
1311 GNUNET_MQ_discard (env);
1312 return;
1313 }
1314
1315 if (GNUNET_NO == ret && 0 == buf_size)
1316 {
1317 /* Transmission paused. */
1318 GNUNET_MQ_discard (env);
1319 return;
1320 }
1321
1322 req->header.size = htons (sizeof (*req) + buf_size);
1323 req->request_id = GNUNET_htonll (tmit->request_id);
1324 req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
1325 tmit->fragment_offset += sizeof (*req) + buf_size;
1326
1327 GNUNET_MQ_send (grp->mq, env);
1328
1329 if (GNUNET_YES == ret)
1330 grp->in_transmit = GNUNET_NO;
1331}
1332
1333
1334/**
1335 * Send a message to the origin of the multicast group.
1336 *
1337 * @param mem
1338 * Membership handle.
1339 * @param request_id
1340 * Application layer ID for the request. Opaque to multicast.
1341 * @param notify
1342 * Callback to call to get the message.
1343 * @param notify_cls
1344 * Closure for @a notify.
1345 *
1346 * @return Handle to cancel request, NULL on error (i.e. request already pending).
1347 */
1348struct GNUNET_MULTICAST_MemberTransmitHandle *
1349GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
1350 uint64_t request_id,
1351 GNUNET_MULTICAST_MemberTransmitNotify notify,
1352 void *notify_cls)
1353{
1354 if (GNUNET_YES == mem->grp.in_transmit)
1355 return NULL;
1356 mem->grp.in_transmit = GNUNET_YES;
1357
1358 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1359 tmit->member = mem;
1360 tmit->request_id = request_id;
1361 tmit->fragment_offset = 0;
1362 tmit->notify = notify;
1363 tmit->notify_cls = notify_cls;
1364
1365 member_to_origin (mem);
1366 return tmit;
1367}
1368
1369
1370/**
1371 * Resume message transmission to origin.
1372 *
1373 * @param th
1374 * Transmission to cancel.
1375 */
1376void
1377GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1378{
1379 struct GNUNET_MULTICAST_Group *grp = &th->member->grp;
1380 if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
1381 return;
1382 member_to_origin (th->member);
1383}
1384
1385
1386/**
1387 * Cancel request for message transmission to origin.
1388 *
1389 * @param th
1390 * Transmission to cancel.
1391 */
1392void
1393GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1394{
1395 th->member->grp.in_transmit = GNUNET_NO;
1396}
1397
1398
1399/* end of multicast_api.c */
diff --git a/src/multicast/test_multicast.c b/src/multicast/test_multicast.c
deleted file mode 100644
index 70efdcbfb..000000000
--- a/src/multicast/test_multicast.c
+++ /dev/null
@@ -1,758 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 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/test_multicast.c
23 * @brief Tests for the Multicast API.
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_common.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_testing_lib.h"
34#include "gnunet_multicast_service.h"
35
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
37
38/**
39 * Return value from 'main'.
40 */
41static int res;
42
43/**
44 * Handle for task for timeout termination.
45 */
46static struct GNUNET_SCHEDULER_Task * end_badly_task;
47
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50struct GNUNET_PeerIdentity this_peer;
51
52struct GNUNET_MULTICAST_Origin *origin;
53struct GNUNET_MULTICAST_Member *member;
54
55struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
56struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
57
58struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
59struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
60
61struct TransmitClosure {
62 struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit;
63 struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit;
64 char * data[16];
65 uint8_t data_delay[16];
66 uint8_t data_count;
67 uint8_t paused;
68 uint8_t n;
69} tmit_cls;
70
71struct OriginClosure {
72 uint8_t msgs_expected;
73 uint8_t n;
74} origin_cls;
75
76struct MemberClosure {
77 uint8_t msgs_expected;
78 size_t n;
79} member_cls;
80
81struct GNUNET_MessageHeader *join_req, *join_resp;
82
83enum
84{
85 TEST_NONE = 0,
86 TEST_ORIGIN_START = 1,
87 TEST_MEMBER_JOIN_REFUSE = 2,
88 TEST_MEMBER_JOIN_ADMIT = 3,
89 TEST_ORIGIN_TO_ALL = 4,
90 TEST_ORIGIN_TO_ALL_RECV = 5,
91 TEST_MEMBER_TO_ORIGIN = 6,
92 TEST_MEMBER_REPLAY_ERROR = 7,
93 TEST_MEMBER_REPLAY_OK = 8,
94 TEST_MEMBER_PART = 9,
95 TEST_ORIGIN_STOP = 10,
96} test;
97
98uint64_t replay_fragment_id;
99uint64_t replay_flags;
100
101static void
102member_join (int t);
103
104
105/**
106 * Clean up all resources used.
107 */
108static void
109cleanup ()
110{
111 if (NULL != member)
112 {
113 GNUNET_MULTICAST_member_part (member, NULL, NULL);
114 member = NULL;
115 }
116 if (NULL != origin)
117 {
118 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
119 origin = NULL;
120 }
121}
122
123
124/**
125 * Terminate the test case (failure).
126 *
127 * @param cls NULL
128 */
129static void
130end_badly (void *cls)
131{
132 res = 1;
133 cleanup ();
134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
135}
136
137
138/**
139 * Terminate the test case (success).
140 *
141 * @param cls NULL
142 */
143static void
144end_normally (void *cls)
145{
146 res = 0;
147 cleanup ();
148 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n");
149}
150
151
152/**
153 * Finish the test case (successfully).
154 */
155static void
156end ()
157{
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
159
160 if (end_badly_task != NULL)
161 {
162 GNUNET_SCHEDULER_cancel (end_badly_task);
163 end_badly_task = NULL;
164 }
165 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
166 &end_normally, NULL);
167}
168
169
170static void
171tmit_resume (void *cls)
172{
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
174 struct TransmitClosure *tmit = cls;
175 if (NULL != tmit->orig_tmit)
176 GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit);
177 else if (NULL != tmit->mem_tmit)
178 GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit);
179}
180
181
182static int
183tmit_notify (void *cls, size_t *data_size, void *data)
184{
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "Test #%u: origin_tmit_notify()\n", test);
187 struct TransmitClosure *tmit = cls;
188
189 if (0 == tmit->data_count)
190 {
191 *data_size = 0;
192 return GNUNET_YES;
193 }
194
195 uint16_t size = strlen (tmit->data[tmit->n]);
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197 "Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n",
198 (unsigned int) *data_size,
199 tmit->n + 1,
200 tmit->data_count,
201 size);
202 if (*data_size < size)
203 {
204 *data_size = 0;
205 GNUNET_assert (0);
206 return GNUNET_SYSERR;
207 }
208
209 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
210 {
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
212 tmit->paused = GNUNET_YES;
213 GNUNET_SCHEDULER_add_delayed (
214 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
215 tmit->data_delay[tmit->n]),
216 tmit_resume, tmit);
217 *data_size = 0;
218 return GNUNET_NO;
219 }
220 tmit->paused = GNUNET_NO;
221
222 *data_size = size;
223 GNUNET_memcpy (data, tmit->data[tmit->n], size);
224
225 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
226}
227
228
229static void
230member_recv_join_request (void *cls,
231 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
232 const struct GNUNET_MessageHeader *join_msg,
233 struct GNUNET_MULTICAST_JoinHandle *jh)
234{
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 "Test #%u: member_recv_join_request()\n", test);
237}
238
239
240static void
241origin_stopped (void *cls)
242{
243 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244 "Test #%u: origin_stopped()\n", test);
245 end ();
246}
247
248
249static void
250schedule_origin_stop (void *cls)
251{
252 test = TEST_ORIGIN_STOP;
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254 "Test #%u: origin_stop()\n", test);
255 GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL);
256 origin = NULL;
257}
258
259
260static void
261member_parted (void *cls)
262{
263 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
264 "Test #%u: member_parted()\n", test);
265 member = NULL;
266
267 switch (test)
268 {
269 case TEST_MEMBER_JOIN_REFUSE:
270 // Test 3 starts here
271 member_join (TEST_MEMBER_JOIN_ADMIT);
272 break;
273
274 case TEST_MEMBER_PART:
275 GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL);
276 break;
277
278 default:
279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280 "Invalid test #%d in member_parted()\n", test);
281 GNUNET_assert (0);
282 }
283}
284
285
286static void
287schedule_member_part (void *cls)
288{
289 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
290 "Test #%u: schedule_member_part()\n", test);
291 GNUNET_MULTICAST_member_part (member, member_parted, NULL);
292}
293
294
295static void
296member_part ()
297{
298 test = TEST_MEMBER_PART;
299 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
300 "Test #%u: member_part()\n", test);
301 // Test 10 starts here
302 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
303}
304
305
306static void
307member_replay_ok ()
308{
309 // Execution of test 8 here
310 test = TEST_MEMBER_REPLAY_OK;
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 "Test #%u: member_replay_ok()\n", test);
313 replay_fragment_id = 1;
314 replay_flags = 1 | 1<<11;
315 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
316 replay_flags);
317}
318
319
320static void
321member_replay_error ()
322{
323 test = TEST_MEMBER_REPLAY_ERROR;
324 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
325 "Test #%u: member_replay_error()\n", test);
326 replay_fragment_id = 1234;
327 replay_flags = 11 | 1<<11;
328 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
329 replay_flags);
330}
331
332
333static void
334origin_recv_replay_msg (void *cls,
335 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
336 uint64_t message_id,
337 uint64_t fragment_offset,
338 uint64_t flags,
339 struct GNUNET_MULTICAST_ReplayHandle *rh)
340{
341 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
342 "Test #%u: origin_recv_replay_msg()\n", test);
343 GNUNET_assert (0);
344}
345
346
347static void
348member_recv_replay_msg (void *cls,
349 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
350 uint64_t message_id,
351 uint64_t fragment_offset,
352 uint64_t flags,
353 struct GNUNET_MULTICAST_ReplayHandle *rh)
354{
355 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
356 "Test #%u: member_recv_replay_msg()\n", test);
357 GNUNET_assert (0);
358}
359
360
361static void
362origin_recv_replay_frag (void *cls,
363 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
364 uint64_t fragment_id,
365 uint64_t flags,
366 struct GNUNET_MULTICAST_ReplayHandle *rh)
367{
368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
369 "Test #%u: origin_recv_replay_frag()"
370 " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n",
371 test, fragment_id, flags);
372 GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags);
373 switch (test)
374 {
375 case TEST_MEMBER_REPLAY_ERROR:
376 // Test 8 starts here
377 GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR);
378 member_replay_ok ();
379 break;
380
381 case TEST_MEMBER_REPLAY_OK:
382 {
383 struct GNUNET_MULTICAST_MessageHeader mmsg = {
384 .header = {
385 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE),
386 .size = htons (sizeof (mmsg)),
387 },
388 .fragment_id = GNUNET_htonll (1),
389 .message_id = GNUNET_htonll (1),
390 .fragment_offset = 0,
391 .group_generation = GNUNET_htonll (1),
392 .flags = 0,
393 };
394 member_cls.n = 0;
395 member_cls.msgs_expected = 1;
396 GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK);
397 GNUNET_MULTICAST_replay_response_end (rh);
398 break;
399 }
400
401 default:
402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 "Invalid test #%d in origin_recv_replay_frag()\n", test);
404 GNUNET_assert (0);
405 }
406}
407
408
409static void
410member_recv_replay_frag (void *cls,
411 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
412 uint64_t fragment_id,
413 uint64_t flags,
414 struct GNUNET_MULTICAST_ReplayHandle *rh)
415{
416 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
417 "Test #%u: member_recv_replay_frag()\n", test);
418 GNUNET_assert (0);
419}
420
421
422static void
423origin_recv_request (void *cls,
424 const struct GNUNET_MULTICAST_RequestHeader *req)
425{
426 struct OriginClosure *ocls = cls;
427 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
428 "Test #%u: origin_recv_request()\n", test);
429 if (++ocls->n != ocls->msgs_expected)
430 return;
431
432 GNUNET_assert (0 == memcmp (&req->member_pub_key,
433 &member_pub_key, sizeof (member_pub_key)));
434
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Test #%u: verify message content, take first 3 bytes: %.3s\n",
437 test, (char *)&req[1]);
438 GNUNET_assert (0 == memcmp (&req[1], "abc", 3));
439
440 // Test 7 starts here
441 member_replay_error ();
442}
443
444
445static void
446member_to_origin ()
447{
448 test = TEST_MEMBER_TO_ORIGIN;
449 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
450 "Test #%u: member_to_origin()\n", test);
451
452 struct TransmitClosure *tmit = &tmit_cls;
453 *tmit = (struct TransmitClosure) {};
454 tmit->data[0] = "abc def";
455 tmit->data[1] = "ghi jkl mno";
456 tmit->data_delay[1] = 2;
457 tmit->data[2] = "pqr stuw xyz";
458 tmit->data_count = 3;
459
460 origin_cls.n = 0;
461 origin_cls.msgs_expected = 1;
462
463 tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1,
464 tmit_notify, tmit);
465}
466
467
468static void
469member_recv_message (void *cls,
470 const struct GNUNET_MULTICAST_MessageHeader *msg)
471{
472 struct MemberClosure *mcls = cls;
473
474 // Test 5 starts here after message has been received from origin
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Test #%u: member_recv_message() %u/%u\n",
477 test,
478 (unsigned int) (mcls->n + 1),
479 mcls->msgs_expected);
480 if (++mcls->n != mcls->msgs_expected)
481 return;
482
483 // FIXME: check message content
484
485 switch (test)
486 {
487 case TEST_ORIGIN_TO_ALL:
488 test = TEST_ORIGIN_TO_ALL_RECV;
489 break;
490
491 case TEST_ORIGIN_TO_ALL_RECV:
492 // Test 6 starts here
493 member_to_origin ();
494 break;
495
496 case TEST_MEMBER_REPLAY_OK:
497 // Test 9 starts here
498 GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id));
499 member_part ();
500 break;
501
502 default:
503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
504 "Invalid test #%d in origin_recv_message()\n", test);
505 GNUNET_assert (0);
506 }
507}
508
509
510static void
511origin_recv_message (void *cls,
512 const struct GNUNET_MULTICAST_MessageHeader *msg)
513{
514 struct OriginClosure *ocls = cls;
515 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
516 "Test #%u: origin_recv_message() %u/%u\n",
517 test, ocls->n + 1, ocls->msgs_expected);
518 if (++ocls->n != ocls->msgs_expected)
519 return;
520
521 // FIXME: check message content
522
523 switch (test)
524 {
525 case TEST_ORIGIN_TO_ALL:
526 // Prepare to execute test 5
527 test = TEST_ORIGIN_TO_ALL_RECV;
528 break;
529
530 case TEST_ORIGIN_TO_ALL_RECV:
531 // Test 6 starts here
532 member_to_origin ();
533 break;
534
535 default:
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 "Invalid test #%d in origin_recv_message()\n", test);
538 GNUNET_assert (0);
539 }
540}
541
542
543static void
544origin_to_all ()
545{
546 test = TEST_ORIGIN_TO_ALL;
547 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
548 "Test #%u: origin_to_all()\n", test);
549
550 struct TransmitClosure *tmit = &tmit_cls;
551 *tmit = (struct TransmitClosure) {};
552 tmit->data[0] = "ABC DEF";
553 tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1);
554 uint16_t i;
555 for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++)
556 tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
557 tmit->data[2] = "GHI JKL MNO";
558 tmit->data_delay[2] = 2;
559 tmit->data[3] = "PQR STUW XYZ";
560 tmit->data_count = 4;
561
562 origin_cls.n = member_cls.n = 0;
563 origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count;
564
565 tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1,
566 tmit_notify, tmit);
567}
568
569
570static void
571member_recv_join_decision (void *cls,
572 int is_admitted,
573 const struct GNUNET_PeerIdentity *peer,
574 uint16_t relay_count,
575 const struct GNUNET_PeerIdentity *relays,
576 const struct GNUNET_MessageHeader *join_msg)
577{
578 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
579 "Test #%u: member_recv_join_decision() - is_admitted: %d\n",
580 test, is_admitted);
581
582 GNUNET_assert (join_msg->size == join_resp->size);
583 GNUNET_assert (join_msg->type == join_resp->type);
584 GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size)));
585
586 switch (test)
587 {
588 case TEST_MEMBER_JOIN_REFUSE:
589 GNUNET_assert (0 == relay_count);
590 // Test 3 starts here
591 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
592 break;
593
594 case TEST_MEMBER_JOIN_ADMIT:
595 GNUNET_assert (1 == relay_count);
596 GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer)));
597 // Test 4 starts here
598 origin_to_all ();
599 break;
600
601 default:
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 "Invalid test #%d in member_recv_join_decision()\n", test);
604 GNUNET_assert (0);
605 }
606}
607
608/**
609 * Test: origin receives join request
610 */
611static void
612origin_recv_join_request (void *cls,
613 const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key,
614 const struct GNUNET_MessageHeader *join_msg,
615 struct GNUNET_MULTICAST_JoinHandle *jh)
616{
617 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
618 "Test #%u: origin_recv_join_request()\n", test);
619
620 GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key)));
621 GNUNET_assert (join_msg->size == join_req->size);
622 GNUNET_assert (join_msg->type == join_req->type);
623 GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size)));
624
625 char data[] = "here's the decision";
626 uint8_t data_size = strlen (data) + 1;
627 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
628 join_resp->size = htons (sizeof (join_resp) + data_size);
629 join_resp->type = htons (456);
630 GNUNET_memcpy (&join_resp[1], data, data_size);
631
632 switch (test)
633 {
634 case TEST_MEMBER_JOIN_REFUSE:
635 // Test 3 starts here
636 GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp);
637 break;
638
639 case TEST_MEMBER_JOIN_ADMIT:
640 // Test 3 is running
641 GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp);
642 break;
643
644 default:
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646 "Invalid test #%d in origin_recv_join_request()\n", test);
647 GNUNET_assert (0);
648 break;
649 }
650}
651
652/**
653 * Test: member joins multicast group
654 */
655static void
656member_join (int t)
657{
658 test = t;
659 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
660 "Test #%u: member_join()\n", test);
661
662 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
663 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
664
665 if (NULL != join_req)
666 GNUNET_free (join_req);
667
668 char data[] = "let me in!";
669 uint8_t data_size = strlen (data) + 1;
670 join_req = GNUNET_malloc (sizeof (join_req) + data_size);
671 join_req->size = htons (sizeof (join_req) + data_size);
672 join_req->type = htons (123);
673 GNUNET_memcpy (&join_req[1], data, data_size);
674
675 member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key,
676 &this_peer, 1, &this_peer, join_req,
677 member_recv_join_request,
678 member_recv_join_decision,
679 member_recv_replay_frag,
680 member_recv_replay_msg,
681 member_recv_message,
682 &member_cls);
683}
684
685/**
686 * Test: Start a multicast group as origin
687 */
688static void
689origin_start ()
690{
691 test = TEST_ORIGIN_START;
692 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
693 "Test #%u: origin_start()\n", test);
694
695 group_key = GNUNET_CRYPTO_eddsa_key_create ();
696 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
697
698 origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0,
699 origin_recv_join_request,
700 origin_recv_replay_frag,
701 origin_recv_replay_msg,
702 origin_recv_request,
703 origin_recv_message,
704 &origin_cls);
705 // Test 2 starts here
706 member_join (TEST_MEMBER_JOIN_REFUSE);
707}
708
709
710/**
711 * Main function of the test, run from scheduler.
712 *
713 * @param cls NULL
714 * @param cfg configuration we use (also to connect to Multicast service)
715 * @param peer handle to access more of the peer (not used)
716 */
717static void
718#if DEBUG_TEST_MULTICAST
719run (void *cls,
720 char *const *args,
721 const char *cfgfile,
722 const struct GNUNET_CONFIGURATION_Handle *c)
723#else
724run (void *cls,
725 const struct GNUNET_CONFIGURATION_Handle *c,
726 struct GNUNET_TESTING_Peer *peer)
727#endif
728{
729 cfg = c;
730 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
731 &end_badly, NULL);
732 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
733
734 // Test 1 starts here
735 origin_start ();
736}
737
738
739int
740main (int argc, char *argv[])
741{
742 res = 1;
743#if DEBUG_TEST_MULTICAST
744 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
745 GNUNET_GETOPT_OPTION_END
746 };
747 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast",
748 "test-multicast [options]",
749 opts, &run, NULL))
750 return 1;
751#else
752 if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL))
753 return 1;
754#endif
755 return res;
756}
757
758/* end of test_multicast.c */
diff --git a/src/multicast/test_multicast.conf b/src/multicast/test_multicast.conf
deleted file mode 100644
index b2f1a764b..000000000
--- a/src/multicast/test_multicast.conf
+++ /dev/null
@@ -1,56 +0,0 @@
1[testbed]
2HOSTNAME = localhost
3
4[arm]
5GLOBAL_POSTFIX=-L ERROR
6
7[multicast]
8#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
9#PREFIX = valgrind --leak-check=full
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
11
12[vpn]
13START_ON_DEMAND = NO
14
15[peerinfo]
16# Do not use shipped gnunet HELLOs
17USE_INCLUDED_HELLOS = NO
18
19# Option to disable all disk IO; only useful for testbed runs
20# (large-scale experiments); disables persistence of HELLOs!
21NO_IO = YES
22
23[hostlist]
24IMMEDIATE_START = NO
25START_ON_DEMAND = NO
26
27[nat]
28ENABLE_UPNP = NO
29
30[fs]
31IMMEDIATE_START = NO
32START_ON_DEMAND = NO
33
34[vpn]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[revocation]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[gns]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[namestore]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namecache]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[topology]
55IMMEDIATE_START = NO
56START_ON_DEMAND = NO
diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c
deleted file mode 100644
index ea996026c..000000000
--- a/src/multicast/test_multicast_2peers.c
+++ /dev/null
@@ -1,520 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 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/test_multicast_2peers.c
23 * @brief Tests for the Multicast API with two peers doing the ping
24 * pong test.
25 * @author xrs
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_common.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_testbed_service.h"
35#include "gnunet_multicast_service.h"
36
37#define NUM_PEERS 2
38
39static struct GNUNET_TESTBED_Operation *op0;
40static struct GNUNET_TESTBED_Operation *op1;
41static struct GNUNET_TESTBED_Operation *pi_op0;
42static struct GNUNET_TESTBED_Operation *pi_op1;
43
44static struct GNUNET_TESTBED_Peer **peers;
45const struct GNUNET_PeerIdentity *peer_id[2];
46
47static struct GNUNET_SCHEDULER_Task *timeout_tid;
48
49static struct GNUNET_MULTICAST_Origin *origin;
50static struct GNUNET_MULTICAST_Member *member;
51
52struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
53struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
54
55struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
56struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
57
58/**
59 * Global result for testcase.
60 */
61static int result;
62
63
64/**
65 * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
66 * Cleans up.
67 */
68static void
69shutdown_task (void *cls)
70{
71 if (NULL != op0)
72 {
73 GNUNET_TESTBED_operation_done (op0);
74 op0 = NULL;
75 }
76 if (NULL != op1)
77 {
78 GNUNET_TESTBED_operation_done (op1);
79 op1 = NULL;
80 }
81 if (NULL != pi_op0)
82 {
83 GNUNET_TESTBED_operation_done (pi_op0);
84 pi_op0 = NULL;
85 }
86 if (NULL != pi_op1)
87 {
88 GNUNET_TESTBED_operation_done (pi_op1);
89 pi_op1 = NULL;
90 }
91 if (NULL != timeout_tid)
92 {
93 GNUNET_SCHEDULER_cancel (timeout_tid);
94 timeout_tid = NULL;
95 }
96}
97
98
99static void
100timeout_task (void *cls)
101{
102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103 "Timeout!\n");
104 result = GNUNET_SYSERR;
105 GNUNET_SCHEDULER_shutdown ();
106}
107
108
109static void
110member_join_request (void *cls,
111 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
112 const struct GNUNET_MessageHeader *join_msg,
113 struct GNUNET_MULTICAST_JoinHandle *jh)
114{
115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
116 "Member sent a join request.\n");
117
118}
119
120
121static int
122notify (void *cls,
123 size_t *data_size,
124 void *data)
125{
126
127 char text[] = "ping";
128 *data_size = strlen(text)+1;
129 GNUNET_memcpy(data, text, *data_size);
130
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132 "Member sents message to origin: %s\n", text);
133
134 return GNUNET_YES;
135}
136
137
138static void
139member_join_decision (void *cls,
140 int is_admitted,
141 const struct GNUNET_PeerIdentity *peer,
142 uint16_t relay_count,
143 const struct GNUNET_PeerIdentity *relays,
144 const struct GNUNET_MessageHeader *join_msg)
145{
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Member received a decision from origin: %s\n",
148 (GNUNET_YES == is_admitted)
149 ? "accepted"
150 : "rejected");
151
152 if (GNUNET_YES == is_admitted)
153 {
154 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
155
156 // FIXME: move to MQ-style API!
157 req = GNUNET_MULTICAST_member_to_origin (member,
158 0,
159 &notify,
160 NULL);
161 }
162}
163
164
165static void
166member_message (void *cls,
167 const struct GNUNET_MULTICAST_MessageHeader *msg)
168{
169 if (0 != strncmp ("pong", (char *)&msg[1], 4))
170 {
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n");
172 result = GNUNET_SYSERR;
173 GNUNET_SCHEDULER_shutdown ();
174 }
175
176 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
177 "member receives: %s\n", (char *)&msg[1]);
178
179 // Testcase ends here.
180 result = GNUNET_YES;
181 GNUNET_SCHEDULER_shutdown ();
182}
183
184
185static void
186origin_join_request (void *cls,
187 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
188 const struct GNUNET_MessageHeader *join_msg,
189 struct GNUNET_MULTICAST_JoinHandle *jh)
190{
191 struct GNUNET_MessageHeader *join_resp;
192
193 uint8_t data_size = ntohs (join_msg->size);
194
195 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
196 "origin got a join request...\n");
197 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
198 "origin receives: '%s'\n", (char *)&join_msg[1]);
199
200 const char data[] = "Come in!";
201 data_size = strlen (data) + 1;
202 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
203 join_resp->size = htons (sizeof (join_resp) + data_size);
204 join_resp->type = htons (123);
205 GNUNET_memcpy (&join_resp[1], data, data_size);
206
207 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208 "origin sends: '%s'\n", data);
209
210 GNUNET_MULTICAST_join_decision (jh,
211 GNUNET_YES,
212 0,
213 NULL,
214 join_resp);
215 GNUNET_free (join_resp);
216 result = GNUNET_OK;
217}
218
219
220int
221origin_notify (void *cls,
222 size_t *data_size,
223 void *data)
224{
225 char text[] = "pong";
226
227 *data_size = strlen(text)+1;
228 GNUNET_memcpy (data,
229 text,
230 *data_size);
231
232 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
233
234 return GNUNET_YES;
235}
236
237
238static void
239origin_request (void *cls,
240 const struct GNUNET_MULTICAST_RequestHeader *req)
241{
242 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
243
244 if (0 != strncmp ("ping", (char *)&req[1], 4))
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
246
247 GNUNET_MULTICAST_origin_to_all (origin,
248 0,
249 0,
250 origin_notify,
251 NULL);
252}
253
254
255static void
256origin_message (void *cls,
257 const struct GNUNET_MULTICAST_MessageHeader *msg)
258{
259 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
260}
261
262
263static void
264service_connect1 (void *cls,
265 struct GNUNET_TESTBED_Operation *op,
266 void *ca_result,
267 const char *emsg)
268{
269 member = ca_result;
270
271 if (NULL == member)
272 {
273 result = GNUNET_SYSERR;
274 GNUNET_SCHEDULER_shutdown ();
275 }
276 else
277 {
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
279 }
280}
281
282
283static void
284multicast_da1 (void *cls,
285 void * op_result)
286{
287 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
288 "Member parting from multicast group\n");
289
290 GNUNET_MULTICAST_member_part (member, NULL, NULL);
291}
292
293
294static void *
295multicast_ca1 (void *cls,
296 const struct GNUNET_CONFIGURATION_Handle *cfg)
297{
298 struct GNUNET_MessageHeader *join_msg;
299 void *ret;
300
301 // Get members keys
302 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
303 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
304
305 char data[] = "Hi, can I enter?";
306 uint8_t data_size = strlen (data) + 1;
307 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
308 join_msg->size = htons (sizeof (join_msg) + data_size);
309 join_msg->type = htons (123);
310 GNUNET_memcpy (&join_msg[1], data, data_size);
311
312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
313 "Members tries to join multicast group\n");
314
315 ret = GNUNET_MULTICAST_member_join (cfg,
316 &group_pub_key,
317 member_key,
318 peer_id[0],
319 0,
320 NULL,
321 join_msg, /* join message */
322 member_join_request,
323 member_join_decision,
324 NULL, /* no test for member_replay_frag */
325 NULL, /* no test for member_replay_msg */
326 member_message,
327 NULL);
328 GNUNET_free (join_msg);
329 return ret;
330}
331
332
333static void
334peer_information_cb (void *cls,
335 struct GNUNET_TESTBED_Operation *op,
336 const struct GNUNET_TESTBED_PeerInformation *pinfo,
337 const char *emsg)
338{
339 int i = (int) (long) cls;
340
341 if (NULL == pinfo)
342 {
343 result = GNUNET_SYSERR;
344 GNUNET_SCHEDULER_shutdown ();
345 }
346
347 peer_id[i] = pinfo->result.id;
348
349 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
350 "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
351
352 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
353 "Create member peer\n");
354
355 if (0 == i)
356 {
357 /* connect to multicast service of member */
358 op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
359 peers[1], /* The peer whose service to connect to */
360 "multicast", /* The name of the service */
361 service_connect1, /* callback to call after a handle to service
362 is opened */
363 NULL, /* closure for the above callback */
364 multicast_ca1, /* callback to call with peer's configuration;
365 this should open the needed service connection */
366 multicast_da1, /* callback to be called when closing the
367 opened service connection */
368 NULL); /* closure for the above two callbacks */
369 }
370}
371
372
373/**
374 * Test logic of peer "0" being origin starts here.
375 *
376 * @param cls closure, for the example: NULL
377 * @param op should be equal to "dht_op"
378 * @param ca_result result of the connect operation, the
379 * connection to the DHT service
380 * @param emsg error message, if testbed somehow failed to
381 * connect to the DHT.
382 */
383static void
384service_connect0 (void *cls,
385 struct GNUNET_TESTBED_Operation *op,
386 void *ca_result,
387 const char *emsg)
388{
389 origin = ca_result;
390
391 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
392 "Connected to multicast service of origin\n");
393
394 // Get GNUnet identity of origin
395 pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
396 GNUNET_TESTBED_PIT_IDENTITY,
397 peer_information_cb,
398 (void *) 0);
399 // Get GNUnet identity of member
400 pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
401 GNUNET_TESTBED_PIT_IDENTITY,
402 peer_information_cb,
403 (void *) 1);
404
405 /* Connection to service successful. Here we'd usually do something with
406 * the service. */
407 result = GNUNET_OK;
408 //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
409}
410
411
412
413/**
414 * Function run when service multicast has started and is providing us
415 * with a configuration file.
416 */
417static void *
418multicast_ca0 (void *cls,
419 const struct GNUNET_CONFIGURATION_Handle *cfg)
420{
421 group_key = GNUNET_CRYPTO_eddsa_key_create ();
422 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
423
424 return GNUNET_MULTICAST_origin_start (cfg,
425 group_key,
426 0,
427 origin_join_request,
428 NULL, /* no test for origin_replay_frag */
429 NULL, /* no test for origin_replay_msg */
430 origin_request,
431 origin_message,
432 NULL);
433}
434
435static void
436multicast_da0 (void *cls,
437 void *op_result)
438{
439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440 "Origin closes multicast group\n");
441
442 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
443}
444
445
446/**
447 * Main function inovked from TESTBED once all of the
448 * peers are up and running. This one then connects
449 * just to the multicast service of peer 0 and 1.
450 * Peer 0 is going to be origin.
451 * Peer 1 is going to be one member.
452 * Origin will start a multicast group and the member will try to join it.
453 * After that we execute some multicast test.
454 *
455 * @param cls closure
456 * @param h the run handle
457 * @param peers started peers for the test
458 * @param num_peers size of the 'peers' array
459 * @param links_succeeded number of links between peers that were created
460 * @param links_failed number of links testbed was unable to establish
461 */
462static void
463testbed_master (void *cls,
464 struct GNUNET_TESTBED_RunHandle *h,
465 unsigned int num_peers,
466 struct GNUNET_TESTBED_Peer **p,
467 unsigned int links_succeeded,
468 unsigned int links_failed)
469{
470 /* Testbed is ready with peers running and connected in a pre-defined overlay
471 topology (FIXME) */
472 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
473 "Connected to testbed_master()\n");
474
475 peers = p;
476
477 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
478 "Create origin peer\n");
479 op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
480 peers[0], /* The peer whose service to connect to */
481 "multicast", /* The name of the service */
482 service_connect0, /* callback to call after a handle to service
483 is opened */
484 NULL, /* closure for the above callback */
485 multicast_ca0, /* callback to call with peer's configuration;
486 this should open the needed service connection */
487 multicast_da0, /* callback to be called when closing the
488 opened service connection */
489 NULL); /* closure for the above two callbacks */
490
491 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
492
493 /* Schedule the shutdown task with a delay of a few Seconds */
494 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
495 &timeout_task, NULL);
496}
497
498
499int
500main (int argc, char *argv[])
501{
502 int ret;
503
504 result = GNUNET_SYSERR;
505 ret = GNUNET_TESTBED_test_run
506 ("test-multicast-2peers", /* test case name */
507 "test_multicast.conf", /* template configuration */
508 NUM_PEERS, /* number of peers to start */
509 0LL, /* Event mask - set to 0 for no event notifications */
510 NULL, /* Controller event callback */
511 NULL, /* Closure for controller event callback */
512 testbed_master, /* continuation callback to be called when testbed setup is complete */
513 NULL); /* Closure for the test_master callback */
514 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
515 return 1;
516 return 0;
517}
518
519
520/* end of test_multicast_2peers.c */
diff --git a/src/multicast/test_multicast_line.conf b/src/multicast/test_multicast_line.conf
deleted file mode 100644
index c1ce7c63f..000000000
--- a/src/multicast/test_multicast_line.conf
+++ /dev/null
@@ -1,63 +0,0 @@
1[testbed]
2HOSTNAME = localhost
3OVERLAY_TOPOLOGY = LINE
4
5[arm]
6GLOBAL_POSTFIX=-L ERROR
7
8[multicast]
9#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
10#PREFIX = valgrind --leak-check=full
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
12
13[vpn]
14START_ON_DEMAND = NO
15
16[peerinfo]
17# Do not use shipped gnunet HELLOs
18USE_INCLUDED_HELLOS = NO
19
20# Option to disable all disk IO; only useful for testbed runs
21# (large-scale experiments); disables persistence of HELLOs!
22NO_IO = YES
23
24[cadet]
25ID_ANNOUNCE_TIME = 5 s
26
27[hostlist]
28IMMEDIATE_START = NO
29START_ON_DEMAND = NO
30
31[nat]
32ENABLE_UPNP = NO
33
34[fs]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[vpn]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[revocation]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[gns]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namestore]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[namecache]
55IMMEDIATE_START = NO
56START_ON_DEMAND = NO
57
58[topology]
59IMMEDIATE_START = NO
60START_ON_DEMAND = NO
61
62[nse]
63WORKBITS = 0
diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c
deleted file mode 100644
index 9b44e05db..000000000
--- a/src/multicast/test_multicast_multipeer.c
+++ /dev/null
@@ -1,643 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 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/test_multicast_multipeers.c
23 * @brief Tests for the Multicast API with multiple peers.
24 * @author xrs
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_common.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_testbed_service.h"
34#include "gnunet_multicast_service.h"
35
36#define PEERS_REQUESTED 12
37
38struct MulticastPeerContext
39{
40 int peer; /* peer number */
41 struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
42 const struct GNUNET_PeerIdentity *id;
43 struct GNUNET_TESTBED_Operation *op; /* not yet in use */
44 struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */
45 int test_ok;
46};
47
48enum pingpong
49{
50 PING = 1,
51 PONG = 2
52};
53
54struct pingpong_msg
55{
56 int peer;
57 enum pingpong msg;
58};
59
60static void service_connect (void *cls,
61 struct GNUNET_TESTBED_Operation *op,
62 void *ca_result,
63 const char *emsg);
64
65static struct MulticastPeerContext **multicast_peers;
66static struct GNUNET_TESTBED_Peer **peers;
67
68static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED];
69static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED];
70
71static struct GNUNET_MULTICAST_Origin *origin;
72static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */
73
74static struct GNUNET_SCHEDULER_Task *timeout_tid;
75
76static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
77static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
78static struct GNUNET_HashCode group_pub_key_hash;
79
80/**
81 * Global result for testcase.
82 */
83static int result;
84
85/**
86 * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
87 * Cleans up.
88 */
89static void
90shutdown_task (void *cls)
91{
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "shutdown_task!\n");
94 for (int i=0;i<PEERS_REQUESTED;i++)
95 {
96 if (NULL != op[i])
97 {
98 GNUNET_TESTBED_operation_done(op[i]);
99 op[i] = NULL;
100 }
101 if (NULL != pi_op[i])
102 {
103 GNUNET_TESTBED_operation_done (pi_op[i]);
104 pi_op[i] = NULL;
105 }
106 }
107
108 if (NULL != multicast_peers)
109 {
110 for (int i=0; i < PEERS_REQUESTED; i++)
111 {
112 GNUNET_free_non_null (multicast_peers[i]->key);
113 GNUNET_free (multicast_peers[i]);
114 multicast_peers[i] = NULL;
115 }
116 GNUNET_free (multicast_peers);
117 multicast_peers = NULL;
118 }
119
120 if (NULL != timeout_tid)
121 {
122 GNUNET_SCHEDULER_cancel (timeout_tid);
123 timeout_tid = NULL;
124 }
125}
126
127
128static void
129timeout_task (void *cls)
130{
131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
132 "Timeout!\n");
133 result = GNUNET_SYSERR;
134 GNUNET_SCHEDULER_shutdown ();
135}
136
137
138static void
139member_join_request (void *cls,
140 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
141 const struct GNUNET_MessageHeader *join_msg,
142 struct GNUNET_MULTICAST_JoinHandle *jh)
143{
144 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
145 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
146 "Peer #%u (%s) sent a join request.\n",
147 mc_peer->peer,
148 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
149}
150
151
152static int
153notify (void *cls,
154 size_t *data_size,
155 void *data)
156{
157 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
158
159 struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
160 pp_msg->peer = mc_peer->peer;
161 pp_msg->msg = PING;
162
163 *data_size = sizeof (struct pingpong_msg);
164 GNUNET_memcpy(data, pp_msg, *data_size);
165 GNUNET_free (pp_msg);
166
167 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
168 "Peer #%u sents ping to origin\n", mc_peer->peer);
169
170 return GNUNET_YES;
171}
172
173
174static void
175member_join_decision (void *cls,
176 int is_admitted,
177 const struct GNUNET_PeerIdentity *peer,
178 uint16_t relay_count,
179 const struct GNUNET_PeerIdentity *relays,
180 const struct GNUNET_MessageHeader *join_msg)
181{
182 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
183
184 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
185 "Peer #%u (%s) received a decision from origin: %s\n",
186 mc_peer->peer,
187 GNUNET_i2s (multicast_peers[mc_peer->peer]->id),
188 (GNUNET_YES == is_admitted)?"accepted":"rejected");
189
190 if (GNUNET_YES == is_admitted)
191 {
192 GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer],
193 0,
194 notify,
195 cls);
196
197 }
198}
199
200
201static void
202member_replay_frag ()
203{
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "member replay frag...\n");
206}
207
208
209static void
210member_replay_msg ()
211{
212 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
213 "member replay msg...\n");
214}
215
216
217static void
218origin_disconnected_cb (void *cls)
219{
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221 "Origin disconnected. Shutting down.\n");
222 result = GNUNET_YES;
223 GNUNET_SCHEDULER_shutdown ();
224}
225
226
227static void
228member_disconnected_cb (void *cls)
229{
230 for (int i = 1; i < PEERS_REQUESTED; ++i)
231 if (GNUNET_NO == multicast_peers[i]->test_ok)
232 return;
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "All member disconnected. Stopping origin.\n");
235 GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls);
236}
237
238
239static void
240member_message (void *cls,
241 const struct GNUNET_MULTICAST_MessageHeader *msg)
242{
243 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
244 struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]);
245
246 if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer)
247 {
248 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
249 "peer #%i (%s) receives a pong\n",
250 mc_peer->peer,
251 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
252 mc_peer->test_ok = GNUNET_OK;
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254 "peer #%u (%s) parting from multicast group\n",
255 mc_peer->peer,
256 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
257
258 GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls);
259 }
260}
261
262
263static void
264origin_join_request (void *cls,
265 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
266 const struct GNUNET_MessageHeader *join_msg,
267 struct GNUNET_MULTICAST_JoinHandle *jh)
268{
269 struct GNUNET_MessageHeader *join_resp;
270
271 uint8_t data_size = ntohs (join_msg->size);
272
273 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 "origin got a join request...\n");
275 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
276 "origin receives: '%s'\n", (char *)&join_msg[1]);
277
278 char data[] = "Come in!";
279 data_size = strlen (data) + 1;
280 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
281 join_resp->size = htons (sizeof (join_resp) + data_size);
282 join_resp->type = htons (123);
283 GNUNET_memcpy (&join_resp[1], data, data_size);
284
285 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
286 "origin sends: '%s'\n", data);
287
288 GNUNET_MULTICAST_join_decision (jh,
289 GNUNET_YES,
290 0,
291 NULL,
292 join_resp);
293
294 result = GNUNET_OK;
295}
296
297
298static void
299origin_replay_frag (void *cls,
300 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
301 uint64_t fragment_id,
302 uint64_t flags,
303 struct GNUNET_MULTICAST_ReplayHandle *rh)
304{
305 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
306}
307
308
309static void
310origin_replay_msg (void *cls,
311 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
312 uint64_t message_id,
313 uint64_t fragment_offset,
314 uint64_t flags,
315 struct GNUNET_MULTICAST_ReplayHandle *rh)
316{
317
318 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
319}
320
321
322static int
323origin_notify (void *cls,
324 size_t *data_size,
325 void *data)
326{
327 struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls;
328 struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
329
330 pp_msg->peer = rcv_pp_msg->peer;
331 pp_msg->msg = PONG;
332 *data_size = sizeof (struct pingpong_msg);
333 GNUNET_memcpy(data, pp_msg, *data_size);
334 GNUNET_free (pp_msg);
335
336 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n");
337
338 return GNUNET_YES;
339}
340
341
342static void
343origin_request (void *cls,
344 const struct GNUNET_MULTICAST_RequestHeader *req)
345{
346 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n");
347
348 req++;
349 struct pingpong_msg *pp_msg = (struct pingpong_msg *) req;
350
351 if (1 != pp_msg->msg) {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
353 }
354
355 GNUNET_MULTICAST_origin_to_all (origin,
356 0,
357 0,
358 origin_notify,
359 pp_msg);
360}
361
362
363static void
364origin_message (void *cls,
365 const struct GNUNET_MULTICAST_MessageHeader *msg)
366{
367 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
368}
369
370
371static void
372multicast_disconnect (void *cls,
373 void *op_result)
374{
375
376}
377
378
379static void *
380multicast_connect (void *cls,
381 const struct GNUNET_CONFIGURATION_Handle *cfg)
382{
383 struct MulticastPeerContext *multicast_peer = cls;
384 struct GNUNET_MessageHeader *join_msg;
385 char data[64];
386
387 if (0 == multicast_peer->peer)
388 {
389 group_key = GNUNET_CRYPTO_eddsa_key_create ();
390 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
391
392 GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash);
393 origin = GNUNET_MULTICAST_origin_start (cfg,
394 group_key,
395 0,
396 origin_join_request,
397 origin_replay_frag,
398 origin_replay_msg,
399 origin_request,
400 origin_message,
401 cls);
402 if (NULL == origin)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
405 "Peer #%u could not create a multicast group",
406 multicast_peer->peer);
407 return NULL;
408 }
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer #%u connected as origin to group %s\n",
411 multicast_peer->peer,
412 GNUNET_h2s (&group_pub_key_hash));
413 return origin;
414 }
415 else
416 {
417 multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create ();
418
419 sprintf(data, "Hi, I am peer #%u (%s). Can I enter?",
420 multicast_peer->peer,
421 GNUNET_i2s (multicast_peers[multicast_peer->peer]->id));
422 uint8_t data_size = strlen (data) + 1;
423 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
424 join_msg->size = htons (sizeof (join_msg) + data_size);
425 join_msg->type = htons (123);
426 GNUNET_memcpy (&join_msg[1], data, data_size);
427
428 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
429 "Peer #%u (%s) tries to join multicast group %s\n",
430 multicast_peer->peer,
431 GNUNET_i2s (multicast_peers[multicast_peer->peer]->id),
432 GNUNET_h2s (&group_pub_key_hash));
433
434 members[multicast_peer->peer] =
435 GNUNET_MULTICAST_member_join (cfg,
436 &group_pub_key,
437 multicast_peer->key,
438 multicast_peers[0]->id,
439 0,
440 NULL,
441 join_msg, /* join message */
442 member_join_request,
443 member_join_decision,
444 member_replay_frag,
445 member_replay_msg,
446 member_message,
447 cls);
448 return members[multicast_peer->peer];
449 }
450}
451
452
453static void
454peer_information_cb (void *cls,
455 struct GNUNET_TESTBED_Operation *operation,
456 const struct GNUNET_TESTBED_PeerInformation *pinfo,
457 const char *emsg)
458{
459 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
460
461 if (NULL == pinfo) {
462 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n");
463 result = GNUNET_SYSERR;
464 GNUNET_SCHEDULER_shutdown ();
465 }
466
467 multicast_peers[mc_peer->peer]->id = pinfo->result.id;
468
469 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
470 "Got peer information of %s (%s)\n",
471 (0 == mc_peer->peer)? "origin" : "member",
472 GNUNET_i2s (pinfo->result.id));
473
474 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
475 "Create peer #%u (%s)\n",
476 mc_peer->peer,
477 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
478
479 if (0 != mc_peer->peer)
480 {
481 /* connect to multicast service of members */
482 op[mc_peer->peer] =
483 GNUNET_TESTBED_service_connect (/* Closure for operation */
484 NULL,
485 /* The peer whose service to connect to */
486 peers[mc_peer->peer],
487 /* The name of the service */
488 "multicast",
489 /* called after a handle to service is opened */
490 service_connect,
491 /* closure for the above callback */
492 cls,
493 /* called when opening the service connection */
494 multicast_connect,
495 /* called when closing the service connection */
496 multicast_disconnect,
497 /* closure for the above two callbacks */
498 cls);
499 }
500}
501
502
503static void
504service_connect (void *cls,
505 struct GNUNET_TESTBED_Operation *op,
506 void *ca_result,
507 const char *emsg)
508{
509 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
510
511 if (NULL == ca_result)
512 {
513 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514 "Connection adapter not created for peer #%u (%s)\n",
515 mc_peer->peer,
516 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
517
518 result = GNUNET_SYSERR;
519 GNUNET_SCHEDULER_shutdown();
520 }
521
522 if (0 == mc_peer->peer)
523 {
524 // Get GNUnet identity of members
525 for (int i = 0; i<PEERS_REQUESTED; i++)
526 {
527 pi_op[i] = GNUNET_TESTBED_peer_get_information (peers[i],
528 GNUNET_TESTBED_PIT_IDENTITY,
529 peer_information_cb,
530 multicast_peers[i]);
531 }
532 }
533}
534
535
536
537/**
538 * Main function inovked from TESTBED once all of the
539 * peers are up and running. This one then connects
540 * just to the multicast service of peer 0 and 1.
541 * Peer 0 is going to be origin.
542 * Peer 1 is going to be one member.
543 * Origin will start a multicast group and the member will try to join it.
544 * After that we execute some multicast test.
545 *
546 * @param cls closure
547 * @param h the run handle
548 * @param peers started peers for the test
549 * @param PEERS_REQUESTED size of the 'peers' array
550 * @param links_succeeded number of links between peers that were created
551 * @param links_failed number of links testbed was unable to establish
552 */
553static void
554testbed_master (void *cls,
555 struct GNUNET_TESTBED_RunHandle *h,
556 unsigned int num_peers,
557 struct GNUNET_TESTBED_Peer **p,
558 unsigned int links_succeeded,
559 unsigned int links_failed)
560{
561 /* Testbed is ready with peers running and connected in a pre-defined overlay
562 topology (FIXME) */
563 peers = p;
564 multicast_peers = GNUNET_new_array (PEERS_REQUESTED, struct MulticastPeerContext*);
565
566 // Create test contexts for members
567 for (int i = 0; i<PEERS_REQUESTED; i++)
568 {
569 multicast_peers[i] = GNUNET_new (struct MulticastPeerContext);
570 multicast_peers[i]->peer = i;
571 multicast_peers[i]->test_ok = GNUNET_NO;
572 }
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
574 "Create origin peer\n");
575 op[0] =
576 GNUNET_TESTBED_service_connect (/* Closure for operation */
577 NULL,
578 /* The peer whose service to connect to */
579 peers[0],
580 /* The name of the service */
581 "multicast",
582 /* called after a handle to service is opened */
583 service_connect,
584 /* closure for the above callback */
585 multicast_peers[0],
586 /* called when opening the service connection */
587 multicast_connect,
588 /* called when closing the service connection */
589 multicast_disconnect,
590 /* closure for the above two callbacks */
591 multicast_peers[0]);
592 /* Schedule a new task on shutdown */
593 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
594 /* Schedule the shutdown task with a delay of a few Seconds */
595 timeout_tid =
596 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
597 (GNUNET_TIME_UNIT_SECONDS, 400),
598 &timeout_task,
599 NULL);
600}
601
602
603int
604main (int argc, char *argv[])
605{
606 int ret;
607 char const *config_file;
608
609 if (strstr (argv[0], "_line") != NULL)
610 {
611 config_file = "test_multicast_line.conf";
612 }
613 else if (strstr(argv[0], "_star") != NULL)
614 {
615 config_file = "test_multicast_star.conf";
616 }
617 else
618 {
619 config_file = "test_multicast_star.conf";
620 }
621
622 result = GNUNET_SYSERR;
623 ret =
624 GNUNET_TESTBED_test_run ("test-multicast-multipeer",
625 config_file,
626 /* number of peers to start */
627 PEERS_REQUESTED,
628 /* Event mask - set to 0 for no event notifications */
629 0LL,
630 /* Controller event callback */
631 NULL,
632 /* Closure for controller event callback */
633 NULL,
634 /* called when testbed setup is complete */
635 testbed_master,
636 /* Closure for the test_master callback */
637 NULL);
638 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
639 return 1;
640 return 0;
641}
642
643/* end of test_multicast_multipeer.c */
diff --git a/src/multicast/test_multicast_star.conf b/src/multicast/test_multicast_star.conf
deleted file mode 100644
index 516c0e302..000000000
--- a/src/multicast/test_multicast_star.conf
+++ /dev/null
@@ -1,64 +0,0 @@
1[testbed]
2HOSTNAME = localhost
3OVERLAY_TOPOLOGY = STAR
4
5[arm]
6GLOBAL_POSTFIX=-L ERROR
7
8[multicast]
9#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
10#PREFIX = valgrind --leak-check=full
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
12
13[vpn]
14START_ON_DEMAND = NO
15
16[peerinfo]
17# Do not use shipped gnunet HELLOs
18USE_INCLUDED_HELLOS = NO
19
20# Option to disable all disk IO; only useful for testbed runs
21# (large-scale experiments); disables persistence of HELLOs!
22NO_IO = YES
23
24[cadet]
25ID_ANNOUNCE_TIME = 5 s
26
27[hostlist]
28IMMEDIATE_START = NO
29START_ON_DEMAND = NO
30
31[nat]
32ENABLE_UPNP = NO
33
34[fs]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[vpn]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[revocation]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[gns]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namestore]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[namecache]
55IMMEDIATE_START = NO
56START_ON_DEMAND = NO
57
58[topology]
59IMMEDIATE_START = NO
60START_ON_DEMAND = NO
61
62[nse]
63WORKBITS = 0
64