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