52684bfde93d5efcba3c4eaf91f0f4fd79e5f262
[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, 40)
44
45
46 /**
47  * Different tests to run
48  */
49 #define SINGLE_REQUEST 1
50 #define DELAYED_REQUESTS 2
51 #define SEED 3
52 #define SEED_BIG 4
53 #define SINGLE_PEER_SEED 5
54 #define SEED_REQUEST 6
55 #define REQUEST_CANCEL 7
56 //TODO start big mal
57
58 /**
59  * What test are we running?
60  */
61 unsigned int test_type = 0;
62
63
64 /**
65  * Portion of malicious peers
66  */
67 static double portion = .1;
68
69 /**
70  * Type of malicious peer to test
71  */
72 static unsigned int mal_type = 0;
73
74
75 /**
76  * Information we track for each peer.
77  */
78 struct RPSPeer
79 {
80   /**
81    * Index of the peer.
82    */
83   unsigned int index;
84
85   /**
86    * Handle for RPS connect operation.
87    */
88   struct GNUNET_TESTBED_Operation *op;
89
90   /**
91    * Handle to RPS service.
92    */
93   struct GNUNET_RPS_Handle *rps_handle;
94
95   /**
96    * ID of the peer.
97    */
98   struct GNUNET_PeerIdentity *peer_id;
99
100   /**
101    * A request handle to check for an request
102    */
103   struct GNUNET_RPS_Request_Handle *req_handle;
104
105   /**
106    * Received PeerIDs
107    */
108   struct GNUNET_PeerIdentity *rec_ids;
109
110   /**
111    * Number of received PeerIDs
112    */
113   unsigned int num_rec_ids;
114 };
115
116
117 /**
118  * Information for all the peers.
119  */
120 static struct RPSPeer rps_peers[NUM_PEERS];
121
122 /**
123  * IDs of the peers.
124  */
125 static struct GNUNET_PeerIdentity rps_peer_ids[NUM_PEERS];
126
127 /**
128  * Return value from 'main'.
129  */
130 static int ok;
131
132
133 /**
134  * Test the success of a single test
135  */
136 static int
137 evaluate (struct RPSPeer *loc_rps_peers,
138           unsigned int num_loc_rps_peers,
139           unsigned int expected_recv)
140 {
141   unsigned int i;
142   int tmp_ok;
143
144   tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
145
146   for (i = 0 ; i < num_loc_rps_peers ; i++)
147   {
148     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149                 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
150                 i,
151                 GNUNET_i2s (loc_rps_peers[i].peer_id),
152                 loc_rps_peers[i].num_rec_ids,
153                 expected_recv,
154                 (1 == loc_rps_peers[i].num_rec_ids));
155     tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
156   }
157   return tmp_ok? 0 : 1;
158 }
159
160
161 /**
162  * Task run on timeout to shut everything down.
163  */
164 static void
165 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
166 {
167   unsigned int i;
168
169   for (i=0;i<NUM_PEERS;i++)
170     GNUNET_TESTBED_operation_done (rps_peers[i].op);
171   GNUNET_SCHEDULER_shutdown ();
172 }
173
174
175 /**
176  * Callback to call when network size estimate is updated.
177  *
178  * @param cls closure
179  * @param timestamp server timestamp
180  * @param estimate the value of the current network size estimate
181  * @param std_dev standard deviation (rounded down to nearest integer)
182  *                of the size estimation values seen
183  *
184  */
185 static void
186 handle_reply (void *cls, uint64_t n, const struct GNUNET_PeerIdentity *recv_peers)
187 {
188   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
189   unsigned int i;
190
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192               "[%s] got %" PRIu64 " peers:\n",
193               GNUNET_i2s (rps_peer->peer_id),
194               n);
195   
196   for (i = 0 ; i < n ; i++)
197   {
198     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
199                 "%u: %s\n",
200                 i,
201                 GNUNET_i2s (&recv_peers[i]));
202
203     GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
204   }
205 }
206
207
208 /**
209  * (Randomly) request random peers.
210  */
211   void
212 request_peers (void *cls,
213                const struct GNUNET_SCHEDULER_TaskContext *tc)
214 {
215   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
216
217   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218               "Requesting one peer\n");
219
220   (void) GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
221   //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
222 }
223
224
225 /**
226  * Seed peers.
227  */
228   void
229 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
230 {
231   unsigned int amount;
232   struct RPSPeer *peer = (struct RPSPeer *) cls;
233   unsigned int i;
234
235   // TODO if malicious don't seed mal peers
236   amount = round (.5 * NUM_PEERS);
237
238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
239   for (i = 0 ; i < amount ; i++)
240     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
241                 i,
242                 GNUNET_i2s (&rps_peer_ids[i]));
243
244   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
245 }
246
247
248 /**
249  * Get the id of peer i.
250  */
251   void
252 info_cb (void *cb_cls,
253          struct GNUNET_TESTBED_Operation *op,
254          const struct GNUNET_TESTBED_PeerInformation *pinfo,
255          const char *emsg)
256 {
257   unsigned int i = *((unsigned int *) cb_cls);
258
259   if (NULL == pinfo || NULL != emsg)
260   {
261     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
262     return;
263   }
264
265   GNUNET_free (cb_cls);
266
267   rps_peer_ids[i] = *(pinfo->result.id);
268   rps_peers[i].peer_id = &rps_peer_ids[i];
269   rps_peers[i].rec_ids = NULL;
270   rps_peers[i].num_rec_ids = 0;
271
272 }
273
274
275 /**
276  * Callback to be called when RPS service connect operation is completed
277  *
278  * @param cls the callback closure from functions generating an operation
279  * @param op the operation that has been finished
280  * @param ca_result the RPS service handle returned from rps_connect_adapter
281  * @param emsg error message in case the operation has failed; will be NULL if
282  *          operation has executed successfully.
283  */
284 static void
285 rps_connect_complete_cb (void *cls,
286                          struct GNUNET_TESTBED_Operation *op,
287                          void *ca_result,
288                          const char *emsg)
289 {
290   struct RPSPeer *rps_peer = cls;
291   struct GNUNET_RPS_Handle *rps = ca_result;
292   //struct GNUNET_RPS_Request_Handle *req_handle;
293   uint32_t num_mal_peers;
294
295   rps_peer->rps_handle = rps;
296
297   GNUNET_assert (op == rps_peer->op);
298   if (NULL != emsg)
299   {
300     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301                 "Failed to connect to RPS service: %s\n",
302                 emsg);
303     ok = 1;
304     GNUNET_SCHEDULER_shutdown ();
305     return;
306   }
307
308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
309
310   #ifdef ENABLE_MALICIOUS
311   if (1 == mal_type
312       || 2 == mal_type)
313   {
314     GNUNET_assert (1 >= portion
315                    && 0 <  portion);
316     num_mal_peers = round (portion * NUM_PEERS);
317
318     if (rps_peer->index >= num_mal_peers)
319     { /* It's useless to ask a malicious peer about a random sample -
320          it's not sampling */
321       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
322                                     seed_peers, rps_peer);
323       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
324                                     request_peers, rps_peer);
325     }
326   }
327   #endif /* ENABLE_MALICIOUS */
328
329   if (SINGLE_REQUEST == test_type)
330   {
331     //(void) GNUNET_RPS_request_peers (rps, 1, handle_reply, NULL);
332   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
333                                 request_peers, rps_peer);
334   }
335   else if (DELAYED_REQUESTS == test_type)
336   {
337   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
338                                 request_peers, rps_peer);
339   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
340                                 request_peers, rps_peer);
341   }
342   else if (SEED == test_type)
343   {
344   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
345                                 seed_peers, rps_peer);
346   }
347   else if (SEED_BIG == test_type)
348   {
349   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
350   }
351   else if (SINGLE_PEER_SEED == test_type)
352   {
353   // TODO
354   }
355   else if (SEED_REQUEST == test_type)
356   {
357     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
358                                   seed_peers, rps_peer);
359     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
360                                   request_peers, rps_peer);
361   }
362   else if (REQUEST_CANCEL == test_type)
363   {
364   // TODO
365   }
366 }
367
368
369 /**
370  * Adapter function called to establish a connection to
371  * the RPS service.
372  *
373  * @param cls closure
374  * @param cfg configuration of the peer to connect to; will be available until
375  *          GNUNET_TESTBED_operation_done() is called on the operation returned
376  *          from GNUNET_TESTBED_service_connect()
377  * @return service handle to return in 'op_result', NULL on error
378  */
379 static void *
380 rps_connect_adapter (void *cls,
381                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
382 {
383   struct GNUNET_RPS_Handle *h;
384   #ifdef ENABLE_MALICIOUS
385   uint32_t num_mal_peers;
386   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
387   #endif /* ENABLE_MALICIOUS */
388
389   h = GNUNET_RPS_connect (cfg);
390
391   #ifdef ENABLE_MALICIOUS
392   GNUNET_assert (1 >= portion
393                  && 0 <  portion);
394   num_mal_peers = round (portion * NUM_PEERS);
395
396   if (rps_peer->index < num_mal_peers)
397   {
398     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
400                 rps_peer->index,
401                 GNUNET_i2s (rps_peer->peer_id),
402                 num_mal_peers);
403
404     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
405   }
406   #endif /* ENABLE_MALICIOUS */
407
408   return h;
409 }
410
411
412 /**
413  * Adapter function called to destroy connection to
414  * RPS service.
415  *
416  * @param cls closure
417  * @param op_result service handle returned from the connect adapter
418  */
419 static void
420 rps_disconnect_adapter (void *cls,
421                                           void *op_result)
422 {
423   struct GNUNET_RPS_Handle *h = op_result;
424   GNUNET_RPS_disconnect (h);
425 }
426
427
428 /**
429  * Actual "main" function for the testcase.
430  *
431  * @param cls closure
432  * @param h the run handle
433  * @param num_peers number of peers in 'peers'
434  * @param peers handle to peers run in the testbed
435  * @param links_succeeded the number of overlay link connection attempts that
436  *          succeeded
437  * @param links_failed the number of overlay link connection attempts that
438  *          failed
439  */
440 static void
441 run (void *cls,
442      struct GNUNET_TESTBED_RunHandle *h,
443      unsigned int num_peers,
444      struct GNUNET_TESTBED_Peer **peers,
445      unsigned int links_succeeded,
446      unsigned int links_failed)
447 {
448   unsigned int i;
449   unsigned int *tmp_i;
450
451   for (i = 0 ; i < NUM_PEERS ; i++)
452   {
453     tmp_i = GNUNET_new (unsigned int);
454     *tmp_i = i;
455
456     (void) GNUNET_TESTBED_peer_get_information (peers[i],
457                                                 GNUNET_TESTBED_PIT_IDENTITY,
458                                                 &info_cb,
459                                                 tmp_i);
460   }
461
462   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
463               "Type %i\n",
464               test_type);
465
466   GNUNET_assert (NUM_PEERS == num_peers);
467   for (i = 0 ; i < num_peers ; i++)
468   {
469     rps_peers[i].index = i;
470     rps_peers[i].op =
471       GNUNET_TESTBED_service_connect (&rps_peers[i],
472                                                                           peers[i],
473                                                                           "rps",
474                                                                           &rps_connect_complete_cb,
475                                                                           &rps_peers[i],
476                                                                           &rps_connect_adapter,
477                                                                           &rps_disconnect_adapter,
478                                                                           &rps_peers[i]);
479   }
480   GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
481 }
482
483
484 /**
485  * Entry point for the testcase, sets up the testbed.
486  *
487  * @param argc unused
488  * @param argv unused
489  * @return 0 on success
490  */
491 int
492 main (int argc, char *argv[])
493 {
494   if (strstr (argv[0], "malicious_1") != NULL)
495   {
496     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
497     mal_type = 1;
498   }
499   else if (strstr (argv[0], "malicious_2") != NULL)
500   {
501     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
502     mal_type = 2;
503   }
504   else if (strstr (argv[0], "_single_req") != NULL)
505   {
506     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
507     test_type = SINGLE_REQUEST;
508   }
509   else if (strstr (argv[0], "_delayed_reqs") != NULL)
510   {
511     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
512     test_type = DELAYED_REQUESTS;
513   }
514   else if (strstr (argv[0], "_seed_big") != NULL)
515   {
516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
517     test_type = SEED_BIG;
518   }
519   else if (strstr (argv[0], "_single_peer_seed") != NULL)
520   {
521     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
522     test_type = SINGLE_PEER_SEED;
523   }
524   else if (strstr (argv[0], "_seed_request") != NULL)
525   {
526     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
527     test_type = SEED_REQUEST;
528   }
529   else if (strstr (argv[0], "_seed") != NULL)
530   {
531     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
532     test_type = SEED;
533   }
534   else if (strstr (argv[0], "_req_cancel") != NULL)
535   {
536     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
537     test_type = REQUEST_CANCEL;
538   }
539
540   ok = 1;
541   (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
542                                   "test_rps.conf",
543                                   NUM_PEERS,
544                                   0, NULL, NULL,
545                                   &run, NULL);
546
547   unsigned int num_mal_peers;
548   if (1 == mal_type)
549   {
550     num_mal_peers = round (NUM_PEERS * portion);
551     ok = evaluate (&rps_peers[num_mal_peers],
552                    NUM_PEERS - (num_mal_peers),
553                    1);
554   }
555   else if (2 == mal_type)
556   {
557     num_mal_peers = round (NUM_PEERS * portion);
558     ok = evaluate (&rps_peers[num_mal_peers],
559                    NUM_PEERS - (num_mal_peers),
560                    1);
561   }
562   else if (SINGLE_REQUEST == test_type)
563   {
564     ok = evaluate (rps_peers, NUM_PEERS, 1);
565   }
566   else if (SEED_REQUEST == test_type)
567   {
568     ok = evaluate (rps_peers, NUM_PEERS, 1);
569   }
570
571   return ok;
572 }
573
574 /* end of test_rps_multipeer.c */