06df22583e993992c3a922e95b502d6818841722
[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       || 1 == 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       (void) GNUNET_RPS_request_peers (rps, 1, handle_reply, NULL);
322     }
323     return;
324   }
325   #endif /* ENABLE_MALICIOUS */
326
327   if (SINGLE_REQUEST == test_type)
328   {
329     //(void) GNUNET_RPS_request_peers (rps, 1, handle_reply, NULL);
330   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
331                                 request_peers, rps_peer);
332   }
333   else if (DELAYED_REQUESTS == test_type)
334   {
335   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
336                                 request_peers, rps_peer);
337   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
338                                 request_peers, rps_peer);
339   }
340   else if (SEED == test_type)
341   {
342   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
343                                 seed_peers, rps_peer);
344   }
345   else if (SEED_BIG == test_type)
346   {
347   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
348   }
349   else if (SINGLE_PEER_SEED == test_type)
350   {
351   // TODO
352   }
353   else if (SEED_REQUEST == test_type)
354   {
355   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
356                                 seed_peers, rps_peer);
357   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
358                                 request_peers, rps_peer);
359   }
360   else if (REQUEST_CANCEL == test_type)
361   {
362   // TODO
363   }
364 }
365
366
367 /**
368  * Adapter function called to establish a connection to
369  * the RPS service.
370  *
371  * @param cls closure
372  * @param cfg configuration of the peer to connect to; will be available until
373  *          GNUNET_TESTBED_operation_done() is called on the operation returned
374  *          from GNUNET_TESTBED_service_connect()
375  * @return service handle to return in 'op_result', NULL on error
376  */
377 static void *
378 rps_connect_adapter (void *cls,
379                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
380 {
381   struct GNUNET_RPS_Handle *h;
382   #ifdef ENABLE_MALICIOUS
383   uint32_t num_mal_peers;
384   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
385   #endif /* ENABLE_MALICIOUS */
386
387   h = GNUNET_RPS_connect (cfg);
388
389   #ifdef ENABLE_MALICIOUS
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   return h;
407 }
408
409
410 /**
411  * Adapter function called to destroy connection to
412  * RPS service.
413  *
414  * @param cls closure
415  * @param op_result service handle returned from the connect adapter
416  */
417 static void
418 rps_disconnect_adapter (void *cls,
419                                           void *op_result)
420 {
421   struct GNUNET_RPS_Handle *h = op_result;
422   GNUNET_RPS_disconnect (h);
423 }
424
425
426 /**
427  * Actual "main" function for the testcase.
428  *
429  * @param cls closure
430  * @param h the run handle
431  * @param num_peers number of peers in 'peers'
432  * @param peers handle to peers run in the testbed
433  * @param links_succeeded the number of overlay link connection attempts that
434  *          succeeded
435  * @param links_failed the number of overlay link connection attempts that
436  *          failed
437  */
438 static void
439 run (void *cls,
440      struct GNUNET_TESTBED_RunHandle *h,
441      unsigned int num_peers,
442      struct GNUNET_TESTBED_Peer **peers,
443      unsigned int links_succeeded,
444      unsigned int links_failed)
445 {
446   unsigned int i;
447   unsigned int *tmp_i;
448
449   for (i = 0 ; i < NUM_PEERS ; i++)
450   {
451     tmp_i = GNUNET_new (unsigned int);
452     *tmp_i = i;
453
454     (void) GNUNET_TESTBED_peer_get_information (peers[i],
455                                                 GNUNET_TESTBED_PIT_IDENTITY,
456                                                 &info_cb,
457                                                 tmp_i);
458   }
459
460   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
461               "Type %i\n",
462               test_type);
463
464   GNUNET_assert (NUM_PEERS == num_peers);
465   for (i = 0 ; i < num_peers ; i++)
466   {
467     rps_peers[i].index = i;
468     rps_peers[i].op =
469       GNUNET_TESTBED_service_connect (&rps_peers[i],
470                                                                           peers[i],
471                                                                           "rps",
472                                                                           &rps_connect_complete_cb,
473                                                                           &rps_peers[i],
474                                                                           &rps_connect_adapter,
475                                                                           &rps_disconnect_adapter,
476                                                                           &rps_peers[i]);
477   }
478   GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
479 }
480
481
482 /**
483  * Entry point for the testcase, sets up the testbed.
484  *
485  * @param argc unused
486  * @param argv unused
487  * @return 0 on success
488  */
489 int
490 main (int argc, char *argv[])
491 {
492   if (strstr (argv[0], "malicious_1") != NULL)
493   {
494     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
495     mal_type = 1;
496   }
497   else if (strstr (argv[0], "malicious_2") != NULL)
498   {
499     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
500     mal_type = 2;
501   }
502   else if (strstr (argv[0], "_single_req") != NULL)
503   {
504     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
505     test_type = SINGLE_REQUEST;
506   }
507   else if (strstr (argv[0], "_delayed_reqs") != NULL)
508   {
509     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
510     test_type = DELAYED_REQUESTS;
511   }
512   else if (strstr (argv[0], "_seed_big") != NULL)
513   {
514     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
515     test_type = SEED_BIG;
516   }
517   else if (strstr (argv[0], "_single_peer_seed") != NULL)
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
520     test_type = SINGLE_PEER_SEED;
521   }
522   else if (strstr (argv[0], "_seed_request") != NULL)
523   {
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
525     test_type = SEED_REQUEST;
526   }
527   else if (strstr (argv[0], "_seed") != NULL)
528   {
529     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
530     test_type = SEED;
531   }
532   else if (strstr (argv[0], "_req_cancel") != NULL)
533   {
534     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
535     test_type = REQUEST_CANCEL;
536   }
537
538   ok = 1;
539   (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
540                                   "test_rps.conf",
541                                   NUM_PEERS,
542                                   0, NULL, NULL,
543                                   &run, NULL);
544
545   unsigned int num_mal_peers;
546   if (1 == mal_type)
547   {
548     num_mal_peers = NUM_PEERS * portion;
549     ok = evaluate (&rps_peers[num_mal_peers],
550                    NUM_PEERS - (num_mal_peers),
551                    1);
552   }
553   else if (2 == mal_type)
554   {
555     num_mal_peers = NUM_PEERS * portion;
556     ok = evaluate (&rps_peers[num_mal_peers],
557                    NUM_PEERS - (num_mal_peers),
558                    1);
559   }
560   else if (SINGLE_REQUEST == test_type)
561   {
562     ok = evaluate (rps_peers, NUM_PEERS, 1);
563   }
564   else if (SEED_REQUEST == test_type)
565   {
566     ok = evaluate (rps_peers, NUM_PEERS, 1);
567   }
568
569   return ok;
570 }
571
572 /* end of test_rps_multipeer.c */