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