d1b7f9eaacd8ce051313a12b500f4ce73d86db51
[oweals/gnunet.git] / src / rps / test_rps.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file rps/test_rps_multipeer.c
22  * @brief Testcase for the random peer sampling service.  Starts
23  *        a peergroup with a given number of peers, then waits to
24  *        receive size pushes/pulls from each peer.  Expects to wait
25  *        for one message from each peer.
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testbed_service.h"
30 #include "gnunet_rps_service.h"
31
32 #include <inttypes.h>
33
34
35 /**
36  * How many peers do we start?
37  */
38 #define NUM_PEERS 5
39
40 /**
41  * How long do we run the test?
42  */
43 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
44
45
46 /**
47  * Portion of malicious peers
48  */
49 static double portion = .1;
50
51 /**
52  * Type of malicious peer to test
53  */
54 static unsigned int mal_type = 0;
55
56
57 /**
58  * Information we track for each peer.
59  */
60 struct RPSPeer
61 {
62   /**
63    * Index of the peer.
64    */
65   unsigned int index;
66
67   /**
68    * Handle for RPS connect operation.
69    */
70   struct GNUNET_TESTBED_Operation *op;
71
72   /**
73    * Handle to RPS service.
74    */
75   struct GNUNET_RPS_Handle *rps_handle;
76
77   /**
78    * ID of the peer.
79    */
80   struct GNUNET_PeerIdentity *peer_id;
81
82   /**
83    * A request handle to check for an request
84    */
85   //struct GNUNET_RPS_Request_Handle *req_handle;
86
87   /**
88    * Received PeerIDs
89    */
90   struct GNUNET_PeerIdentity *rec_ids;
91
92   /**
93    * Number of received PeerIDs
94    */
95   unsigned int num_rec_ids;
96 };
97
98
99 /**
100  * Information for all the peers.
101  */
102 static struct RPSPeer rps_peers[NUM_PEERS];
103
104 /**
105  * IDs of the peers.
106  */
107 static struct GNUNET_PeerIdentity rps_peer_ids[NUM_PEERS];
108
109 /**
110  * Return value from 'main'.
111  */
112 static int ok;
113
114
115 /**
116  * Called directly after connecting to the service
117  */
118 typedef void (*PreTest) (void *cls, struct GNUNET_RPS_Handle *h);
119
120 /**
121  * Called from within #rps_connect_complete_cb ()
122  * Executes functions to test the api/service
123  */
124 typedef void (*MainTest) (struct RPSPeer *rps_peer);
125
126 /**
127  * Function called after disconnect to evaluate test success
128  */
129 typedef int (*EvaluationCallback) (void);
130
131
132 /**
133  * Structure to define a single test
134  */
135 struct SingleTestRun
136 {
137   /**
138    * Called directly after connecting to the service
139    */
140   PreTest pre_test;
141
142   /**
143    * Function to execute the functions to be tested
144    */
145   MainTest main_test;
146
147   /**
148    * Function to evaluate the test results
149    */
150   EvaluationCallback eval_cb;
151 } cur_test_run;
152
153
154 /**
155  * Test the success of a single test
156  */
157 static int
158 evaluate (struct RPSPeer *loc_rps_peers,
159           unsigned int num_loc_rps_peers,
160           unsigned int expected_recv)
161 {
162   unsigned int i;
163   int tmp_ok;
164
165   tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
166
167   for (i = 0 ; i < num_loc_rps_peers ; i++)
168   {
169     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170                 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
171                 i,
172                 GNUNET_i2s (loc_rps_peers[i].peer_id),
173                 loc_rps_peers[i].num_rec_ids,
174                 expected_recv,
175                 (1 == loc_rps_peers[i].num_rec_ids));
176     tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
177   }
178   return tmp_ok? 0 : 1;
179 }
180
181
182 /**
183  * Task run on timeout to shut everything down.
184  */
185 static void
186 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
187 {
188   unsigned int i;
189
190   for (i=0;i<NUM_PEERS;i++)
191     GNUNET_TESTBED_operation_done (rps_peers[i].op);
192   GNUNET_SCHEDULER_shutdown ();
193 }
194
195
196 /**
197  * Callback to call on receipt of a reply
198  *
199  * @param cls closure
200  * @param n number of peers
201  * @param recv_peers the received peers
202  */
203 static void
204 handle_reply (void *cls, uint64_t n, const struct GNUNET_PeerIdentity *recv_peers)
205 {
206   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
207   unsigned int i;
208
209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210               "[%s] got %" PRIu64 " peers:\n",
211               GNUNET_i2s (rps_peer->peer_id),
212               n);
213   
214   for (i = 0 ; i < n ; i++)
215   {
216     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
217                 "%u: %s\n",
218                 i,
219                 GNUNET_i2s (&recv_peers[i]));
220
221     GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
222   }
223 }
224
225
226 /**
227  * Request random peers.
228  */
229   void
230 request_peers (void *cls,
231                const struct GNUNET_SCHEDULER_TaskContext *tc)
232 {
233   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
234
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236               "Requesting one peer\n");
237
238   (void) GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
239   //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
240 }
241
242
243 /**
244  * Seed peers.
245  */
246   void
247 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
248 {
249   unsigned int amount;
250   struct RPSPeer *peer = (struct RPSPeer *) cls;
251   unsigned int i;
252
253   // TODO if malicious don't seed mal peers
254   amount = round (.5 * NUM_PEERS);
255
256   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
257   for (i = 0 ; i < amount ; i++)
258     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
259                 i,
260                 GNUNET_i2s (&rps_peer_ids[i]));
261
262   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
263 }
264
265
266 /**
267  * Get the id of peer i.
268  */
269   void
270 info_cb (void *cb_cls,
271          struct GNUNET_TESTBED_Operation *op,
272          const struct GNUNET_TESTBED_PeerInformation *pinfo,
273          const char *emsg)
274 {
275   unsigned int i = *((unsigned int *) cb_cls);
276
277   if (NULL == pinfo || NULL != emsg)
278   {
279     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
280     return;
281   }
282
283   GNUNET_free (cb_cls);
284
285   rps_peer_ids[i] = *(pinfo->result.id);
286   rps_peers[i].peer_id = &rps_peer_ids[i];
287   rps_peers[i].rec_ids = NULL;
288   rps_peers[i].num_rec_ids = 0;
289
290 }
291
292
293 /**
294  * Callback to be called when RPS service connect operation is completed
295  *
296  * @param cls the callback closure from functions generating an operation
297  * @param op the operation that has been finished
298  * @param ca_result the RPS service handle returned from rps_connect_adapter
299  * @param emsg error message in case the operation has failed; will be NULL if
300  *          operation has executed successfully.
301  */
302 static void
303 rps_connect_complete_cb (void *cls,
304                          struct GNUNET_TESTBED_Operation *op,
305                          void *ca_result,
306                          const char *emsg)
307 {
308   struct RPSPeer *rps_peer = cls;
309   struct GNUNET_RPS_Handle *rps = ca_result;
310
311   rps_peer->rps_handle = rps;
312
313   GNUNET_assert (op == rps_peer->op);
314   if (NULL != emsg)
315   {
316     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317                 "Failed to connect to RPS service: %s\n",
318                 emsg);
319     ok = 1;
320     GNUNET_SCHEDULER_shutdown ();
321     return;
322   }
323
324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
325
326   cur_test_run.main_test (rps_peer);
327 }
328
329
330 /**
331  * Adapter function called to establish a connection to
332  * the RPS service.
333  *
334  * @param cls closure
335  * @param cfg configuration of the peer to connect to; will be available until
336  *          GNUNET_TESTBED_operation_done() is called on the operation returned
337  *          from GNUNET_TESTBED_service_connect()
338  * @return service handle to return in 'op_result', NULL on error
339  */
340 static void *
341 rps_connect_adapter (void *cls,
342                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
343 {
344   struct GNUNET_RPS_Handle *h;
345
346   h = GNUNET_RPS_connect (cfg);
347
348   if (NULL != cur_test_run.pre_test)
349     cur_test_run.pre_test (cls, h);
350
351   return h;
352 }
353
354
355 /**
356  * Adapter function called to destroy connection to
357  * RPS service.
358  *
359  * @param cls closure
360  * @param op_result service handle returned from the connect adapter
361  */
362 static void
363 rps_disconnect_adapter (void *cls,
364                                           void *op_result)
365 {
366   struct GNUNET_RPS_Handle *h = op_result;
367   GNUNET_RPS_disconnect (h);
368 }
369
370
371 /***********************************************************************
372  * Definition of tests
373 ***********************************************************************/
374
375 static int
376 default_eval_cb (void)
377 {
378   return evaluate (rps_peers, NUM_PEERS, 1);
379 }
380 /***********************************
381  * MALICIOUS
382 ***********************************/
383 static void
384 mal_pre (void *cls, struct GNUNET_RPS_Handle *h)
385 {
386   #ifdef ENABLE_MALICIOUS
387   uint32_t num_mal_peers;
388   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
389
390   GNUNET_assert (1 >= portion
391                  && 0 <  portion);
392   num_mal_peers = round (portion * NUM_PEERS);
393
394   if (rps_peer->index < num_mal_peers)
395   {
396     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
398                 rps_peer->index,
399                 GNUNET_i2s (rps_peer->peer_id),
400                 num_mal_peers);
401
402     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
403   }
404   #endif /* ENABLE_MALICIOUS */
405 }
406
407 static void
408 mal_cb (struct RPSPeer *rps_peer)
409 {
410   uint32_t num_mal_peers;
411
412   #ifdef ENABLE_MALICIOUS
413   GNUNET_assert (1 >= portion
414                  && 0 <  portion);
415   num_mal_peers = round (portion * NUM_PEERS);
416
417   if (rps_peer->index >= num_mal_peers)
418   { /* It's useless to ask a malicious peer about a random sample -
419        it's not sampling */
420     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
421                                   seed_peers, rps_peer);
422     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
423                                   request_peers, rps_peer);
424   }
425   #endif /* ENABLE_MALICIOUS */
426 }
427
428 static int
429 mal_eval (void)
430 {
431   unsigned int num_mal_peers;
432
433   num_mal_peers = round (NUM_PEERS * portion);
434   return evaluate (&rps_peers[num_mal_peers],
435                    NUM_PEERS - (num_mal_peers),
436                    1);
437 }
438
439
440 /***********************************
441  * SINGLE_REQUEST
442 ***********************************/
443 static void
444 single_req_cb (struct RPSPeer *rps_peer)
445 {
446   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
447                                 request_peers, rps_peer);
448 }
449
450 /***********************************
451  * DELAYED_REQUESTS
452 ***********************************/
453 static void
454 delay_req_cb (struct RPSPeer *rps_peer)
455 {
456   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
457                                 request_peers, rps_peer);
458   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
459                                 request_peers, rps_peer);
460 }
461
462 /***********************************
463  * SEED
464 ***********************************/
465 static void
466 seed_cb (struct RPSPeer *rps_peer)
467 {
468   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
469                                 seed_peers, rps_peer);
470 }
471
472 static int
473 seed_eval (void)
474 {
475   return 1;
476 }
477
478 /***********************************
479  * SEED_BIG
480 ***********************************/
481 static void
482 seed_big_cb (struct RPSPeer *rps_peer)
483 {
484   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
485 }
486
487 /***********************************
488  * SINGLE_PEER_SEED
489 ***********************************/
490 static void
491 single_peer_seed_cb (struct RPSPeer *rps_peer)
492 {
493   // TODO
494 }
495
496 /***********************************
497  * SEED_REQUEST
498 ***********************************/
499 static void
500 seed_req_cb (struct RPSPeer *rps_peer)
501 {
502   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
503                                 seed_peers, rps_peer);
504   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
505                                 request_peers, rps_peer);
506 }
507
508 //TODO start big mal
509
510 /***********************************
511  * REQUEST_CANCEL
512 ***********************************/
513 static void
514 req_cancel_cb (struct RPSPeer *rps_peer)
515 {
516   // TODO
517 }
518
519 /***********************************************************************
520  * /Definition of tests
521 ***********************************************************************/
522
523
524 /**
525  * Actual "main" function for the testcase.
526  *
527  * @param cls closure
528  * @param h the run handle
529  * @param num_peers number of peers in 'peers'
530  * @param peers handle to peers run in the testbed
531  * @param links_succeeded the number of overlay link connection attempts that
532  *          succeeded
533  * @param links_failed the number of overlay link connection attempts that
534  *          failed
535  */
536 static void
537 run (void *cls,
538      struct GNUNET_TESTBED_RunHandle *h,
539      unsigned int num_peers,
540      struct GNUNET_TESTBED_Peer **peers,
541      unsigned int links_succeeded,
542      unsigned int links_failed)
543 {
544   unsigned int i;
545   unsigned int *tmp_i;
546
547   for (i = 0 ; i < NUM_PEERS ; i++)
548   {
549     tmp_i = GNUNET_new (unsigned int);
550     *tmp_i = i;
551
552     (void) GNUNET_TESTBED_peer_get_information (peers[i],
553                                                 GNUNET_TESTBED_PIT_IDENTITY,
554                                                 &info_cb,
555                                                 tmp_i);
556   }
557
558   GNUNET_assert (NUM_PEERS == num_peers);
559   for (i = 0 ; i < num_peers ; i++)
560   {
561     rps_peers[i].index = i;
562     rps_peers[i].op =
563       GNUNET_TESTBED_service_connect (&rps_peers[i],
564                                                                           peers[i],
565                                                                           "rps",
566                                                                           &rps_connect_complete_cb,
567                                                                           &rps_peers[i],
568                                                                           &rps_connect_adapter,
569                                                                           &rps_disconnect_adapter,
570                                                                           &rps_peers[i]);
571   }
572   GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
573 }
574
575
576 /**
577  * Entry point for the testcase, sets up the testbed.
578  *
579  * @param argc unused
580  * @param argv unused
581  * @return 0 on success
582  */
583 int
584 main (int argc, char *argv[])
585 {
586   cur_test_run.pre_test = NULL;
587   cur_test_run.eval_cb = default_eval_cb;
588
589   if (strstr (argv[0], "malicious") != NULL)
590   {
591     cur_test_run.pre_test = mal_pre;
592     cur_test_run.main_test = mal_cb;
593     cur_test_run.eval_cb = mal_eval;
594
595     if (strstr (argv[0], "_1") != NULL)
596     {
597       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
598       mal_type = 1;
599     }
600     else if (strstr (argv[0], "_2") != NULL)
601     {
602       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
603       mal_type = 2;
604     }
605     else if (strstr (argv[0], "_3") != NULL)
606     {
607       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
608       mal_type = 3;
609     }
610   }
611
612   else if (strstr (argv[0], "_single_req") != NULL)
613   {
614     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
615     cur_test_run.main_test = single_req_cb;
616   }
617   else if (strstr (argv[0], "_delayed_reqs") != NULL)
618   {
619     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
620     cur_test_run.main_test = delay_req_cb;
621   }
622   else if (strstr (argv[0], "_seed_big") != NULL)
623   {
624     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
625     cur_test_run.main_test = seed_big_cb;
626   }
627   else if (strstr (argv[0], "_single_peer_seed") != NULL)
628   {
629     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
630     cur_test_run.main_test = single_peer_seed_cb;
631   }
632   else if (strstr (argv[0], "_seed_request") != NULL)
633   {
634     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
635     cur_test_run.main_test = seed_req_cb;
636   }
637   else if (strstr (argv[0], "_seed") != NULL)
638   {
639     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
640     cur_test_run.main_test = seed_cb;
641     cur_test_run.eval_cb = seed_eval;
642   }
643   else if (strstr (argv[0], "_req_cancel") != NULL)
644   {
645     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
646     cur_test_run.main_test = req_cancel_cb;
647   }
648
649   ok = 1;
650   (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
651                                   "test_rps.conf",
652                                   NUM_PEERS,
653                                   0, NULL, NULL,
654                                   &run, NULL);
655
656   return cur_test_run.eval_cb();
657 }
658
659 /* end of test_rps_multipeer.c */