2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU 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.
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.
17 * @file multicast/test_multicast.c
18 * @brief Tests for the Multicast API.
19 * @author Gabor X Toth
25 #include "gnunet_crypto_lib.h"
26 #include "gnunet_common.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_testing_lib.h"
29 #include "gnunet_multicast_service.h"
31 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34 * Return value from 'main'.
39 * Handle for task for timeout termination.
41 static struct GNUNET_SCHEDULER_Task * end_badly_task;
43 static const struct GNUNET_CONFIGURATION_Handle *cfg;
45 struct GNUNET_PeerIdentity this_peer;
47 struct GNUNET_MULTICAST_Origin *origin;
48 struct GNUNET_MULTICAST_Member *member;
50 struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
51 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
53 struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
54 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
56 struct TransmitClosure {
57 struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit;
58 struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit;
60 uint8_t data_delay[16];
66 struct OriginClosure {
67 uint8_t msgs_expected;
71 struct MemberClosure {
72 uint8_t msgs_expected;
76 struct GNUNET_MessageHeader *join_req, *join_resp;
81 TEST_ORIGIN_START = 1,
82 TEST_MEMBER_JOIN_REFUSE = 2,
83 TEST_MEMBER_JOIN_ADMIT = 3,
84 TEST_ORIGIN_TO_ALL = 4,
85 TEST_ORIGIN_TO_ALL_RECV = 5,
86 TEST_MEMBER_TO_ORIGIN = 6,
87 TEST_MEMBER_REPLAY_ERROR = 7,
88 TEST_MEMBER_REPLAY_OK = 8,
90 TEST_ORIGIN_STOP = 10,
93 uint64_t replay_fragment_id;
94 uint64_t replay_flags;
101 * Clean up all resources used.
108 GNUNET_MULTICAST_member_part (member, NULL, NULL);
113 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
120 * Terminate the test case (failure).
125 end_badly (void *cls)
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
134 * Terminate the test case (success).
139 end_normally (void *cls)
143 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n");
148 * Finish the test case (successfully).
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
155 if (end_badly_task != NULL)
157 GNUNET_SCHEDULER_cancel (end_badly_task);
158 end_badly_task = NULL;
160 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
161 &end_normally, NULL);
166 tmit_resume (void *cls)
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
169 struct TransmitClosure *tmit = cls;
170 if (NULL != tmit->orig_tmit)
171 GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit);
172 else if (NULL != tmit->mem_tmit)
173 GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit);
178 tmit_notify (void *cls, size_t *data_size, void *data)
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181 "Test #%u: origin_tmit_notify()\n", test);
182 struct TransmitClosure *tmit = cls;
184 if (0 == tmit->data_count)
190 uint16_t size = strlen (tmit->data[tmit->n]);
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n",
193 (unsigned int) *data_size,
197 if (*data_size < size)
201 return GNUNET_SYSERR;
204 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
207 tmit->paused = GNUNET_YES;
208 GNUNET_SCHEDULER_add_delayed (
209 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
210 tmit->data_delay[tmit->n]),
215 tmit->paused = GNUNET_NO;
218 GNUNET_memcpy (data, tmit->data[tmit->n], size);
220 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
225 member_recv_join_request (void *cls,
226 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
227 const struct GNUNET_MessageHeader *join_msg,
228 struct GNUNET_MULTICAST_JoinHandle *jh)
230 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
231 "Test #%u: member_recv_join_request()\n", test);
236 origin_stopped (void *cls)
238 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
239 "Test #%u: origin_stopped()\n", test);
245 schedule_origin_stop (void *cls)
247 test = TEST_ORIGIN_STOP;
248 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
249 "Test #%u: origin_stop()\n", test);
250 GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL);
256 member_parted (void *cls)
258 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259 "Test #%u: member_parted()\n", test);
264 case TEST_MEMBER_JOIN_REFUSE:
265 // Test 3 starts here
266 member_join (TEST_MEMBER_JOIN_ADMIT);
269 case TEST_MEMBER_PART:
270 GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL);
274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
275 "Invalid test #%d in member_parted()\n", test);
282 schedule_member_part (void *cls)
284 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
285 "Test #%u: schedule_member_part()\n", test);
286 GNUNET_MULTICAST_member_part (member, member_parted, NULL);
293 test = TEST_MEMBER_PART;
294 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
295 "Test #%u: member_part()\n", test);
296 // Test 10 starts here
297 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
304 // Execution of test 8 here
305 test = TEST_MEMBER_REPLAY_OK;
306 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
307 "Test #%u: member_replay_ok()\n", test);
308 replay_fragment_id = 1;
309 replay_flags = 1 | 1<<11;
310 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
316 member_replay_error ()
318 test = TEST_MEMBER_REPLAY_ERROR;
319 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
320 "Test #%u: member_replay_error()\n", test);
321 replay_fragment_id = 1234;
322 replay_flags = 11 | 1<<11;
323 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
329 origin_recv_replay_msg (void *cls,
330 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
332 uint64_t fragment_offset,
334 struct GNUNET_MULTICAST_ReplayHandle *rh)
336 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
337 "Test #%u: origin_recv_replay_msg()\n", test);
343 member_recv_replay_msg (void *cls,
344 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
346 uint64_t fragment_offset,
348 struct GNUNET_MULTICAST_ReplayHandle *rh)
350 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
351 "Test #%u: member_recv_replay_msg()\n", test);
357 origin_recv_replay_frag (void *cls,
358 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
359 uint64_t fragment_id,
361 struct GNUNET_MULTICAST_ReplayHandle *rh)
363 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
364 "Test #%u: origin_recv_replay_frag()"
365 " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n",
366 test, fragment_id, flags);
367 GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags);
370 case TEST_MEMBER_REPLAY_ERROR:
371 // Test 8 starts here
372 GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR);
376 case TEST_MEMBER_REPLAY_OK:
378 struct GNUNET_MULTICAST_MessageHeader mmsg = {
380 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE),
381 .size = htons (sizeof (mmsg)),
383 .fragment_id = GNUNET_htonll (1),
384 .message_id = GNUNET_htonll (1),
385 .fragment_offset = 0,
386 .group_generation = GNUNET_htonll (1),
390 member_cls.msgs_expected = 1;
391 GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK);
392 GNUNET_MULTICAST_replay_response_end (rh);
397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398 "Invalid test #%d in origin_recv_replay_frag()\n", test);
405 member_recv_replay_frag (void *cls,
406 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
407 uint64_t fragment_id,
409 struct GNUNET_MULTICAST_ReplayHandle *rh)
411 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
412 "Test #%u: member_recv_replay_frag()\n", test);
418 origin_recv_request (void *cls,
419 const struct GNUNET_MULTICAST_RequestHeader *req)
421 struct OriginClosure *ocls = cls;
422 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
423 "Test #%u: origin_recv_request()\n", test);
424 if (++ocls->n != ocls->msgs_expected)
427 GNUNET_assert (0 == memcmp (&req->member_pub_key,
428 &member_pub_key, sizeof (member_pub_key)));
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431 "Test #%u: verify message content, take first 3 bytes: %.3s\n",
432 test, (char *)&req[1]);
433 GNUNET_assert (0 == memcmp (&req[1], "abc", 3));
435 // Test 7 starts here
436 member_replay_error ();
443 test = TEST_MEMBER_TO_ORIGIN;
444 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
445 "Test #%u: member_to_origin()\n", test);
447 struct TransmitClosure *tmit = &tmit_cls;
448 *tmit = (struct TransmitClosure) {};
449 tmit->data[0] = "abc def";
450 tmit->data[1] = "ghi jkl mno";
451 tmit->data_delay[1] = 2;
452 tmit->data[2] = "pqr stuw xyz";
453 tmit->data_count = 3;
456 origin_cls.msgs_expected = 1;
458 tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1,
464 member_recv_message (void *cls,
465 const struct GNUNET_MULTICAST_MessageHeader *msg)
467 struct MemberClosure *mcls = cls;
469 // Test 5 starts here after message has been received from origin
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "Test #%u: member_recv_message() %u/%u\n",
473 (unsigned int) (mcls->n + 1),
474 mcls->msgs_expected);
475 if (++mcls->n != mcls->msgs_expected)
478 // FIXME: check message content
482 case TEST_ORIGIN_TO_ALL:
483 test = TEST_ORIGIN_TO_ALL_RECV;
486 case TEST_ORIGIN_TO_ALL_RECV:
487 // Test 6 starts here
491 case TEST_MEMBER_REPLAY_OK:
492 // Test 9 starts here
493 GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id));
498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
499 "Invalid test #%d in origin_recv_message()\n", test);
506 origin_recv_message (void *cls,
507 const struct GNUNET_MULTICAST_MessageHeader *msg)
509 struct OriginClosure *ocls = cls;
510 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
511 "Test #%u: origin_recv_message() %u/%u\n",
512 test, ocls->n + 1, ocls->msgs_expected);
513 if (++ocls->n != ocls->msgs_expected)
516 // FIXME: check message content
520 case TEST_ORIGIN_TO_ALL:
521 // Prepare to execute test 5
522 test = TEST_ORIGIN_TO_ALL_RECV;
525 case TEST_ORIGIN_TO_ALL_RECV:
526 // Test 6 starts here
531 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532 "Invalid test #%d in origin_recv_message()\n", test);
541 test = TEST_ORIGIN_TO_ALL;
542 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
543 "Test #%u: origin_to_all()\n", test);
545 struct TransmitClosure *tmit = &tmit_cls;
546 *tmit = (struct TransmitClosure) {};
547 tmit->data[0] = "ABC DEF";
548 tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1);
550 for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++)
551 tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
552 tmit->data[2] = "GHI JKL MNO";
553 tmit->data_delay[2] = 2;
554 tmit->data[3] = "PQR STUW XYZ";
555 tmit->data_count = 4;
557 origin_cls.n = member_cls.n = 0;
558 origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count;
560 tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1,
566 member_recv_join_decision (void *cls,
568 const struct GNUNET_PeerIdentity *peer,
569 uint16_t relay_count,
570 const struct GNUNET_PeerIdentity *relays,
571 const struct GNUNET_MessageHeader *join_msg)
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
574 "Test #%u: member_recv_join_decision() - is_admitted: %d\n",
577 GNUNET_assert (join_msg->size == join_resp->size);
578 GNUNET_assert (join_msg->type == join_resp->type);
579 GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size)));
583 case TEST_MEMBER_JOIN_REFUSE:
584 GNUNET_assert (0 == relay_count);
585 // Test 3 starts here
586 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
589 case TEST_MEMBER_JOIN_ADMIT:
590 GNUNET_assert (1 == relay_count);
591 GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer)));
592 // Test 4 starts here
597 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
598 "Invalid test #%d in member_recv_join_decision()\n", test);
604 * Test: origin receives join request
607 origin_recv_join_request (void *cls,
608 const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key,
609 const struct GNUNET_MessageHeader *join_msg,
610 struct GNUNET_MULTICAST_JoinHandle *jh)
612 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
613 "Test #%u: origin_recv_join_request()\n", test);
615 GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key)));
616 GNUNET_assert (join_msg->size == join_req->size);
617 GNUNET_assert (join_msg->type == join_req->type);
618 GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size)));
620 char data[] = "here's the decision";
621 uint8_t data_size = strlen (data) + 1;
622 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
623 join_resp->size = htons (sizeof (join_resp) + data_size);
624 join_resp->type = htons (456);
625 GNUNET_memcpy (&join_resp[1], data, data_size);
629 case TEST_MEMBER_JOIN_REFUSE:
630 // Test 3 starts here
631 GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp);
634 case TEST_MEMBER_JOIN_ADMIT:
636 GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp);
640 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
641 "Invalid test #%d in origin_recv_join_request()\n", test);
648 * Test: member joins multicast group
654 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
655 "Test #%u: member_join()\n", test);
657 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
658 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
660 if (NULL != join_req)
661 GNUNET_free (join_req);
663 char data[] = "let me in!";
664 uint8_t data_size = strlen (data) + 1;
665 join_req = GNUNET_malloc (sizeof (join_req) + data_size);
666 join_req->size = htons (sizeof (join_req) + data_size);
667 join_req->type = htons (123);
668 GNUNET_memcpy (&join_req[1], data, data_size);
670 member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key,
671 &this_peer, 1, &this_peer, join_req,
672 member_recv_join_request,
673 member_recv_join_decision,
674 member_recv_replay_frag,
675 member_recv_replay_msg,
681 * Test: Start a multicast group as origin
686 test = TEST_ORIGIN_START;
687 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
688 "Test #%u: origin_start()\n", test);
690 group_key = GNUNET_CRYPTO_eddsa_key_create ();
691 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
693 origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0,
694 origin_recv_join_request,
695 origin_recv_replay_frag,
696 origin_recv_replay_msg,
700 // Test 2 starts here
701 member_join (TEST_MEMBER_JOIN_REFUSE);
706 * Main function of the test, run from scheduler.
709 * @param cfg configuration we use (also to connect to Multicast service)
710 * @param peer handle to access more of the peer (not used)
713 #if DEBUG_TEST_MULTICAST
717 const struct GNUNET_CONFIGURATION_Handle *c)
720 const struct GNUNET_CONFIGURATION_Handle *c,
721 struct GNUNET_TESTING_Peer *peer)
725 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
727 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
729 // Test 1 starts here
735 main (int argc, char *argv[])
738 #if DEBUG_TEST_MULTICAST
739 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
740 GNUNET_GETOPT_OPTION_END
742 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast",
743 "test-multicast [options]",
747 if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL))
753 /* end of test_multicast.c */