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