glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / multicast / test_multicast_multipeer.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 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
16 /**
17  * @file multicast/test_multicast_multipeers.c
18  * @brief Tests for the Multicast API with multiple peers.
19  * @author xrs
20  */
21
22 #include <inttypes.h>
23
24 #include "platform.h"
25 #include "gnunet_crypto_lib.h"
26 #include "gnunet_common.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_testbed_service.h"
29 #include "gnunet_multicast_service.h"
30
31 #define PEERS_REQUESTED 12
32
33 struct MulticastPeerContext
34 {
35   int peer; /* peer number */
36   struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
37   const struct GNUNET_PeerIdentity *id;
38   struct GNUNET_TESTBED_Operation *op; /* not yet in use */
39   struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */
40   int test_ok;
41 };
42
43 enum pingpong
44 {
45   PING = 1,
46   PONG = 2
47 };
48
49 struct pingpong_msg
50 {
51   int peer;
52   enum pingpong msg;
53 };
54
55 static void service_connect (void *cls,
56                              struct GNUNET_TESTBED_Operation *op,
57                              void *ca_result,
58                              const char *emsg);
59
60 static struct MulticastPeerContext **multicast_peers;
61 static struct GNUNET_TESTBED_Peer **peers;
62
63 static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED];
64 static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED];
65
66 static struct GNUNET_MULTICAST_Origin *origin;
67 static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */
68
69 static struct GNUNET_SCHEDULER_Task *timeout_tid;
70
71 static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
72 static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
73 static struct GNUNET_HashCode group_pub_key_hash;
74
75 /**
76  * Global result for testcase.
77  */
78 static int result;
79
80 /**
81  * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
82  * Cleans up.
83  */
84 static void
85 shutdown_task (void *cls)
86 {
87   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88               "shutdown_task!\n");
89   for (int i=0;i<PEERS_REQUESTED;i++)
90   {
91     if (NULL != op[i])
92     {
93       GNUNET_TESTBED_operation_done(op[i]);
94       op[i] = NULL;
95     }
96     if (NULL != pi_op[i])
97     {
98       GNUNET_TESTBED_operation_done (pi_op[i]);
99       pi_op[i] = NULL;
100     }
101   }
102
103   if (NULL != multicast_peers)
104   {
105     for (int i=0; i < PEERS_REQUESTED; i++)
106     {
107       GNUNET_free_non_null (multicast_peers[i]->key);
108       GNUNET_free (multicast_peers[i]);
109       multicast_peers[i] = NULL;
110     }
111     GNUNET_free (multicast_peers);
112     multicast_peers = NULL;
113   }
114
115   if (NULL != timeout_tid)
116   {
117     GNUNET_SCHEDULER_cancel (timeout_tid);
118     timeout_tid = NULL;
119   }
120 }
121
122
123 static void
124 timeout_task (void *cls)
125 {
126   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127               "Timeout!\n");
128   result = GNUNET_SYSERR;
129   GNUNET_SCHEDULER_shutdown ();
130 }
131
132
133 static void
134 member_join_request (void *cls,
135                      const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
136                      const struct GNUNET_MessageHeader *join_msg,
137                      struct GNUNET_MULTICAST_JoinHandle *jh)
138 {
139   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
140   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
141               "Peer #%u (%s) sent a join request.\n",
142               mc_peer->peer,
143               GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
144 }
145
146
147 static int
148 notify (void *cls,
149         size_t *data_size,
150         void *data)
151 {
152   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
153
154   struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
155   pp_msg->peer = mc_peer->peer;
156   pp_msg->msg = PING;
157
158   *data_size = sizeof (struct pingpong_msg);
159   GNUNET_memcpy(data, pp_msg, *data_size);
160
161   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
162               "Peer #%u sents ping to origin\n", mc_peer->peer);
163
164   return GNUNET_YES;
165 }
166
167
168 static void
169 member_join_decision (void *cls,
170                       int is_admitted,
171                       const struct GNUNET_PeerIdentity *peer,
172                       uint16_t relay_count,
173                       const struct GNUNET_PeerIdentity *relays,
174                       const struct GNUNET_MessageHeader *join_msg)
175 {
176   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
177
178   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
179               "Peer #%u (%s) received a decision from origin: %s\n",
180               mc_peer->peer,
181               GNUNET_i2s (multicast_peers[mc_peer->peer]->id),
182               (GNUNET_YES == is_admitted)?"accepted":"rejected");
183
184   if (GNUNET_YES == is_admitted)
185   {
186     GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer],
187                                        0,
188                                        notify,
189                                        cls);
190
191   }
192 }
193
194
195 static void
196 member_replay_frag ()
197 {
198   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
199               "member replay frag...\n");
200 }
201
202
203 static void
204 member_replay_msg ()
205 {
206   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
207               "member replay msg...\n");
208 }
209
210
211 static void
212 origin_disconnected_cb (void *cls)
213 {
214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215               "Origin disconnected. Shutting down.\n");
216   result = GNUNET_YES;
217   GNUNET_SCHEDULER_shutdown ();
218 }
219
220
221 static void
222 member_disconnected_cb (void *cls)
223 {
224   for (int i = 1; i < PEERS_REQUESTED; ++i)
225     if (GNUNET_NO == multicast_peers[i]->test_ok)
226       return;
227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228               "All member disconnected. Stopping origin.\n");
229   GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls);
230 }
231
232
233 static void
234 member_message (void *cls,
235                 const struct GNUNET_MULTICAST_MessageHeader *msg)
236 {
237   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
238   struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]);
239
240   if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer)
241   {
242     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
243                 "peer #%i (%s) receives a pong\n",
244                 mc_peer->peer,
245                 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
246     mc_peer->test_ok = GNUNET_OK;
247     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
248                 "peer #%u (%s) parting from multicast group\n",
249                 mc_peer->peer,
250                 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
251
252     GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls);
253   }
254 }
255
256
257 static void
258 origin_join_request (void *cls,
259                  const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
260                  const struct GNUNET_MessageHeader *join_msg,
261                  struct GNUNET_MULTICAST_JoinHandle *jh)
262 {
263   struct GNUNET_MessageHeader *join_resp;
264
265   uint8_t data_size = ntohs (join_msg->size);
266
267   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
268               "origin got a join request...\n");
269   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
270               "origin receives: '%s'\n", (char *)&join_msg[1]);
271
272   char data[] = "Come in!";
273   data_size = strlen (data) + 1;
274   join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
275   join_resp->size = htons (sizeof (join_resp) + data_size);
276   join_resp->type = htons (123);
277   GNUNET_memcpy (&join_resp[1], data, data_size);
278
279   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
280               "origin sends: '%s'\n", data);
281
282   GNUNET_MULTICAST_join_decision (jh,
283                                   GNUNET_YES,
284                                   0,
285                                   NULL,
286                                   join_resp);
287
288   result = GNUNET_OK;
289 }
290
291
292 static void
293 origin_replay_frag (void *cls,
294                     const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
295                     uint64_t fragment_id,
296                     uint64_t flags,
297                     struct GNUNET_MULTICAST_ReplayHandle *rh)
298 {
299   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
300 }
301
302
303 static void
304 origin_replay_msg (void *cls,
305                    const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
306                    uint64_t message_id,
307                    uint64_t fragment_offset,
308                    uint64_t flags,
309                    struct GNUNET_MULTICAST_ReplayHandle *rh)
310 {
311
312   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
313 }
314
315
316 static int
317 origin_notify (void *cls,
318                size_t *data_size,
319                void *data)
320 {
321   struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls;
322   struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
323
324   pp_msg->peer = rcv_pp_msg->peer;
325   pp_msg->msg = PONG;
326   *data_size = sizeof (struct pingpong_msg);
327   GNUNET_memcpy(data, pp_msg, *data_size);
328
329   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n");
330
331   return GNUNET_YES;
332 }
333
334
335 static void
336 origin_request (void *cls,
337                 const struct GNUNET_MULTICAST_RequestHeader *req)
338 {
339   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n");
340
341   req++;
342   struct pingpong_msg *pp_msg = (struct pingpong_msg *) req;
343
344   if (1 != pp_msg->msg) {
345     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
346   }
347
348   GNUNET_MULTICAST_origin_to_all (origin,
349                                   0,
350                                   0,
351                                   origin_notify,
352                                   pp_msg);
353 }
354
355
356 static void
357 origin_message (void *cls,
358                 const struct GNUNET_MULTICAST_MessageHeader *msg)
359 {
360   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
361 }
362
363
364 static void
365 multicast_disconnect (void *cls,
366                       void *op_result)
367 {
368
369 }
370
371
372 static void *
373 multicast_connect (void *cls,
374                    const struct GNUNET_CONFIGURATION_Handle *cfg)
375 {
376   struct MulticastPeerContext *multicast_peer = cls;
377   struct GNUNET_MessageHeader *join_msg;
378   char data[64];
379
380   if (0 == multicast_peer->peer)
381   {
382     group_key = GNUNET_CRYPTO_eddsa_key_create ();
383     GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
384
385     GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash);
386     origin = GNUNET_MULTICAST_origin_start (cfg,
387                                             group_key,
388                                             0,
389                                             origin_join_request,
390                                             origin_replay_frag,
391                                             origin_replay_msg,
392                                             origin_request,
393                                             origin_message,
394                                             cls);
395     if (NULL == origin)
396     {
397       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
398                   "Peer #%u could not create a multicast group",
399                   multicast_peer->peer);
400       return NULL;
401     }
402     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
403                 "Peer #%u connected as origin to group %s\n",
404                 multicast_peer->peer,
405                 GNUNET_h2s (&group_pub_key_hash));
406     return origin;
407   }
408   else
409   {
410     multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create ();
411
412     sprintf(data, "Hi, I am peer #%u (%s). Can I enter?",
413             multicast_peer->peer,
414             GNUNET_i2s (multicast_peers[multicast_peer->peer]->id));
415     uint8_t data_size = strlen (data) + 1;
416     join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
417     join_msg->size = htons (sizeof (join_msg) + data_size);
418     join_msg->type = htons (123);
419     GNUNET_memcpy (&join_msg[1], data, data_size);
420
421     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
422                 "Peer #%u (%s) tries to join multicast group %s\n",
423                 multicast_peer->peer,
424                 GNUNET_i2s (multicast_peers[multicast_peer->peer]->id),
425                 GNUNET_h2s (&group_pub_key_hash));
426
427     members[multicast_peer->peer] =
428       GNUNET_MULTICAST_member_join (cfg,
429                                     &group_pub_key,
430                                     multicast_peer->key,
431                                     multicast_peers[0]->id,
432                                     0,
433                                     NULL,
434                                     join_msg, /* join message */
435                                     member_join_request,
436                                     member_join_decision,
437                                     member_replay_frag,
438                                     member_replay_msg,
439                                     member_message,
440                                     cls);
441     return members[multicast_peer->peer];
442   }
443 }
444
445
446 static void
447 peer_information_cb (void *cls,
448                      struct GNUNET_TESTBED_Operation *operation,
449                      const struct GNUNET_TESTBED_PeerInformation *pinfo,
450                      const char *emsg)
451 {
452   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
453
454   if (NULL == pinfo) {
455     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n");
456     result = GNUNET_SYSERR;
457     GNUNET_SCHEDULER_shutdown ();
458   }
459
460   multicast_peers[mc_peer->peer]->id = pinfo->result.id;
461
462   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
463               "Got peer information of %s (%s)\n",
464               (0 == mc_peer->peer)? "origin" : "member",
465               GNUNET_i2s (pinfo->result.id));
466
467   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
468               "Create peer #%u (%s)\n",
469               mc_peer->peer,
470               GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
471
472   if (0 != mc_peer->peer)
473   {
474     /* connect to multicast service of members */
475     op[mc_peer->peer] =
476       GNUNET_TESTBED_service_connect (/* Closure for operation */
477                                       NULL,
478                                       /* The peer whose service to connect to */
479                                       peers[mc_peer->peer],
480                                       /* The name of the service */
481                                       "multicast",
482                                       /* called after a handle to service is opened */
483                                       service_connect,
484                                       /* closure for the above callback */
485                                       cls,
486                                       /* called when opening the service connection */
487                                       multicast_connect,
488                                       /* called when closing the service connection */
489                                       multicast_disconnect,
490                                       /* closure for the above two callbacks */
491                                       cls);
492   }
493 }
494
495
496 static void
497 service_connect (void *cls,
498                  struct GNUNET_TESTBED_Operation *op,
499                  void *ca_result,
500                  const char *emsg)
501 {
502   struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
503
504   if (NULL == ca_result)
505   {
506     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
507                 "Connection adapter not created for peer #%u (%s)\n",
508                 mc_peer->peer,
509                 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
510
511     result = GNUNET_SYSERR;
512     GNUNET_SCHEDULER_shutdown();
513   }
514
515   if (0 == mc_peer->peer)
516   {
517     // Get GNUnet identity of members
518     for (int i = 0; i<PEERS_REQUESTED; i++)
519     {
520       pi_op[i] = GNUNET_TESTBED_peer_get_information (peers[i],
521                                                       GNUNET_TESTBED_PIT_IDENTITY,
522                                                       peer_information_cb,
523                                                       multicast_peers[i]);
524     }
525   }
526 }
527
528
529
530 /**
531  * Main function inovked from TESTBED once all of the
532  * peers are up and running.  This one then connects
533  * just to the multicast service of peer 0 and 1.
534  * Peer 0 is going to be origin.
535  * Peer 1 is going to be one member.
536  * Origin will start a multicast group and the member will try to join it.
537  * After that we execute some multicast test.
538  *
539  * @param cls closure
540  * @param h the run handle
541  * @param peers started peers for the test
542  * @param PEERS_REQUESTED size of the 'peers' array
543  * @param links_succeeded number of links between peers that were created
544  * @param links_failed number of links testbed was unable to establish
545  */
546 static void
547 testbed_master (void *cls,
548                 struct GNUNET_TESTBED_RunHandle *h,
549                 unsigned int num_peers,
550                 struct GNUNET_TESTBED_Peer **p,
551                 unsigned int links_succeeded,
552                 unsigned int links_failed)
553 {
554   /* Testbed is ready with peers running and connected in a pre-defined overlay
555      topology (FIXME)  */
556   peers = p;
557   multicast_peers = GNUNET_new_array (PEERS_REQUESTED, struct MulticastPeerContext*);
558
559   // Create test contexts for members
560   for (int i = 0; i<PEERS_REQUESTED; i++)
561   {
562     multicast_peers[i] = GNUNET_new (struct MulticastPeerContext);
563     multicast_peers[i]->peer = i;
564     multicast_peers[i]->test_ok = GNUNET_NO;
565   }
566   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
567               "Create origin peer\n");
568   op[0] =
569     GNUNET_TESTBED_service_connect (/* Closure for operation */
570                                     NULL,
571                                     /* The peer whose service to connect to */
572                                     peers[0],
573                                     /* The name of the service */
574                                     "multicast",
575                                     /* called after a handle to service is opened */
576                                     service_connect,
577                                     /* closure for the above callback */
578                                     multicast_peers[0],
579                                     /* called when opening the service connection */
580                                     multicast_connect,
581                                     /* called when closing the service connection */
582                                     multicast_disconnect,
583                                     /* closure for the above two callbacks */
584                                     multicast_peers[0]);
585   /* Schedule a new task on shutdown */
586   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
587   /* Schedule the shutdown task with a delay of a few Seconds */
588   timeout_tid =
589     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
590                                   (GNUNET_TIME_UNIT_SECONDS, 400),
591                                   &timeout_task,
592                                   NULL);
593 }
594
595
596 int
597 main (int argc, char *argv[])
598 {
599   int ret;
600   char const *config_file;
601
602   if (strstr (argv[0], "_line") != NULL)
603   {
604     config_file = "test_multicast_line.conf";
605   }
606   else if (strstr(argv[0], "_star") != NULL)
607   {
608     config_file = "test_multicast_star.conf";
609   }
610   else
611   {
612     config_file = "test_multicast_star.conf";
613   }
614
615   result = GNUNET_SYSERR;
616   ret =
617     GNUNET_TESTBED_test_run ("test-multicast-multipeer",
618                              config_file,
619                              /* number of peers to start */
620                              PEERS_REQUESTED,
621                              /* Event mask - set to 0 for no event notifications */
622                              0LL,
623                              /* Controller event callback */
624                              NULL,
625                              /* Closure for controller event callback */
626                              NULL,
627                              /* called when testbed setup is complete */
628                              testbed_master,
629                              /* Closure for the test_master callback */
630                              NULL);
631   if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
632     return 1;
633   return 0;
634 }
635
636 /* end of test_multicast_multipeer.c */