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