-unified testing
[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_testbed_service.h"
29 #include "gnunet_rps_service.h"
30
31 #include <inttypes.h>
32
33
34 /**
35  * How many peers do we start?
36  */
37 #define NUM_PEERS 5
38
39 /**
40  * How long do we run the test?
41  */
42 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
43
44
45 /**
46  * Portion of malicious peers
47  */
48 static double portion = .1;
49
50 /**
51  * Type of malicious peer to test
52  */
53 static unsigned int mal_type = 0;
54
55
56 /**
57  * Information we track for each peer.
58  */
59 struct RPSPeer
60 {
61   /**
62    * Index of the peer.
63    */
64   unsigned int index;
65
66   /**
67    * Handle for RPS connect operation.
68    */
69   struct GNUNET_TESTBED_Operation *op;
70
71   /**
72    * Handle to RPS service.
73    */
74   struct GNUNET_RPS_Handle *rps_handle;
75
76   /**
77    * ID of the peer.
78    */
79   struct GNUNET_PeerIdentity *peer_id;
80 };
81
82
83 /**
84  * Information for all the peers.
85  */
86 static struct RPSPeer rps_peers[NUM_PEERS];
87
88 /**
89  * IDs of the peers.
90  */
91 static struct GNUNET_PeerIdentity rps_peer_ids[NUM_PEERS];
92
93 /**
94  * Return value from 'main'.
95  */
96 static int ok;
97
98
99 /**
100  * Task run on timeout to shut everything down.
101  */
102 static void
103 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
104 {
105   unsigned int i;
106
107   for (i=0;i<NUM_PEERS;i++)
108     GNUNET_TESTBED_operation_done (rps_peers[i].op);
109   GNUNET_SCHEDULER_shutdown ();
110 }
111
112
113 /**
114  * Callback to call when network size estimate is updated.
115  *
116  * @param cls closure
117  * @param timestamp server timestamp
118  * @param estimate the value of the current network size estimate
119  * @param std_dev standard deviation (rounded down to nearest integer)
120  *                of the size estimation values seen
121  *
122  */
123 static void
124 handle_reply (void *cls, uint64_t n, const struct GNUNET_PeerIdentity *peers)
125 {
126   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got peer %s\n", GNUNET_i2s (peers));
127   
128   ok = 0;
129 }
130
131
132 /**
133  * (Randomly) request random peers.
134  */
135   void
136 request_peers (void *cls,
137                const struct GNUNET_SCHEDULER_TaskContext *tc)
138 {
139   struct RPSPeer *peer = (struct RPSPeer *) cls;
140   struct GNUNET_RPS_Request_Handle *req_handle;
141
142   req_handle = GNUNET_RPS_request_peers (peer->rps_handle, 1, handle_reply, NULL);
143   GNUNET_free (req_handle);
144 }
145
146
147 /**
148  * Seed peers.
149  */
150   void
151 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
152 {
153   unsigned int amount;
154   struct RPSPeer *peer = (struct RPSPeer *) cls;
155   unsigned int i;
156
157   GNUNET_assert (1 >= portion
158                  && 0 <  portion);
159                 
160   amount = round (portion * NUM_PEERS);
161
162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
163   for (i = 0 ; i < amount ; i++)
164     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
165                 i,
166                 GNUNET_i2s (&rps_peer_ids[i]));
167
168   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
169 }
170
171
172 /**
173  * Get the id of peer i.
174  */
175   void
176 info_cb (void *cb_cls,
177          struct GNUNET_TESTBED_Operation *op,
178          const struct GNUNET_TESTBED_PeerInformation *pinfo,
179          const char *emsg)
180 {
181   unsigned int i = *((unsigned int *) cb_cls);
182
183   if (NULL == pinfo || NULL != emsg)
184   {
185     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
186     return;
187   }
188
189   GNUNET_free (cb_cls);
190
191   rps_peer_ids[i] = *(pinfo->result.id);
192   rps_peers[i].peer_id = &rps_peer_ids[i];
193
194 }
195
196
197 /**
198  * Callback to be called when RPS service connect operation is completed
199  *
200  * @param cls the callback closure from functions generating an operation
201  * @param op the operation that has been finished
202  * @param ca_result the RPS service handle returned from rps_connect_adapter
203  * @param emsg error message in case the operation has failed; will be NULL if
204  *          operation has executed successfully.
205  */
206 static void
207 rps_connect_complete_cb (void *cls,
208                          struct GNUNET_TESTBED_Operation *op,
209                          void *ca_result,
210                          const char *emsg)
211 {
212   struct RPSPeer *rps_peer = cls;
213   struct GNUNET_RPS_Handle *rps = ca_result;
214   struct GNUNET_RPS_Request_Handle *req_handle;
215   uint32_t num_mal_peers;
216
217   rps_peer->rps_handle = rps;
218
219   GNUNET_assert (op == rps_peer->op);
220   if (NULL != emsg)
221   {
222     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223                 "Failed to connect to RPS service: %s\n",
224                 emsg);
225     ok = 1;
226     GNUNET_SCHEDULER_shutdown ();
227     return;
228   }
229
230   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
231
232   #ifdef ENABLE_MALICIOUS
233   if (1 == mal_type
234       || 1 == mal_type)
235   {
236     GNUNET_assert (1 >= portion
237                    && 0 <  portion);
238     num_mal_peers = round (portion * NUM_PEERS);
239
240     if (rps_peer->index >= num_mal_peers)
241     { /* It's useless to ask a malicious peer about a random sample -
242          it's not sampling */
243       req_handle = GNUNET_RPS_request_peers (rps, 1, handle_reply, NULL);
244       GNUNET_free (req_handle);
245     }
246     return;
247   }
248   #endif /* ENABLE_MALICIOUS */
249
250   req_handle = GNUNET_RPS_request_peers (rps, 1, handle_reply, NULL);
251   GNUNET_free (req_handle);
252   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
253                                 request_peers, rps_peer);
254   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
255                                 seed_peers, rps_peer);
256   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
257 }
258
259
260 /**
261  * Adapter function called to establish a connection to
262  * the RPS service.
263  *
264  * @param cls closure
265  * @param cfg configuration of the peer to connect to; will be available until
266  *          GNUNET_TESTBED_operation_done() is called on the operation returned
267  *          from GNUNET_TESTBED_service_connect()
268  * @return service handle to return in 'op_result', NULL on error
269  */
270 static void *
271 rps_connect_adapter (void *cls,
272                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
273 {
274   struct GNUNET_RPS_Handle *h;
275   #ifdef ENABLE_MALICIOUS
276   uint32_t num_mal_peers;
277   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
278   #endif /* ENABLE_MALICIOUS */
279
280   h = GNUNET_RPS_connect (cfg);
281
282   #ifdef ENABLE_MALICIOUS
283   GNUNET_assert (1 >= portion
284                  && 0 <  portion);
285   num_mal_peers = round (portion * NUM_PEERS);
286
287   if (rps_peer->index < num_mal_peers)
288   {
289     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
290                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
291                 rps_peer->index,
292                 GNUNET_i2s (rps_peer->peer_id),
293                 num_mal_peers);
294
295     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
296   }
297   #endif /* ENABLE_MALICIOUS */
298
299   return h;
300 }
301
302
303 /**
304  * Adapter function called to destroy connection to
305  * RPS service.
306  *
307  * @param cls closure
308  * @param op_result service handle returned from the connect adapter
309  */
310 static void
311 rps_disconnect_adapter (void *cls,
312                                           void *op_result)
313 {
314   struct GNUNET_RPS_Handle *h = op_result;
315   GNUNET_RPS_disconnect (h);
316 }
317
318
319 /**
320  * Actual "main" function for the testcase.
321  *
322  * @param cls closure
323  * @param h the run handle
324  * @param num_peers number of peers in 'peers'
325  * @param peers handle to peers run in the testbed
326  * @param links_succeeded the number of overlay link connection attempts that
327  *          succeeded
328  * @param links_failed the number of overlay link connection attempts that
329  *          failed
330  */
331 static void
332 run (void *cls,
333      struct GNUNET_TESTBED_RunHandle *h,
334      unsigned int num_peers,
335      struct GNUNET_TESTBED_Peer **peers,
336      unsigned int links_succeeded,
337      unsigned int links_failed)
338 {
339   unsigned int i;
340   unsigned int *tmp_i;
341
342   for (i = 0 ; i < NUM_PEERS ; i++)
343   {
344     tmp_i = GNUNET_new (unsigned int);
345     *tmp_i = i;
346
347     (void) GNUNET_TESTBED_peer_get_information (peers[i],
348                                                 GNUNET_TESTBED_PIT_IDENTITY,
349                                                 &info_cb,
350                                                 tmp_i);
351   }
352
353
354   GNUNET_assert (NUM_PEERS == num_peers);
355   for (i = 0 ; i < num_peers ; i++)
356   {
357     rps_peers[i].index = i;
358     rps_peers[i].op =
359       GNUNET_TESTBED_service_connect (&rps_peers[i],
360                                                                           peers[i],
361                                                                           "rps",
362                                                                           &rps_connect_complete_cb,
363                                                                           &rps_peers[i],
364                                                                           &rps_connect_adapter,
365                                                                           &rps_disconnect_adapter,
366                                                                           &rps_peers[i]);
367   }
368   GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
369 }
370
371
372 /**
373  * Entry point for the testcase, sets up the testbed.
374  *
375  * @param argc unused
376  * @param argv unused
377  * @return 0 on success
378  */
379 int
380 main (int argc, char *argv[])
381 {
382   if (strstr (argv[0], "malicious_1") != NULL)
383   {
384     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Malicious type 1\n");
385                 mal_type = 1;
386   }
387   else if (strstr (argv[0], "malicious_2") != NULL)
388   {
389     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Malicious type 2\n");
390                 mal_type = 2;
391   }
392   else
393   {
394     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Type unknown using type 0 - no malicious behaviour\n");
395                 mal_type = 0;
396   }
397
398   ok = 1;
399   (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
400                                   "test_rps.conf",
401                                   NUM_PEERS,
402                                   0, NULL, NULL,
403                                   &run, NULL);
404   return ok;
405 }
406
407 /* end of test_rps_multipeer.c */