small API change: do no longer pass rarely needed GNUNET_SCHEDULER_TaskContext to...
[oweals/gnunet.git] / src / multicast / test_multicast.c
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
6  * it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 3, or (at your
8  * option) any later version.
9  *
10  * GNUnet is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with GNUnet; see the file COPYING.  If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file multicast/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_core_service.h"
35 #include "gnunet_multicast_service.h"
36
37 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39 /**
40  * Return value from 'main'.
41  */
42 static int res;
43
44 /**
45  * Handle for task for timeout termination.
46  */
47 static struct GNUNET_SCHEDULER_Task * end_badly_task;
48
49 static const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51 struct GNUNET_CORE_Handle *core;
52 struct GNUNET_PeerIdentity this_peer;
53
54 struct GNUNET_MULTICAST_Origin *origin;
55 struct GNUNET_MULTICAST_Member *member;
56
57 struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
58 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
59
60 struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
61 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
62
63 struct TransmitClosure {
64   struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit;
65   struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit;
66   char * data[16];
67   uint8_t data_delay[16];
68   uint8_t data_count;
69   uint8_t paused;
70   uint8_t n;
71 } tmit_cls;
72
73 struct OriginClosure {
74   uint8_t msgs_expected;
75   uint8_t n;
76 } origin_cls;
77
78 struct MemberClosure {
79   uint8_t msgs_expected;
80   size_t n;
81 } member_cls;
82
83 struct GNUNET_MessageHeader *join_req, *join_resp;
84
85 enum
86 {
87   TEST_NONE                = 0,
88   TEST_ORIGIN_START        = 1,
89   TEST_MEMBER_JOIN_REFUSE  = 2,
90   TEST_MEMBER_JOIN_ADMIT   = 3,
91   TEST_ORIGIN_TO_ALL       = 4,
92   TEST_ORIGIN_TO_ALL_RECV  = 5,
93   TEST_MEMBER_TO_ORIGIN    = 6,
94   TEST_MEMBER_REPLAY_ERROR = 7,
95   TEST_MEMBER_REPLAY_OK    = 8,
96   TEST_MEMBER_PART         = 9,
97   TEST_ORIGIN_STOP        = 10,
98 } test;
99
100 uint64_t replay_fragment_id;
101 uint64_t replay_flags;
102
103 static void
104 member_join (int t);
105
106
107 /**
108  * Clean up all resources used.
109  */
110 static void
111 cleanup ()
112 {
113   if (NULL != core)
114   {
115     GNUNET_CORE_disconnect (core);
116     core = NULL;
117   }
118   if (NULL != member)
119   {
120     GNUNET_MULTICAST_member_part (member, NULL, NULL);
121     member = NULL;
122   }
123   if (NULL != origin)
124   {
125     GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
126     origin = NULL;
127   }
128 }
129
130
131 /**
132  * Terminate the test case (failure).
133  *
134  * @param cls NULL
135  */
136 static void
137 end_badly (void *cls)
138 {
139   res = 1;
140   cleanup ();
141   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
142 }
143
144
145 /**
146  * Terminate the test case (success).
147  *
148  * @param cls NULL
149  */
150 static void
151 end_normally (void *cls)
152 {
153   res = 0;
154   cleanup ();
155   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n");
156 }
157
158
159 /**
160  * Finish the test case (successfully).
161  */
162 static void
163 end ()
164 {
165   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
166
167   if (end_badly_task != NULL)
168   {
169     GNUNET_SCHEDULER_cancel (end_badly_task);
170     end_badly_task = NULL;
171   }
172   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
173                                 &end_normally, NULL);
174 }
175
176
177 static void
178 tmit_resume (void *cls)
179 {
180   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
181   struct TransmitClosure *tmit = cls;
182   if (NULL != tmit->orig_tmit)
183     GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit);
184   else if (NULL != tmit->mem_tmit)
185     GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit);
186 }
187
188
189 static int
190 tmit_notify (void *cls, size_t *data_size, void *data)
191 {
192   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193               "Test #%u: origin_tmit_notify()\n", test);
194   struct TransmitClosure *tmit = cls;
195
196   if (0 == tmit->data_count)
197   {
198     *data_size = 0;
199     return GNUNET_YES;
200   }
201
202   uint16_t size = strlen (tmit->data[tmit->n]);
203   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204               "Transmit notify data: %u bytes available, "
205               "processing fragment %u/%u (size %u).\n",
206               *data_size, tmit->n + 1, tmit->data_count, size);
207   if (*data_size < size)
208   {
209     *data_size = 0;
210     GNUNET_assert (0);
211     return GNUNET_SYSERR;
212   }
213
214   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
215   {
216     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
217     tmit->paused = GNUNET_YES;
218     GNUNET_SCHEDULER_add_delayed (
219       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
220                                      tmit->data_delay[tmit->n]),
221       tmit_resume, tmit);
222     *data_size = 0;
223     return GNUNET_NO;
224   }
225   tmit->paused = GNUNET_NO;
226
227   *data_size = size;
228   memcpy (data, tmit->data[tmit->n], size);
229
230   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
231 }
232
233
234 static void
235 member_recv_join_request (void *cls,
236                           const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
237                           const struct GNUNET_MessageHeader *join_msg,
238                           struct GNUNET_MULTICAST_JoinHandle *jh)
239 {
240   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241               "Test #%u: member_recv_join_request()\n", test);
242 }
243
244
245 static void
246 origin_stopped (void *cls)
247 {
248   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
249               "Test #%u: origin_stopped()\n", test);
250   end ();
251 }
252
253
254 static void
255 schedule_origin_stop (void *cls)
256 {
257   test = TEST_ORIGIN_STOP;
258   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
259               "Test #%u: origin_stop()\n", test);
260   GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL);
261   origin = NULL;
262 }
263
264
265 static void
266 member_parted (void *cls)
267 {
268   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
269               "Test #%u: member_parted()\n", test);
270   member = NULL;
271
272   switch (test)
273   {
274   case TEST_MEMBER_JOIN_REFUSE:
275     member_join (TEST_MEMBER_JOIN_ADMIT);
276     break;
277
278   case TEST_MEMBER_PART:
279     GNUNET_SCHEDULER_add_now (schedule_origin_stop, NULL);
280     break;
281
282   default:
283     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
284                 "Invalid test #%d in member_recv_join_decision()\n", test);
285     GNUNET_assert (0);
286   }
287 }
288
289
290 static void
291 schedule_member_part (void *cls)
292 {
293   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294               "Test #%u: schedule_member_part()\n", test);
295   GNUNET_MULTICAST_member_part (member, member_parted, NULL);
296 }
297
298
299 static void
300 member_part ()
301 {
302   test = TEST_MEMBER_PART;
303   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
304               "Test #%u: member_part()\n", test);
305   GNUNET_SCHEDULER_add_now (schedule_member_part, NULL);
306 }
307
308
309 static void
310 member_replay_ok ()
311 {
312   test = TEST_MEMBER_REPLAY_OK;
313   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314               "Test #%u: member_replay_ok()\n", test);
315   replay_fragment_id = 1;
316   replay_flags = 1 | 1<<11;
317   GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
318                                            replay_flags);
319 }
320
321
322 static void
323 member_replay_error ()
324 {
325   test = TEST_MEMBER_REPLAY_ERROR;
326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
327               "Test #%u: member_replay_error()\n", test);
328   replay_fragment_id = 1234;
329   replay_flags = 11 | 1<<11;
330   GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
331                                            replay_flags);
332 }
333
334
335 static void
336 origin_recv_replay_msg (void *cls,
337                         const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
338                         uint64_t message_id,
339                         uint64_t fragment_offset,
340                         uint64_t flags,
341                         struct GNUNET_MULTICAST_ReplayHandle *rh)
342 {
343   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344               "Test #%u: origin_recv_replay_msg()\n", test);
345   GNUNET_assert (0);
346 }
347
348
349 static void
350 member_recv_replay_msg (void *cls,
351                         const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
352                         uint64_t message_id,
353                         uint64_t fragment_offset,
354                         uint64_t flags,
355                         struct GNUNET_MULTICAST_ReplayHandle *rh)
356 {
357   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
358               "Test #%u: member_recv_replay_msg()\n", test);
359   GNUNET_assert (0);
360 }
361
362
363 static void
364 origin_recv_replay_frag (void *cls,
365                          const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
366                          uint64_t fragment_id,
367                          uint64_t flags,
368                          struct GNUNET_MULTICAST_ReplayHandle *rh)
369 {
370   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371               "Test #%u: origin_recv_replay_frag()"
372               " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n",
373               test, fragment_id, flags);
374   GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags);
375   switch (test)
376   {
377   case TEST_MEMBER_REPLAY_ERROR:
378     GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR);
379     member_replay_ok ();
380     break;
381
382   case TEST_MEMBER_REPLAY_OK:
383   {
384     struct GNUNET_MULTICAST_MessageHeader mmsg = {
385       .header = {
386         .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE),
387         .size = htons (sizeof (mmsg)),
388       },
389       .fragment_id = GNUNET_htonll (1),
390       .message_id = GNUNET_htonll (1),
391       .fragment_offset = 0,
392       .group_generation = GNUNET_htonll (1),
393       .flags = 0,
394     };
395     member_cls.n = 0;
396     member_cls.msgs_expected = 1;
397     GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK);
398     GNUNET_MULTICAST_replay_response_end (rh);
399     break;
400   }
401
402   default:
403     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404                 "Invalid test #%d in origin_recv_replay_frag()\n", test);
405     GNUNET_assert (0);
406   }
407 }
408
409
410 static void
411 member_recv_replay_frag (void *cls,
412                          const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
413                          uint64_t fragment_id,
414                          uint64_t flags,
415                          struct GNUNET_MULTICAST_ReplayHandle *rh)
416 {
417   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
418               "Test #%u: member_recv_replay_frag()\n", test);
419   GNUNET_assert (0);
420 }
421
422
423 static void
424 origin_recv_request (void *cls,
425                      const struct GNUNET_MULTICAST_RequestHeader *req)
426 {
427   struct OriginClosure *ocls = cls;
428   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429               "Test #%u: origin_recv_request()\n", test);
430   if (++ocls->n != ocls->msgs_expected)
431     return;
432
433   GNUNET_assert (0 == memcmp (&req->member_pub_key,
434                               &member_pub_key, sizeof (member_pub_key)));
435
436
437   // FIXME: check message content
438
439   member_replay_error ();
440 }
441
442
443 static void
444 member_to_origin ()
445 {
446   test = TEST_MEMBER_TO_ORIGIN;
447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448               "Test #%u: member_to_origin()\n", test);
449
450   struct TransmitClosure *tmit = &tmit_cls;
451   *tmit = (struct TransmitClosure) {};
452   tmit->data[0] = "abc def";
453   tmit->data[1] = "ghi jkl mno";
454   tmit->data_delay[1] = 2;
455   tmit->data[2] = "pqr stuw xyz";
456   tmit->data_count = 3;
457
458   origin_cls.n = 0;
459   origin_cls.msgs_expected = 1;
460
461   tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1,
462                                                       tmit_notify, tmit);
463 }
464
465
466 static void
467 member_recv_message (void *cls,
468                      const struct GNUNET_MULTICAST_MessageHeader *msg)
469 {
470   struct MemberClosure *mcls = cls;
471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472               "Test #%u: member_recv_message() %u/%u\n",
473               test, mcls->n + 1, mcls->msgs_expected);
474   if (++mcls->n != mcls->msgs_expected)
475     return;
476
477   // FIXME: check message content
478
479   switch (test)
480   {
481   case TEST_ORIGIN_TO_ALL_RECV:
482     member_to_origin ();
483     break;
484
485   case TEST_MEMBER_REPLAY_OK:
486     GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id));
487     member_part ();
488     break;
489
490   default:
491     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
492                 "Invalid test #%d in origin_recv_message()\n", test);
493     GNUNET_assert (0);
494   }
495 }
496
497
498 static void
499 origin_recv_message (void *cls,
500                      const struct GNUNET_MULTICAST_MessageHeader *msg)
501 {
502   struct OriginClosure *ocls = cls;
503   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504               "Test #%u: origin_recv_message() %u/%u\n",
505               test, ocls->n + 1, ocls->msgs_expected);
506   if (++ocls->n != ocls->msgs_expected)
507     return;
508
509   // FIXME: check message content
510
511   switch (test)
512   {
513   case TEST_ORIGIN_TO_ALL:
514     test = TEST_ORIGIN_TO_ALL_RECV;
515     break;
516
517   default:
518     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
519                 "Invalid test #%d in origin_recv_message()\n", test);
520     GNUNET_assert (0);
521   }
522 }
523
524
525 static void
526 origin_to_all ()
527 {
528   test = TEST_ORIGIN_TO_ALL;
529   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
530               "Test #%u: origin_to_all()\n", test);
531
532   struct TransmitClosure *tmit = &tmit_cls;
533   *tmit = (struct TransmitClosure) {};
534   tmit->data[0] = "ABC DEF";
535   tmit->data[1] =  GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1);
536   uint16_t i;
537   for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++)
538     tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
539   tmit->data[2] = "GHI JKL MNO";
540   tmit->data_delay[2] = 2;
541   tmit->data[3] = "PQR STUW XYZ";
542   tmit->data_count = 4;
543
544   origin_cls.n = member_cls.n = 0;
545   origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count;
546
547   tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1,
548                                                     tmit_notify, tmit);
549 }
550
551
552 static void
553 member_recv_join_decision (void *cls,
554                            int is_admitted,
555                            const struct GNUNET_PeerIdentity *peer,
556                            uint16_t relay_count,
557                            const struct GNUNET_PeerIdentity *relays,
558                            const struct GNUNET_MessageHeader *join_msg)
559 {
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561               "Test #%u: member_recv_join_decision() - is_admitted: %d\n",
562               test, is_admitted);
563
564   GNUNET_assert (join_msg->size == join_resp->size);
565   GNUNET_assert (join_msg->type == join_resp->type);
566   GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size)));
567
568   switch (test)
569   {
570   case TEST_MEMBER_JOIN_REFUSE:
571     GNUNET_assert (0 == relay_count);
572     GNUNET_SCHEDULER_add_now (schedule_member_part, NULL);
573     break;
574
575   case TEST_MEMBER_JOIN_ADMIT:
576     GNUNET_assert (1 == relay_count);
577     GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer)));
578     origin_to_all ();
579     break;
580
581   default:
582     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583                 "Invalid test #%d in member_recv_join_decision()\n", test);
584     GNUNET_assert (0);
585   }
586 }
587
588
589 static void
590 origin_recv_join_request (void *cls,
591                           const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key,
592                           const struct GNUNET_MessageHeader *join_msg,
593                           struct GNUNET_MULTICAST_JoinHandle *jh)
594 {
595   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596               "Test #%u: origin_recv_join_request()\n", test);
597
598   GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key)));
599   GNUNET_assert (join_msg->size == join_req->size);
600   GNUNET_assert (join_msg->type == join_req->type);
601   GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size)));
602
603   char data[] = "here's the decision";
604   uint8_t data_size = strlen (data) + 1;
605   join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
606   join_resp->size = htons (sizeof (join_resp) + data_size);
607   join_resp->type = htons (456);
608   memcpy (&join_resp[1], data, data_size);
609
610   switch (test)
611   {
612   case TEST_MEMBER_JOIN_REFUSE:
613     GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp);
614     break;
615
616   case TEST_MEMBER_JOIN_ADMIT:
617     GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp);
618     break;
619
620   default:
621     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
622                 "Invalid test #%d in origin_recv_join_request()\n", test);
623     GNUNET_assert (0);
624     break;
625   }
626 }
627
628
629 static void
630 member_join (int t)
631 {
632   test = t;
633   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
634               "Test #%u: member_join()\n", test);
635
636   member_key = GNUNET_CRYPTO_ecdsa_key_create ();
637   GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
638
639   if (NULL != join_req)
640     GNUNET_free (join_req);
641
642   char data[] = "let me in!";
643   uint8_t data_size = strlen (data) + 1;
644   join_req = GNUNET_malloc (sizeof (join_req) + data_size);
645   join_req->size = htons (sizeof (join_req) + data_size);
646   join_req->type = htons (123);
647   memcpy (&join_req[1], data, data_size);
648
649   member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key,
650                                          &this_peer, 1, &this_peer, join_req,
651                                          member_recv_join_request,
652                                          member_recv_join_decision,
653                                          member_recv_replay_frag,
654                                          member_recv_replay_msg,
655                                          member_recv_message,
656                                          &member_cls);
657 }
658
659
660 static void
661 origin_start ()
662 {
663   test = TEST_ORIGIN_START;
664   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
665               "Test #%u: origin_start()\n", test);
666
667   group_key = GNUNET_CRYPTO_eddsa_key_create ();
668   GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
669
670   origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0,
671                                           origin_recv_join_request,
672                                           origin_recv_replay_frag,
673                                           origin_recv_replay_msg,
674                                           origin_recv_request,
675                                           origin_recv_message,
676                                           &origin_cls);
677   member_join (TEST_MEMBER_JOIN_REFUSE);
678 }
679
680
681 static void
682 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
683 {
684   this_peer = *my_identity;
685   origin_start ();
686 }
687
688
689 /**
690  * Main function of the test, run from scheduler.
691  *
692  * @param cls NULL
693  * @param cfg configuration we use (also to connect to Multicast service)
694  * @param peer handle to access more of the peer (not used)
695  */
696 static void
697 #if DEBUG_TEST_MULTICAST
698 run (void *cls, char *const *args, const char *cfgfile,
699      const struct GNUNET_CONFIGURATION_Handle *c)
700 #else
701 run (void *cls,
702      const struct GNUNET_CONFIGURATION_Handle *c,
703      struct GNUNET_TESTING_Peer *peer)
704 #endif
705 {
706   cfg = c;
707   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
708
709   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
710                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
711 }
712
713
714 int
715 main (int argc, char *argv[])
716 {
717   res = 1;
718 #if DEBUG_TEST_MULTICAST
719   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
720     GNUNET_GETOPT_OPTION_END
721   };
722   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast",
723                                        "test-multicast [options]",
724                                        opts, &run, NULL))
725     return 1;
726 #else
727   if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL))
728     return 1;
729 #endif
730   return res;
731 }
732
733 /* end of test_multicast.c */