add test_multicast_2peers.c
[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
158 static void
159 member_message (void *cls, 
160                 const struct GNUNET_MULTICAST_MessageHeader *msg)
161 {
162   if (0 != strncmp ("pong", (char *)&msg[1], 4)) {
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
235   GNUNET_MULTICAST_origin_to_all (origin,
236                                   0,
237                                   0,
238                                   origin_notify,
239                                   NULL);
240 }
241
242 static void
243 origin_message (void *cls,
244                 const struct GNUNET_MULTICAST_MessageHeader *msg) 
245 {
246   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
247 }
248
249
250 static void
251 service_connect1 (void *cls,
252                   struct GNUNET_TESTBED_Operation *op,
253                   void *ca_result,
254                   const char *emsg)
255 {
256   member = ca_result;
257
258   if (NULL != member)
259     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
260   else
261     result = GNUNET_SYSERR;
262 }
263
264 static void
265 multicast_da1 (void *cls,
266                void * op_result)
267 {
268   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
269               "Member parting from multicast group\n");
270
271   GNUNET_MULTICAST_member_part (member, NULL, NULL);
272 }
273
274
275 static void *
276 multicast_ca1 (void *cls,
277                const struct GNUNET_CONFIGURATION_Handle *cfg)
278 {
279   struct GNUNET_MessageHeader *join_msg;
280
281   // Get members keys
282   member_key = GNUNET_CRYPTO_ecdsa_key_create ();
283   GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
284   
285   char data[] = "Hi, can I enter?";
286   uint8_t data_size = strlen (data) + 1;
287   join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
288   join_msg->size = htons (sizeof (join_msg) + data_size);
289   join_msg->type = htons (123);
290   GNUNET_memcpy (&join_msg[1], data, data_size);
291
292   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
293               "Members tries to join multicast group\n");
294
295   return GNUNET_MULTICAST_member_join (cfg,
296                                        &group_pub_key,
297                                        member_key,
298                                        peer_id[0],
299                                        0,
300                                        NULL,
301                                        join_msg, /* join message */
302                                        member_join_request,
303                                        member_join_decision,
304                                        NULL, /* no test for member_replay_frag */
305                                        NULL, /* no test for member_replay_msg */
306                                        member_message,
307                                        NULL);
308 }
309
310
311 static void
312 peer_information_cb (void *cls,
313                      struct GNUNET_TESTBED_Operation *op,
314                      const struct GNUNET_TESTBED_PeerInformation *pinfo,
315                      const char *emsg)
316 {
317   int i = (int) (long) cls;
318
319   if (NULL == pinfo) {
320     result = GNUNET_SYSERR;
321     GNUNET_SCHEDULER_shutdown ();
322   }
323
324   peer_id[i] = pinfo->result.id;
325
326   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
327               "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
328
329   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
330               "Create member peer\n");
331
332   if (0 == i) {
333   /* connect to multicast service of member */
334   op1 = GNUNET_TESTBED_service_connect (NULL,                    /* Closure for operation */
335                                         peers[1],                /* The peer whose service to connect to */
336                                         "multicast",             /* The name of the service */
337                                         service_connect1,   /* callback to call after a handle to service
338                                                                is opened */
339                                         NULL,                    /* closure for the above callback */
340                                         multicast_ca1,      /* callback to call with peer's configuration;
341                                                                this should open the needed service connection */
342                                         multicast_da1,     /* callback to be called when closing the
343                                                               opened service connection */
344                                         NULL);                   /* closure for the above two callbacks */
345   }
346 }
347
348 /**
349  * Test logic of peer "0" being origin starts here.
350  *
351  * @param cls closure, for the example: NULL
352  * @param op should be equal to "dht_op"
353  * @param ca_result result of the connect operation, the
354  *        connection to the DHT service
355  * @param emsg error message, if testbed somehow failed to
356  *        connect to the DHT.
357  */
358 static void
359 service_connect0 (void *cls,
360                   struct GNUNET_TESTBED_Operation *op,
361                   void *ca_result,
362                   const char *emsg)
363 {
364   origin = ca_result;
365
366   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
367               "Connected to multicast service of origin\n");
368
369   // Get GNUnet identity of origin
370   pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
371                                                GNUNET_TESTBED_PIT_IDENTITY,
372                                                peer_information_cb,
373                                                (void *) 0);
374   // Get GNUnet identity of member
375   pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
376                                                GNUNET_TESTBED_PIT_IDENTITY,
377                                                peer_information_cb,
378                                                (void *) 1);
379
380   /* Connection to service successful. Here we'd usually do something with
381    * the service. */
382   result = GNUNET_OK;
383   //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
384 }
385
386
387
388 /**
389  * Function run when service multicast has started and is providing us
390  * with a configuration file.
391  */
392 static void *
393 multicast_ca0 (void *cls,
394                const struct GNUNET_CONFIGURATION_Handle *cfg)
395 {
396   group_key = GNUNET_CRYPTO_eddsa_key_create ();
397   GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
398
399   return GNUNET_MULTICAST_origin_start (cfg,
400                                         group_key,
401                                         0,
402                                         origin_join_request,
403                                         NULL, /* no test for origin_replay_frag */
404                                         NULL, /* no test for origin_replay_msg */
405                                         origin_request,
406                                         origin_message,
407                                         NULL);
408 }
409
410 static void
411 multicast_da0 (void *cls,
412                void *op_result)
413 {
414   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
415               "Origin closes multicast group\n");
416
417   GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
418 }
419
420
421 /**
422  * Main function inovked from TESTBED once all of the
423  * peers are up and running.  This one then connects
424  * just to the multicast service of peer 0 and 1.
425  * Peer 0 is going to be origin.
426  * Peer 1 is going to be one member.
427  * Origin will start a multicast group and the member will try to join it.
428  * After that we execute some multicast test.
429  *
430  * @param cls closure
431  * @param h the run handle
432  * @param peers started peers for the test
433  * @param num_peers size of the 'peers' array
434  * @param links_succeeded number of links between peers that were created
435  * @param links_failed number of links testbed was unable to establish
436  */
437 static void
438 testbed_master (void *cls,
439      struct GNUNET_TESTBED_RunHandle *h,
440      unsigned int num_peers,
441      struct GNUNET_TESTBED_Peer **p,
442      unsigned int links_succeeded,
443      unsigned int links_failed)
444 {
445   /* Testbed is ready with peers running and connected in a pre-defined overlay
446      topology (FIXME)  */
447   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
448               "Connected to testbed_master()\n");
449
450   peers = p;
451
452   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
453               "Create origin peer\n");
454   op0 = GNUNET_TESTBED_service_connect (NULL,                    /* Closure for operation */
455                                         peers[0],                /* The peer whose service to connect to */
456                                         "multicast",             /* The name of the service */
457                                         service_connect0,   /* callback to call after a handle to service
458                                                                is opened */
459                                         NULL,                    /* closure for the above callback */
460                                         multicast_ca0,      /* callback to call with peer's configuration;
461                                                                this should open the needed service connection */
462                                         multicast_da0,     /* callback to be called when closing the
463                                                               opened service connection */
464                                         NULL);                   /* closure for the above two callbacks */
465
466   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
467
468   /* Schedule the shutdown task with a delay of a few Seconds */
469   timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
470                                               &timeout_task, NULL);
471 }
472
473
474 int
475 main (int argc, char *argv[])
476 {
477   int ret;
478
479   result = GNUNET_SYSERR;
480   ret = GNUNET_TESTBED_test_run
481       ("test-multicast-multipeer",  /* test case name */
482        "test_multicast.conf", /* template configuration */
483        NUM_PEERS,       /* number of peers to start */
484        0LL, /* Event mask - set to 0 for no event notifications */
485        NULL, /* Controller event callback */
486        NULL, /* Closure for controller event callback */
487        testbed_master, /* continuation callback to be called when testbed setup is complete */
488        NULL); /* Closure for the test_master callback */
489   if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
490     return 1;
491   return 0;
492 }
493
494 /* end of test_multicast_multipeer.c */