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