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